Я должен быть откровенным здесь, это будет
- критика тяги
- Хвастовство ArrayFire (из которых я являюсь главным разработчиком)
Критика тяги
Они отлично справляются с оптимизацией параллельных алгоритмов для векторных входов. Они используют параллелизм уровня данных (среди прочего) для анализа алгоритмов, которые действительно хорошо работают для big, vector Входы.Но они не могут улучшить его и пройти весь путь до совершенства true уровень параллелизма данных. то есть a большое количество мелких проблем.
Этот второй случай полезен во многих приложениях реального мира, и ArrayFire предоставляет решения в этом отношении (посмотрите gfor, параллельный цикл).
Заглушка для ArrayFire
Что должно было простой призыв к сокращению и сканирования, а не становится 4 алгоритмов (один из которых является дорогостоящим рода) и 3 копии памяти в тяге.
Вот как работает код в ArrayFire:
array cell_indices(num_particles, 1, dev_particle_cell_indices, afDevicePointer);
array particle_counts = zeros(num_cells);
gfor(array i, num_cells) // Parallel for loop
particle_counts(i) = sum(cell_indices == i);
array particle_offsets = accum(particle_counts); // Inclusive sum
-
Настройка
- Я использую talonmies код для ориентира против arrayfire.
- Я использую аналогичную графическую карту (gts 360m) на Linux 64 (cuda 4.1/gcc 4.7).
- Вы можете найти полный эталонный код за here.
Benchmark 1
С num_particles = 2000 и num_cells = 1500 (например, исходной задачи)
$ ./a.out
Thrust time taken: 0.002384
ArrayFire time taken: 0.000131
ArrayFire является раз быстрее
Benchmark 2
С num_particles = 10000 и num_cells = 2000 (например, теста talonmies')
$ ./a.out
Thrust time taken: 0.002920
ArrayFire time taken: 0.000132
ArrayFire является раз быстрее
Benchmark 3
С num_particles = 50000 и num_cells = 5000 (только больший тестовый пример)
$ ./a.out
Thrust time taken: 0.003596
ArrayFire time taken: 0.000157
ArrayFire является раз быстрее
Примечания
- Thrust требует, чтобы переписать код
- Thrust обеспечивает скорость до по ~ 320X над первоначальным кодом
- ArrayFire требует мало переписывания трески е (изменение для к gfor)
- ArrayFire в 18-23 раз быстрее (эффективно ~ 7300x по сравнению с исходным кодом)
- ArrayFire масштабируется лучше (во время выполнения увеличивается на 50% за тягой, 15% для ArrayFire)
Заключение
Упорный действительно обеспечивает приличную скорость, если вы можете переписать вашу проблему. Но это не всегда возможно и нетривиально для более сложных задач. Цифры указывают на то, что существуют возможности для более высокой производительности (из-за высокой степени параллелизма данных), которые просто не достигают тяги.
ArrayFire использует параллельные ресурсы гораздо более эффективно, а время указывает, что gpu еще не насыщен.
Возможно, вы захотите написать свой собственный код cuda или использовать ArrayFire. Я просто хотел указать, что иногда использование тяги не является вариантом, потому что оно практически бесполезно при большом количестве небольших проблем.
EDIT фиксированной эталонные 1 результатов (я использую неправильные номера)
Вы бежите, что цикл для каждого кадра? Если 'num_cells' составляет около 1500, вы запускаете около 1500 отдельных ядер и 1500 хостов для копий памяти устройства (каждый из которых почти не работает). Если это так, ваша проблема заключается не в производительности тяги, а в количестве латентности, которую вводит ваш код. – talonmies
@talonmies Ах, мне было интересно, была ли это пропускная способность CPU-GPU. Если я передаю указатель на память устройства, чтобы не засунуть, не единственная копия хоста/устройства, возвращаемая int? – kevintodisco
Да, передача результата является единственной копией. Эта петля выглядит так, будто она выполняет бининг или гистограммирование частиц. Там должно быть много * более эффективных способов сделать это с помощью тяги (возможно, только с одним вызовом). – talonmies