CUDA + Blas

Возникла доволно банальная идея, однако про ее реализацию пока ничего не нашел. Может кто уже встречался с этим.
Идея в следующем - берем обычную библиотеку BLAS, которая используется многими разными научными программами для расчетов. Делаем оболочку и вместо функций из BLAS вызываем функции из CuBlas. В итоге получаем выигрышь в производительности (не будем пока обращать внимание на задачи с малой размерностью) без перекомпилирования самих программ(если Blas динамически подгружалась), исходников к которым может уже и нет.
Или я что-то не понимаю?

Forums: 

А кто будет звать

А кто будет звать cublasSetMatrix, cublasGetMatrix и так далее?

Если вы спрячете эти вызовы в "обертку", то у вас весь пар уйдет в пересылки память-видеокарта и обратно.

Для cublas это же по любому

Для cublas это же по любому делать нужно, в обертке или прямо в коде программы. Но я не слышал, что cublas бессмысленно из-за этого использовать (в смысле что на blas это делать быстрее). Однако это действительно может быть выгодно только для очень больших размерностей задач.

Если вы сразу реализуете на

Если вы сразу реализуете на cublas, то вам необязательно (все) промежуточные результаты копировать на хост.

Написал маленький тест на

Написал маленький тест на SGEMM. 10 расчетов за раз. Вся работа с кудой вынесена в отдельную стат.библиотеку. Получил следующие результаты:

  1. Size: 10
  2. Elapsed time CPU: 0.000003 sec
  3. Elapsed time GPU: 0.000249 sec
  4. Size: 35
  5. Elapsed time CPU: 0.000067 sec
  6. Elapsed time GPU: 0.000248 sec
  7. Size: 60
  8. Elapsed time CPU: 0.000305 sec
  9. Elapsed time GPU: 0.000272 sec
  10. Size: 85
  11. Elapsed time CPU: 0.000831 sec
  12. Elapsed time GPU: 0.000349 sec
  13. Size: 110
  14. Elapsed time CPU: 0.001744 sec
  15. Elapsed time GPU: 0.000432 sec

Так что результат есть. Для 985 элементов 1.41 против 0.02.
Единственное что беспокоит, у blas'ой функции есть возможность выбора способа хранения матриц. У куды такого не нашел. Ну чтож, для таких случаев можно будет и cpu задействовать. Ну или перевести туда-сюда.

Ну вы же заменили *один*

Ну вы же заменили *один* вызов, да еще и сложности N**3.
Понятно, что тут нетрудно дождаться выгоды, взять задачу побольше.

А если в приложении используются операции линейной сложности - то будет проигрыш, спорим?

Да, для линейных задач

Да, для линейных задач использовать gpu нет смысла. Для всех этих операций вызовы просто в blas библиотеку можно передавать.

Я не говорю, что gpu нам

Я не говорю, что gpu нам сделает счастье. Я это все к тому, что можно просто улучшить Blas там, где это возможно. На Blas3 например, ну и возможно на Blas2. Пусть не везде, но скорость улучшим. В любом случае хуже делать смысла нет, а вот сделать лучше - возможности есть.

В cublas есть "thunking

В cublas есть "thunking interface" - там cublasSetMatrix/... уже обвёрнуты. Но насколько я помню интерфейс всё равно не BLAS.
Где-то пол года назад я делал небольшую обёртку для этого thunking под blas, чтобы запустить linpack на cuda без модификации, и насколько я помню некоторые тесты даже запустились, но результаты были маленькие (так как всё время данные туда-сюда тасовлись) - что-то около 20-30 GFlops на Tesla C1060. Потом не было времени дальше пилить(видимо для лучших результатов надо сам linpack пилить) и я это дело забросил.
В сети есть разные попытки на эту тему(gpgpu linpack), например - http://www.ece.neu.edu/groups/nucar/GPGPU/GPGPU-2/Fatica.pdf
Кстати, интересно, может кто знает что вот тут http://www.top500.org/system/10484 запускали?

Как вариант можно попытаться

Как вариант можно попытаться минимизировать пересылку данных:
1. после завершения операции не очищать память gpu, строить карту ram_pointer->gpu_pointer(ещё что-то типа хэша можно) , соответственно когда вызывается операция аргументом которой является указатель который уже есть карте, то сделать небольшую проверку - не изменились ли данные (хэшем(выборкой нескольких значений и т.п.) ) и соответственно использовать то, что уже есть в gpu.
2. соответственно когда память gpu заканчивается - удалять старые данные
3. чтобы не возвращать результат на каждой операции, можно использовать разного рода трюки - например модифицировать атрибуты страниц памяти - при чтении/записи срабатывает исключение - на котором сидит наш обработчик - который нужные данные из gpu и вытащит. Кстати такие трюки можно использовать и для проверки данных на изменения (т.е. в первом пункте).
4. Если серебряная пуля не нужна, а необходимо прикрутить этот blas к конкретному приложению - открывается поле для ряда улучшений. Например, можно один раз чётко выяснить на каких этапах меняются данные, на каких считываются результаты(именно считываются, а не передаются в следующую blas функцию)
В общем вариантов масса.

По поводу модификации

По поводу модификации атрибутов страниц памяти - в ollydbg это называется memory breakpoint (это не DR регистры процессора. DR там называется hardware breakpoint).
Пример реализации можно посмотреть в pydbg: bp_set_mem. (Вообще pydbg крайне полезная штука для reverse engineering)

При использовании thunking

При использовании thunking интерфейса не было проблем с линковкой? Или там может что-то доп. подключать надо? У меня не может найти CUBLAS_SGEMM, хотя fortran_thunking.с собран и подключается как стат. библиотека. __cplusplus определен.

Каких-то серьёзных проблем не

Каких-то серьёзных проблем не было, а так не помню.
Там этот thunking у них изменялся, последний раз экспериментировал с версией которая была в конце апреля.
По поводу CUBLAS_SGEMM - откройте fortran.c (может в новых версиях что-то изменилось, я смотрю именно апрельскую), там есть строки:

  1. #include "fortran_common.h"
  2. #include "fortran.h"

дальше смотрим fortran_common.h:

  1. #define CUBLAS_SGEMV            cublas_sgemv_

Также можно посмотреть символы (nm под linux, dumpbin под windows).