Тут к стати отдельный вопрос почему автор не ипользует ::cudaMallocHost для аллокации памяти на хосте. Это на порядок повысит скорость копирования данных на устройство.
Про pinned memory будет рассказано в следующих частях.
Есть замечательное свойство фильтра Гаусса — вместо расчета один раз окном 9x9 можно применить последовательно 4 раза фильтр Гаусса с окном 3x3 и получить тот же результат (если конечно не учитывать ошибки округления).
Тут Вы, по-моему, ошиблись. Википедия говорит, что применение нескольких, последовательных фильтров с радиусами R1,...,RN эквивалентно применению единого фильтра с радиусом R=sqrt(R12+...+RN2). Так что применение 4-х фильтров с радиусом 3 эквивалентно применению фильтра с радиусом R=sqrt(4*9)=6, а не 9 — нужно применить фильтр с радиусом 3 девять раз, чтобы это было эквивалентно применению фильтра с радиусом 9 один раз.
А в общем — вы сравниваете оптимизированный код на CPU с неоптимизированным кодом на GPU — несколько некорректно, не находите?) Все таки приведенный код на GPU еще тоже есть куда оптимизировать — переместить веса фильтра в константную память, пиксели входного изображения в shared memory, обрабатывать несколько пикселей каждым потоком и т.д. Но я согласен, что и этот пример возможно будет рассчитываться быстрее на CPU, хотя все равно думаю, что для больших изображений GPU вариант должен выигрывать. Для интереса — не могли бы Вы подправить свой вариант, чтобы он выполнял маленький фильтр правильное количество раз, и прогнать его на этом изображении — а я оптимизирую код на GPU, и проверю его время?
Спасибо за замечания — добавил аппаратную конфигурацию и размер тестовых данных в эту статью, учту для следующих. А какую именно программную конфигурацию следует указать — компилятор, версии OpenMP и CUDA?
Немаленького: 10,109 × 4,542. Для изображений стандартных размеров смысла использовать CUDA вообще бы не было — подозреваю, что даже вычислительная часть выполнялась бы медленнее, чем на CPU, не учитывая операций с памятью. Думаю, в следующих статьях (кроме 2 — она уже написана) буду проводить тестирование на входах разной размерности.
Ясно, спасибо. Спросил потому-что практические задания для udacity-курса выполнялись на GPU с архитектурой Fermi — то-есть СС=2.x, но инструкторы все-таки советовали перемещать данные в shared memory, да я и сам замечал прирост в производительности. Я ведь правильно понимаю, дело в том, что начиная с СС 2.0 CUDA и сама перемещает часто используемые данные в L1 кэш — именно поэтому использование shared memory может и не дать прироста?
Вы, судя по всему, «в теме»:) Хотел спросить: то-есть если из этого примера убрать перемещение весов фильтра в общую память блока — то на GPU с Compute Capability >= 2.0 производительность останеться прежней?
Доольно простой пример, где нужен атомик над float — построение гистограммы для любых float значений. Скажем, имея большое количество записей о спортсменах, вы хотите найти средний вес в зависимости от роста — тогда вам сначала нужно построить гистограмму 'рост'->'суммарный вес всех спортсменов с таким ростом', и тут уже без атомик не обойтись, а вес вполне может быть float.
Вы правы. Дело в том, что я не упомянул о контекстах CUDA: это некоторый аналог процесса на CPU — каждый контекст имеет свое собственное адресное пространство, а каждый CPU поток работает только с одним CUDA контекстом в конкретный момент времени. Собственно, первая инициализация происходит с задержкой изза ленивого создания контекста.
Я ни о чем таком пока не слышал и в гугле не нашел, хотя тут и говорят, что конвертация CUDA кода в OpenCL код довольно прямолинейна. Все что нашел — cu2cl — автоматический транслятор CUDA в OpenCL, естественно, с некоторыми ограничениями.
Как понимаете, все дело в определенных различиях между технологиями (которые, кстати, хорошо описаны по первой ссылке).
Я по-быстрому погуглил — так как одним из шагов mp3 енкодинга является FFT или какой-то его аналог, а разные бенчмарки говорят, что для большого количества данных GPU реализация FFT дает определенный прирост в скорости — можно потенциально ускорить этот процесс. Однако, думаю что это нетривиальная задача. — Вот тут например пишут, что в 2008 nVidia проводила конкурс на реализацию mp3 енкодера на CUDA.
В примере к второй статье будет размытие изображения по Гауссу. К четвертой — поразрядная сортировка. К шестой — смешивание изображений по Пуассону. Насчет mp3 енкодера — я посмотрю, может действительно будет примером к одной из статей, если получится разобраться:)
А где было сказано про фэйковые улучшения и подкрутку показателей? Я довольно четко написал, что для данной задачи реальный выигрыш мы не получили — однако сами вычисления выполнились быстрее. В примере для следующей статьи уже будет получено реальное ускорение, с учетом всех операций. Ну а про компанию это вообще не понятно к чему.
Повторю еще раз: цель данной конкретной статьи не состояла в написании супер-пупер быстрого кода на GPU — но в объяснении основ CUDA и написании простого примера для иллюстрации этих основ. Вы даже могли бы обратить внимание на плашку «tutorial».
Ну целью первой статьи было скорее показать, как написать простую программу на CUDA, чем доказать, что вычисления на GPU можно выполнить быстрее чем на CPU. В следующих статьях уже будут примеры, где CUDA вариант действительно быстрее чем CPU вариант — просто они будут несколько сложнее.
Про pinned memory будет рассказано в следующих частях.
Тут Вы, по-моему, ошиблись. Википедия говорит, что применение нескольких, последовательных фильтров с радиусами R1,...,RN эквивалентно применению единого фильтра с радиусом R=sqrt(R12+...+RN2). Так что применение 4-х фильтров с радиусом 3 эквивалентно применению фильтра с радиусом R=sqrt(4*9)=6, а не 9 — нужно применить фильтр с радиусом 3 девять раз, чтобы это было эквивалентно применению фильтра с радиусом 9 один раз.
А в общем — вы сравниваете оптимизированный код на CPU с неоптимизированным кодом на GPU — несколько некорректно, не находите?) Все таки приведенный код на GPU еще тоже есть куда оптимизировать — переместить веса фильтра в константную память, пиксели входного изображения в shared memory, обрабатывать несколько пикселей каждым потоком и т.д. Но я согласен, что и этот пример возможно будет рассчитываться быстрее на CPU, хотя все равно думаю, что для больших изображений GPU вариант должен выигрывать. Для интереса — не могли бы Вы подправить свой вариант, чтобы он выполнял маленький фильтр правильное количество раз, и прогнать его на этом изображении — а я оптимизирую код на GPU, и проверю его время?
Но это действительно учебный пример, на котором довольно просто показать основы CUDA.
Как понимаете, все дело в определенных различиях между технологиями (которые, кстати, хорошо описаны по первой ссылке).
Повторю еще раз: цель данной конкретной статьи не состояла в написании супер-пупер быстрого кода на GPU — но в объяснении основ CUDA и написании простого примера для иллюстрации этих основ. Вы даже могли бы обратить внимание на плашку «tutorial».