Конфликт Банка общей памяти GPU

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

shared_a[threadIdx.x]=global_a[threadIdx.x]

приводит ли это простое действие к банковскому конфликту?

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

tid = threadIdx.x;
for(int i=0;tid+i<N;i+=blockDim.x)
     shared_a[tid+i]=global_a[tid+i];

приводит ли приведенный выше код к банковскому конфликту?

2 ответов


лучший способ проверить это-профилировать ваш код с помощью "Compute Visual Profiler"; это поставляется с набором инструментов CUDA. Также есть отличный раздел в GPU Gems 3 об этом - "39.2.3 избегая конфликтов".

"когда несколько потоков в одном варп доступ к тем же банком, происходит в банке конфликта, если все потоки варпа к тому же адресу в том же 32-битное слово " - Первое, что есть 16 банков памяти каждый 4bytes широкий. Так по существу, если у вас есть любая нить в половину деформации чтение памяти из тех же 4bytes в банке общей памяти, у вас будут банковские конфликты и сериализация и т. д.

OK Итак, ваш первый пример:

сначала предположим, что ваши массивы говорят, например, типа int (32-битное слово). Ваш код сохраняет эти ints в общую память, через любую половину деформации KTH поток сохраняет в Kth банк памяти. Так, например, поток 0 первой половины warp сохранит до shared_a[0] который находится в первом банке памяти, поток 1 сохранит в shared_a[1], каждая половина warp имеет 16 потоков, которые сопоставляются с 16 банками 4byte. В следующей половине warp первый поток теперь сохранит свое значение в shared_a[16], которое находится в первый банк памяти снова. Поэтому, если вы используете слово 4byte, такое int, float и т. д., Ваш первый пример не приведет к банковскому конфликту. Если вы используете 1 байтовое слово, такое как char, в первой половине warp threads 0, 1, 2 и 3 сохранят свои значения в первом банке общей памяти, что вызовет банковский конфликт.

второй пример:

опять же все это будет зависеть от размера слова, которое вы используете, но для примера я буду использовать слово 4byte. Итак, глядя на первую половину warp:

количество потоков = 32

N = 64

поток 0: будет записывать в 0, 31, 63 Резьбы 1: напишу 1, 32

все потоки через половину деформации выполняются одновременно, поэтому записи в общую память не должны вызывать конфликтов банка. Мне придется проверить это.

надеюсь, что это поможет, извините за огромный ответ!


в обоих случаях потоки обращаются к общей памяти с последовательным адресом. Это зависит от размера элемента общей памяти, но последовательный доступ к общей памяти по основанию потоков не приводит к конфликту банка для "малых" размеров элементов.

профилирования код С Nvidia Visual Profiler показывает, что для размера элемента меньше 32 и кратно 4 (4, 8, 12,... , 28), последовательный доступ к общей памяти не приводит к банковский конфликта. Однако размер элемента 32 приводит к банковскому конфликту.


ответ Ljdawson содержит некоторую устаревшую информацию:

... Если вы используете 1 байтовое слово, такое как char, в первой половине warp-потоков 0, 1, 2 и 3 все сохранят свои значения в первом банке общей памяти, что вызовет банковский конфликт.

Это может быть верно для старых графических процессоров, но для недавних графических процессоров с cc >= 2.x, они не причиняют конфликты банка, эффектно должные к широковещательный механизм (ссылке). Следующая цитата от руководство по программированию CUDA C (v8.0.61) G3.3. Общая Память.

запрос общей памяти для warp не создает банковский конфликт между двумя потоками, которые обращаются к любому адресу в пределах одного 32-битного слова (даже если два адреса попадают в один банк): в этом случае для доступа к чтению слово передается запрашивающим потокам (несколько слов могут быть переданы в одном банке). транзакция) и для доступа к записи каждый адрес записывается только одним из потоков (какой поток выполняет запись, не определено).

это означает, в частности, что нет никаких банковских конфликтов, если массив char доступен следующим образом, например:

   extern __shared__ char shared[];
   char data = shared[BaseIndex + tid];