Почему замена if-else на битовую операцию оказывается медленнее в CUDA? - PullRequest
0 голосов
/ 25 августа 2011

Я заменяю

if((nMark >> tempOffset) & 1){nDuplicate++;}
else{nMark = (nMark | (1 << tempOffset));}

на

nDuplicate += ((nMark >> tempOffset) & 1);
nMark = (nMark | (1 << tempOffset));

эта замена оказывается на 5 мс медленнее на видеокарте GT 520.

Не могли бы вы сказать, почему?или у вас есть идея, чтобы помочь мне улучшить его?

Ответы [ 4 ]

0 голосов
/ 26 августа 2011

Встроенный набор команд для графического процессора очень эффективно справляется с небольшими условиями с помощью предикации. Кроме того, инструкция ISET преобразует регистр кода состояния в целое число со значением 0 или 1, которое естественно соответствует вашему условному приращению.

Я предполагаю, что ключевое различие между первой и второй формулировками заключается в том, что вы фактически скрыли тот факт, что это if / else.

Чтобы точно сказать, вы можете использовать cuobjdump для просмотра микрокода, сгенерированного для двух случаев: укажите --keep для nvcc и используйте cuobjdump в файле .cubin для просмотра разобранного микрокода.

0 голосов
/ 25 августа 2011

Показывает ли ваша программа существенное расхождение отраслей?Если вы выполняете, например, 100 деформаций и только 5 из них ведут себя по-разному, и они работают в 5 SM, вы увидите только 21 временной цикл (ожидая 20) ... увеличение на 5%, которое можно легко победить, выполнив в 2 раза больше работы.в каждом потоке, чтобы избежать редких расхождений.

За исключением этого, 520 является довольно современной видеокартой и может включать в себя современные методы планирования SIMT, например, динамическое формирование деформации и уплотнение блоков потоков, чтобы скрыть остановки SIMT.Может быть, посмотрите на архитектурные особенности (спецификации) или напишите простой тест, чтобы сгенерировать n-стороннее расхождение ветвей и измерить замедление?

Кроме этого, проверьте, где находятся ваши переменные.Влияет ли их разделение на производительность / результаты?Поскольку вы всегда получаете доступ ко всем переменным во второй и первой, вы можете избежать доступа к nDimension, поэтому медленный (несообщенный глобальный?) Доступ к памяти может объяснить это.

Просто некоторые вещи, о которых стоит подумать.

0 голосов
/ 26 августа 2011

Для низкоуровневой оптимизации часто полезно взглянуть на низкоуровневую сборку (SASS) ядра напрямую. Вы можете сделать это с помощью инструмента cuobjdump, распространяемого как часть набора инструментов CUDA. Основное использование состоит в том, чтобы скомпилировать с -keep в nvcc, затем выполнить:

cuobjdump -sass mykernel.cubin

Тогда вы сможете увидеть точную последовательность инструкций и сравнить их. Я не уверен, почему версия 1 будет быстрее, чем версия 2 кода, но списки SASS могут дать вам подсказку.

0 голосов
/ 25 августа 2011

Выстрел в темноте, но вы всегда увеличиваете / переопределяете переменную nDuplicate сейчас в последней реализации, где вы не увеличивали / переопределяли ее, если тест в операторе if ранее был ложным. Предполагаю, что это связано с накладными расходами, но вы не описываете свой тестовый набор данных, поэтому я не знаю, так ли это уже было.

...