Новости
З виходом 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]); }}