Понимая размеры сетки CUDA, наибольшие главные размерения и организацию потоков (простое объяснение) [закрытый]

Как потоки организованы, чтобы быть выполненными GPU?

155
задан talonmies 20 February 2016 в 08:23
поделиться

2 ответа

Hardware

Если устройство GPU имеет, например, 4 мультипроцессора, и они могут выполнять 768 потоков каждый: тогда в данный момент времени не более 4*768 потоков будут действительно работать параллельно (если вы запланировали больше потоков, они будут ждать своей очереди).

Программные

потоки организованы в блоки. Блок выполняется многопроцессорным устройством. Потоки блока могут быть идентифицированы (проиндексированы) с помощью 1Dimension(x), 2Dimensions (x,y) или 3Dim индексов (x,y,z), но в любом случае xyz <= 768 для нашего примера (другие ограничения применяются к x,y,z, см. руководство и возможности вашего устройства).

Очевидно, что если вам нужно больше, чем эти 4*768 потоков, вам нужно больше, чем 4 блока. Блоки могут быть также проиндексированы 1D, 2D или 3D. Существует очередь блоков, ожидающих поступления в GPU (потому что в нашем примере GPU имеет 4 мультипроцессора и только 4 блока выполняются одновременно).

Теперь простой случай: обработка изображения 512x512

Предположим, мы хотим, чтобы один поток обрабатывал один пиксель (i,j).

Мы можем использовать блоки по 64 потока в каждом. Тогда нам понадобится 512*512/64 = 4096 блоков (таким образом, чтобы иметь 512x512 потоков = 4096*64)

Обычно (для облегчения индексации изображения) потоки организуются в двумерные блоки, имеющие blockDim = 8 x 8 (64 потока в блоке). Я предпочитаю называть это threadsPerBlock.

dim3 threadsPerBlock(8, 8);  // 64 threads

и 2D gridDim = 64 x 64 блоков (4096 необходимых блоков). Я предпочитаю называть это numBlocks.

dim3 numBlocks(imageWidth/threadsPerBlock.x,  /* for instance 512/8 = 64*/
              imageHeight/threadsPerBlock.y); 

Ядро запускается следующим образом:

myKernel <<<numBlocks,threadsPerBlock>>>( /* params for the kernel function */ );       

Наконец: будет что-то вроде "очереди из 4096 блоков", где блок ожидает назначения одного из мультипроцессоров GPU для выполнения своих 64 потоков.

В ядре пиксель (i,j), который будет обрабатываться потоком, вычисляется так:

uint i = (blockIdx.x * blockDim.x) + threadIdx.x;
uint j = (blockIdx.y * blockDim.y) + threadIdx.y;
279
ответ дан 23 November 2019 в 21:55
поделиться

предположим, что графический процессор 9800GT: 14 мультипроцессоров, каждый из которых имеет 8 потоковых процессоров, а размер деформации равен 32, что означает, что каждый потоковый процессор обрабатывает до 32 потоков. 14 * 8 * 32 = 3584 - максимальное количество текущих потоков.

если вы выполняете это ядро ​​с более чем 3584 потоками (скажем, 4000 потоков, и не важно, как вы определяете блок и сетку. Gpu будет обрабатывать их одинаково):

func1();
__syncthreads();
func2();
__syncthreads();

тогда порядок выполнения этих двух функций заключаются в следующем:

1. func1 выполняется для первых 3584 потоков

2.func2 выполняется для первых 3584 потоков

3.func1 выполняется для оставшихся потоков

4.func2 выполняется для оставшихся потоков

7
ответ дан 23 November 2019 в 21:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: