Ускоряем разработку программ под CUDA, избавляясь от рутины

Всем привет!
Хотел бы поделится библиотекой, которую изначально писал для себя, но она оказалась очень удачная (как по мне), и я решил расшарить ее для остальных разработчиков.

Вот линк:
http://code.google.com/p/devar/

Суть библиотеки в том, что в ней инкапсулировано множество рутинных процедур с массивами в памяти GPU (а именно инициализация, копирование хост-устройство, устройство-хост, устройство-устройство, удаление, и т.д.). При этом при каких либо неудачах (когда процедура не завершается с cudaSuccess) автоматически выбрасывается исключение.
Все это делает программу более читабельной, короткой и надежной.
Как ей пользоваться (а это очень несложно) можно посмотреть на сайте.

Вот пример:

  1. #include "DevAr.h"
  2. ... //other headers
  3.  
  4. void kernel (float* data){
  5. ...   //do something
  6. }
  7.  
  8. int main(){
  9.     DevAr<float> devF(256);   //array in device memory
  10.     float* f = new float[256];   //array in host memory
  11.     ... //initialization of f
  12.     devF.copyFromHost(f);   //copy data from host to device memory
  13.     kernel<<<bl, thr>>>(devF.get());   //execute the kernel
  14.     cout << devF[15] << endl;   //output 15-th element of the device array
  15.     devF.copyToHost(f);   //copy from device to host
  16.     devF.clean();
  17.     delete[] f;
  18. }

Спасибо за внимание.
Надеюсь услышать ваши отзывы!

Forums: 

Я не очень большой специалист

Я не очень большой специалист в thrust, но насколько я знаю, с помощью этой библиотеки можно реализовать стандартные алгоритмы вектора, типа сортировки и пр., на видеокарте, что дает ускорение производительности.
DevAr - это обертка стандартных действий с массивами в памяти устройства. Что нам чаще всего приходится делать с массивами в памяти устройства и хоста? - Создавать массив в устройстве, копировать данные из устройства или в устройство и т.д. Это рутина. Библиотека, которую я сделал позволяет эту рутину сильно уменьшить. Рассмотрим пример с выделением памяти на устройстве. Обычно это делается так:

  1. float* devA;
  2. SAFE_CALL(cudaMalloc((void**)&devA, sizeof(float) * N));
  3. ......
  4. SAFE_CALL(cudaFree((void**)&devA));

А так это делается DevAr:

  1. DevAr<float> devA(N);

И все!

А так это делается в Thrust :

А так это делается в Thrust :)
thrust::device_vector vec_a(N);

А вот так например копирование с девайса на хост:
thrust::host_vector vec_b = vec_a;

Ну и допустим сортировка в памяти устройства:
thrust::sort(vec_a.begin(), vec_a.end());

А можно ли vec_a передать в

А можно ли vec_a передать в ядро? Даже если можно, что скорее всего так (правда интересно знать как :)), ибо thrust довольно мощная библиотека, то во многих случаях всю эту мощь использовать нет необходимости. А вот в DevAr реализованы функции, которые 100% пригодятся (если не в одном, так в другом проекте). К примеру мне очень нравятся доступ к элементу через [], особенно во время отладки, когда нужно вывести какие-то промежуточные результаты:

  1. DevAr<float> devA(200);
  2. ...
  3. cout << devA[15] << endl;

Ненужно вводить какой-то промежуточный массив в памяти ЦПУ и запускать команду копирования из памяти ГПУ. И еще одна приятная, на мой взгляд, особенность - выбрасывание исключений когда операция закончилась с ошибкой (т.е. не было возвращено cudaSuccess). Вот такой обработкой исключений можно быстро выводить описание ошибки:

  1.         try{
  2.                 DevAr<float> *devF  = new DevAr<float>(N);
  3. .......
  4.         } catch (CudaException& c) {
  5.                 std::cerr << c.getMessage();
  6.         }

и сразу же получаем в консоли описание ошибки.
В общем, заменить thrust я и не планировал, а очень простая в использовании обертка, которая может быть и дублирует его функционал, но тем не менее избавляет от надоевшего стандартного объемного кода, думаю весьма полезна. По крайне мере я больше не пишу программ без DevAr. Поэтому и решил поделится этим с остальными :)

Можно в Thrust и в кернел

Можно в Thrust и в кернел передавать, и через [] обращаться к векторам и эксепшены он кидает.
Ну не использовать Thrust из-за её мощи это конечно не логично :)
Кому что нравится.

А вот на счет кернела - это

А вот на счет кернела - это интересно! Как должно выглядить объявление ядра и как осуществляется передача?