29 сентября 2011 г.

Создание простого приложения CUDA в Visual Studio 2010


VS2010WithCUDA

С выходом 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, как показано на рисунке ниже.

NewProject

NewProjectWizard

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

BuildCustomization

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

AddFiles

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

CudaFileType

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

PlatformToolset

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

LinkerAdditionalLibraryDirectories

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

LinkerAdditionalDependencies

Для проверки корректности настроек в файл 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]);
   }
}

Связанные материалы



9 коммент.:

Мурадов Мурад комментирует...

"Выделение памяти CPU" - может просто в основной памяти?

Мурадов Мурад комментирует...

К (int *) data обязательно прибавлять 1.0f (float)? Это такая особенность работы с CUDA или с видеокартой?

Александр Межов комментирует...

@Мурадов Мурад

Я хотел показать, что память, которая выделяется для CPU и для GPU - это принципиально разные вещи, поэтому так написал. CPU (host) может работать только с оперативной памятью, GPU может работать только с видео-памятью; копирование из оперативной памяти в видео и обратно осуществляется через функции CUDA. Сейчас немного изменил формулировку, чтобы было более понятно.

С "1.0f" я немного соврал. Там правда работа идет с простым int, поэтому достаточно написать просто 1. Что касается float - суть в том, что CUDA с float работает гораздо быстрей, чем с double, поэтому рекомендуют явно указывать типы констант (правила хорошего тона). В данном примере это делать не нужно.

Dmitry Selunin комментирует...

как настроить CUDA в Visual Studio 2012?? (2013 как я понял они пока не поддерживают....?)
там в свойствах уже нет Каталогов VC++, и где собственно прописать все эти $(CUDA_PATH...?

Alexander Mezhov комментирует...

Дмитрий, можете сказать, что именно не получилось? Я просмотрел все свойства, вроде, всё на месте.

Dmitry Selunin комментирует...

так.. вот что происходит... если я загружаю какой-нибудь bandwidthTest_vs2012 и запускаю то все ок.
если я элементарно пытаюсь запустить даже просто 1 строку - int main(){return 0;} то ошибка error LNK2019: ссылка на неразрешенный внешний символ ___cudaUnregisterFatBinary@4 в функции "void __cdecl __cudaUnregisterBinaryUtil(void)" (?__cudaUnregisterBinaryUtil@@YAXXZ) C:\Users\\documents\visual studio 2012\Projects\test_cu\test_cu\cuda.cu.obj test_cu

где прописать путь нашел - вкладка CUDA C/C++ появляется если залезть в свойства именно самого файла cu а не всего проекта и не общих настроек... и там есть Additional Include Directories. причем в bandwidthTest_vs2012 указана ./;../../common/inc - если я копирую ее в свой проект то все равно ошибки, ставлю $(CUDA_INC_PATH); то же самое, $(CUDA_PATH_V5_5)\lib\$(Platform) - то же самое.... (у меня версия 5.5 + поставил Nsight но толком не понимаю что это за зверь такой и где его найти....в смысле в самой VS или где-то отдельно..)

Dmitry Selunin комментирует...

http://blog.norture.com/2012/10/gpu-parallel-programming-in-vs2012-with-nvidia-cuda/ попробовал по этой статье - не помогло((
может я где-то не там это прописал?
что соответствует Configuration Properties\Linker\General в русской версии? уже замучился... сначала ставил VS13, потом 12, теперь похоже еще и англ версию придется....

Dmitry Selunin комментирует...

так, проблеме решена если явно написать в коде #pragma comment(lib,"cudart.lib").. но все-таки, как сделать "нормально"? чтобы пути сами прописывались?

Alexander Mezhov комментирует...

К сожалению, сейчас уже точно не скажу, потому что год не работал с CUDA. Наверное, лучше будет задать вопрос на официальном форуме. Потом поделитесь результатами. ;)

Отправить комментарий