Пример параллельного сокращения

Я нашел это параллельное сокращение код из Стэнфорда, использующий разделяемую память.

Код является примером 1‹‹18 элементов, что равно 262144 и дает правильные результаты.

Почему для определенного количества элементов я получаю правильные результаты, а для другого количества элементов, например 200000 или 25000, результаты отличаются от ожидаемых? Мне кажется, что он всегда назначает необходимые блоки потоков


person user1280671    schedule 02.02.2013    source источник


Ответы (2)


// launch a single block to compute the sum of the partial sums
block_sum<<<1,num_blocks,num_blocks * sizeof(float)>>>

этот код вызывает ошибку.

предположим, что numblocks равно 13,

Тогда в блоке ядра Dim.x/2 будет 6, а

if(threadIdx.x < offset)
{
    // add a partial sum upstream to our own
    sdata[threadIdx.x] += sdata[threadIdx.x + offset]; 
}

добавит только первые 12 элементов, вызывающих ошибку.

когда количество элементов равно 200000 или 250000, num_blocks будут нечетными числами и вызывают ошибку, для четных num_blocks все будет работать нормально

person rps    schedule 02.02.2013
comment
Спасибо за ваш ответ. Я пытался протестировать его только с количеством элементов, которые производят четное количество блоков, но все же я не всегда получал правильный результат по сравнению с результатом хоста. Мое наблюдение заключается в том, что в этом примере требуется не только четное количество блоков, но и block_size%num_blocks=0. Есть комментарии по этому поводу? - person user1280671; 03.02.2013
comment
я сомневаюсь при втором запуске ядра, проверяли ли вы вывод первого запуска ядра? - person rps; 03.02.2013
comment
Как вы обслуживали оставшуюся часть? - person mibrahimy; 27.11.2019

Это ядро ​​чувствительно к параметрам блокировки (сетке и размеру блока потоков) ядра. Вы вызываете его с достаточным количеством потоков, чтобы покрыть размер ввода?

Более надежно формулировать такие ядра с помощью циклов for вместо:

unsigned int i = blockIdx.x * blockDim.x + threadIdx.x;

что-то вроде:

for ( size_t i = blockIdx.x*blockDim.x + threadIdx.x;
      i < N;
      i += blockDim.x*gridDim.x ) {
    sum += in[i];
}

Исходный код в Руководстве по CUDA содержит множество примеров «независимого от блокировки» кода. Код сокращения здесь:

https://github.com/ArchaeaSoftware/cudahandbook/tree/master/reduction

person ArchaeaSoftware    schedule 05.02.2013
comment
Спасибо за участие. Программа, на которую я ссылаюсь в своем исходном посте, не имеет проблем с вызовом необходимых потоков и блоков потоков. Размер блока составляет 512, что является максимальным для моей вычислительной способности GPU 1.3. Похоже, есть проблема, если количество блоков не является степенью двойки. - person user1280671; 06.02.2013
comment
Кроме того, возникает проблема, если мой размер ввода приводит к вычислению количества блоков, превышающего 512, которое используется в качестве размера блока для второго вызова ядра. В архиве сокращения cuda, который вы указали мне, вы имеете в виду, что я мог бы использовать для размера ввода 307200, который использует 600 блоков и 512 потоков на блок? - person user1280671; 06.02.2013