2012-02-18 3 views
0

Я реализовал алгоритм соответствия строк на графическом процессоре. Время поиска параллельной версии значительно уменьшилось по сравнению с последовательной версией алгоритма, но с использованием разного количества блоков и потоков я получаю разные результаты. Как определить количество блоков и threds, чтобы получить наилучшие результаты?CUDA - Блоки и потоки

+0

Что вы подразумеваете под «использованием разного количества блоков и потоков», я получаю разные результаты »? Вы имеете в виду разную производительность, или вы имеете в виду, что код не работает? – talonmies

ответ

1

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

  1. Не используйте глобальную память & проверить, как вы можете Макс из использования разделяемой памяти. Как правило, хорошо разбираются в том, как потоки получают доступ к памяти и как извлекаются данные и т. Д.

  2. Поймите, как работают ваши перекосы. Иногда потоки в warp могут ждать завершения других потоков, если у вас есть 1 к 1 сопоставление между потоком и данными. Поэтому вместо этого сопоставления 1 к 1 вы можете сопоставить потоки с несколькими данными, чтобы они были заняты.

  3. Поскольку блоки состоят из нитей, которые группа в 32 нитей основы, то лучше всего, если число потоков в блоке является кратным 32, так что вы не получаете перекосов, состоящий из 3 нитей и т.д.

  4. Избегайте расхождения путей в деформациях.

Надеюсь, это поможет.

1

@ Критические точки очень важны, но больше зависят от самого алгоритма.

  1. Посмотрите руководство Cuda относительно выравнивания резьбы в отношении поиска в памяти. Общие массивы памяти также должны быть размерами, равными 16.

  2. Использовать коагулированную глобальную память. Но по алгоритму это часто бывает, и использование разделяемой памяти помогает.

  3. Не используйте атомные операции в глобальной памяти или вообще, если это возможно. Они очень медленные. Некоторые алгоритмы, использующие атомные операции, могут быть переписаны с использованием разных методов.

Без указания кода никто не может сообщить вам, что является лучшим или почему изменения в производительности.

Число потоков на блок вашего ядра является самым важным значением.

Важные значения для расчета этого значения являются:

  • Максимальное количество резидентов потоков на многопроцессорных
  • Максимальное количество блоков резидентов в многопроцессорной
  • Максимальное количество потоков в блоке
  • Число 32-разрядных регистры на мультипроцессор

Ваши алгоритмы должны быть масштабируемыми на всех 100% -ном заполнении GPU. Для этого я создал себе вспомогательный класс, который автоматически определяет лучшие номера потоков для используемого GPU и передает его в ядро ​​как DEFINE.

/** 
* Number of Threads in a Block 
* 
* Maximum number of resident blocks per multiprocessor : 8 
* 
* /////////////////// 
* Compute capability: 
* /////////////////// 
* 
* Cuda [1.0 - 1.1] = 
* Maximum number of resident threads per multiprocessor 768 
* Optimal Usage: 768/8 = 96 
* Cuda [1.2 - 1.3] = 
* Maximum number of resident threads per multiprocessor 1024 
* Optimal Usage: 1024/8 = 128 
* Cuda [2.x] = 
* Maximum number of resident threads per multiprocessor 1536 
* Optimal Usage: 1536/8 = 192 
*/ 
public static int BLOCK_SIZE_DEF = 96; 

Пример Cuda 1.1, чтобы достигнуть 786 резидентные нитей на СМ

  • 8 блоков * 96 нитей на Block = 786 нитей
  • 3-х блоков * 256 потоков на один блок = 786 нитей
  • 1 Блоки * 512 нитей на блок = 512 нитей < - 33% GPU не будет

Это также упоминается в книге:

Программирование массивно параллельных процессоров: практический подход (Применение GPU Computing Series)

Хорошие советы программирования:

  1. Анализ кода ядра и запись максимального количества потоков, которые он может обрабатывать, или количества «единиц», которые он может обрабатывать.
  2. Также выведите свое использование в регистре и попытайтесь снизить его до соответствующей целевой версии CUDA. Потому что, если вы используете слишком много регистров в своем ядре, будут выполняться меньше блоков, что приведет к меньшему заполнению и производительности.
    Пример: Используя Cuda 1.1 и используя оптимальное количество 768 резидентных потоков на SM, у вас есть 8192 регистра. Это приводит к 8192/768 = 10 максимальным регистрам на поток/ядро. Если вы используете 11, GPU будет использовать 1 блок меньше, что приведет к снижению производительности.

Пример: матричный независимый вектор строки, нормализующий мое ядро.

/* 
* //////////////////////// 
* // Compute capability // 
* //////////////////////// 
* 
* Used 12 registers, 540+16 bytes smem, 36 bytes cmem[1] 
* Used 10 registers, 540+16 bytes smem, 36 bytes cmem[1] <-- with -maxregcount 10 Limit for Cuda 1.1 
* I: Maximum number of Rows = max(x-dim)^max(dimGrid) 
* II: Maximum number of Columns = unlimited, since they are loaded in a tile loop 
* 
* Cuda [1.0 - 1.3]: 
* I: 65535^2 = 4.294.836.225 
* 
* Cuda [2.0]: 
* II: 65535^3 = 281.462.092.005.375 
*/ 
Смежные вопросы