Simple CUDA App in VS 2010

September 29, 2011

С выходом Visual Studio 2010 были связаны некоторые изменения в настройках проектов C++. В частности была удалена возможность создавать собственные правила компиляции. Эти изменения внесли определенные сложности в процесс создания проектов CUDA. Далее рассматривается минимально необходимый набор действий для создания простого приложения на базе технологии CUDA в Visual Studio 2010.

Предустановки

Для полноценной разработки приложений CUDA необходимо иметь видеокарту с поддержкой данной технологии. Список поддерживаемых устройств приведен на сайте производителя. Если видеокарта поддерживает CUDA, то желательно скачать и установить последнюю версию драйвера. Даже если поддержка отсутствует, создавать CUDA-приложения возможно, просто они будут запускаться в режиме эмуляции.

Далее необходимо установить CUDA Toolkit, GPU Computing SDK и Parallel Nsight для соответствующей версии операционной системы. На момент написания данной статьи использовался пакет CUDA Toolkit 4.0 и Parallel Nsight 2.0. Названные компоненты можно скачать на официальном сайте NVIDIA. Прежде чем продолжить, следует сказать несколько слов о данных компонентах.

NVIDIA® CUDA® Toolkit – набор инструментальных средств для разработки GPU-приложений на C/C++. Эти инструменты включают: CUDA-компилятор, библиотеку математических функций, а также набор утилит для отладки и профилирования приложений. Помимо этого в поставку входит подробное описание программно-аппаратной модели, руководство пользователя и документация по CUDA API.

NVIDIA® GPU Computing SDK содержит множество примеров использования CUDA, которые сопровождаются подробным описанием.

NVIDIA® Parallel Nsight – мощное расширение для Visual Studio, позволяющее осуществлять отладку, профилирование и анализ CUDA-приложений и не только.

CUDA Toolkit 4.0 не поддерживает компилятор V100, который идет в поставке с Visual Studio 2010, поэтому для сборки CUDA-проектов нужно иметь C++ компилятор версии VC90 с соответствующим Windows SDK. Для его установки достаточно установить express - версию Visual Studio 2008 (C++).

Создание проекта

Необходимо запустить Visual Studio 2010 и создать пустой Visual C++ Win32 Project, как показано на рисунке ниже.

Далее следует определить правила сборки проекта. Для этого нужно вызвать меню проекта Build Customization и поставить отметку напротив пункта CUDA 4.0. Эта настройка добавит поддержку CUDA-файлов, то есть файлов с расширением *.cu.

После этого в проект можно добавлять файлы с исходным кодом на CUDA. Для примера добавлен файл Program.cu.

Если CUDA-файл был добавлен не через соответствующий шаблон, а простым переименованием cpp-файла, в свойствах нужно явно установить тип CUDA C/C++.

Далее нужно вернуться к настройкам проекта и на вкладке General установить значение свойства Platform Toolset в V90.

В этом же диалоге указывается путь к lib-файлам CUDA. Для этого на вкладке Linker/General в настройке Additional Library Directories добавляется каталог $(CUDA_PATH_V4_0)\lib\$(Platform).

Наконец, на вкладке Linker/Input нужно добавить ссылку на библиотеку CUDA Runtime (cudart.lib). Для этого в настройку Additional Dependencies добавляется ссылка на соответствующую библиотеку.

Для проверки корректности настроек в файл Program.cu следует добавить пустую реализацию метода main и скомпилировать проект.

Написание программы

Ниже приведен код простой программы Program.cu, которая увеличивает значение элементов исходного массива на единицу посредством GPU.

#include <cuda.h>
#include <stdio.h>
 
__global__ void SomeKernel(int* data, int length)
{
   unsigned int threadId = blockIdx.x * blockDim.x
      + threadIdx.x;
 
   if (threadId < length)
   {
      data[threadId] = data[threadId] + 1;
   }
}
 
void main()
{
   int length = 256 * 256;
 
   // Выделение оперативной памяти (для CPU)
   int* hostData = (int*)malloc(length * sizeof(int));
 
   // Инициализация исходных данных
   for (int i = 0; i < length; ++i)
   {
      hostData[i] = i;
   }
 
   // Выделение памяти GPU
   int* deviceData;
   cudaMalloc((void**)&deviceData, length * sizeof(int));
 
   // Копирование исходных данных в GPU для обработки
   cudaMemcpy(deviceData, hostData, length * sizeof(int),
      cudaMemcpyHostToDevice);
 
   dim3 threads = dim3(256);
   dim3 blocks = dim3(length / 256);
 
   // Запуск ядра из (length / 256) блоков по 256 потоков,
   // предполагая, что length кратно 256
   SomeKernel<<<blocks, threads>>>(deviceData, length);
 
   // Считывание результата из GPU
   cudaMemcpy(hostData, deviceData, length * sizeof(int),
      cudaMemcpyDeviceToHost);
 
   // Отображение результата
   for (int i = 0; i < length; ++i)
   {
      printf("%d\t", hostData[i]);
   }
}

Ссылки