Розуміння розмірів сітки CUDA, розмірів блоку та організації потоків (просте пояснення) [закрито]


161

Як організовано потоки для виконання GPU?


Посібник з програмування CUDA повинен бути гарним місцем для початку. Я також рекомендую ознайомитись із введенням CUDA звідси .
Том

Відповіді:


287

Обладнання

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

Програмне забезпечення

нитки організовані в блоки. Блок виконується багатопроцесорним блоком. Нитки блоку можна ідентифікувати (індексувати) за допомогою індексів 1Dimension (x), 2Dimensions (x, y) або 3Dim (x, y, z), але в будь-якому випадку x y z <= 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)

Загальноприйнято організовувати (щоб полегшити індексацію зображення) потоки в 2D блоки, що мають blockDim = 8 x 8 (64 потоки на блок). Я вважаю за краще називати це темиPerBlock.

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;

11
Якщо кожен блок може запускати 768 потоків, навіщо використовувати лише 64? Якщо ви будете використовувати максимальний ліміт 768, у вас буде менше блоків і так краща продуктивність.
Аліза

10
@Aliza: блоки є логічними , межа 768 потоків - для кожного фізичного блоку обробки. Ви використовуєте блоки відповідно до специфікацій вашої проблеми, щоб розподілити роботу по потоках. Мало ймовірно, що ви завжди можете використовувати блоки з 768 ниток для кожної проблеми. Уявіть, що ви повинні обробити зображення розміром 64x64 (4096 пікселів). 4096/768 = 5.333333 блоки?
cibercitizen1

1
блок є логічним, але кожному блоку призначено ядро. якщо блоків більше, ніж ядер, блоки стоять у черзі, поки сердечники не стануть вільними. У вашому прикладі ви можете використовувати 6 блоків, і додаткові потоки нічого не роблять (2/3 потоків на 6-му блоці).
Аліза

3
@ cibercitizen1 - Я думаю, що пункт Алізи хороший: якщо можливо, потрібно використовувати якомога більше потоків на блок. Якщо існує обмеження, яке вимагає меншої кількості потоків, краще поясніть, чому це могло статися у другому прикладі (але все ж поясніть перший, більш простий і бажаний випадок).

6
@thouis Так, можливо. Але справа в тому, що обсяг пам'яті, необхідний кожному потоку, залежить від програми. Наприклад, у моїй останній програмі кожен потік викликає функцію оптимізації, яка має найменший квадрат, вимагаючи "багато" пам'яті. Настільки, що блоки не можуть бути більше 4х4 ниток. Незважаючи на це, отримана швидкість була драматичною проти послідовної версії.
cibercitizen1

9

Припустимо, графічний процесор 9800 ГТ:

  • він має 14 мультипроцесорів (SM)
  • кожен SM має 8 потокових процесорів (потокові процесори AKA, SP або сердечники)
  • дозволяє до 512 потоків на блок
  • warpsize - 32 (це означає, що кожен з процесорів потоку 14x8 = 112 може запланувати до 32 потоків)

https://www.tutorialspoint.com/cuda/cuda_threads.htm

Блок не може мати більш активних потоків, ніж 512, тому __syncthreadsможе синхронізувати лише обмежену кількість потоків. тобто якщо ви виконаєте наступне з 600 потоками:

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

тоді ядро ​​повинно працювати два рази, і порядок виконання буде таким:

  1. func1 виконується для перших 512 потоків
  2. func2 виконується для перших 512 потоків
  3. func1 виконується для решти потоків
  4. func2 виконується для решти потоків

Примітка:

Основним моментом є __syncthreadsоперація, що працює в масштабі блоку, і вона не синхронізує всі потоки.


Я не впевнений у точній кількості потоків, які __syncthreadsможуть синхронізуватися, оскільки ви можете створити блок з більш ніж 512 потоками і дозволити основі обробляти планування. На мій погляд, точніше сказати: func1 виконується принаймні для перших 512 потоків.

Перш ніж редагувати цю відповідь (ще в 2010 році), я виміряв 14x8x32 нитки, які синхронізувались за допомогою __syncthreads.

Я дуже вдячний, якщо хтось перевірить це ще раз для отримання більш точної інформації.


Що станеться, якщо func2 () залежить від результатів func1 (). Я думаю, що це неправильно
Кріс

@Chris Я писав це сім років тому, але якщо я пам'ятаю правильно, я зробив тест на це і дійшов цього висновку, що ядра з більшою кількістю потоків, ніж gpu, ведуть себе таким чином. Якщо ви трапили тест на цю справу і досягли іншого результату, мені доведеться видалити цю публікацію.
Біжан

Вибачте, я думаю, що це неправильно також, що GPU може одночасно запускати 112 потоків.
Стівен Лу

@StevenLu ви пробували? також я не думаю, що 112 одночасних потоків не мають сенсу для GPU. 112 - кількість процесорів потоку. Зараз я майже не можу згадати CUDA :)
Біжан

1
@StevenLu максимальна кількість потоків тут не є проблемою, __syncthreadsце загальноблокова операція, і той факт, що він фактично не синхронізує всі потоки, є неприємністю для студентів CUDA. Тож я оновив свою відповідь на основі інформації, яку ви мені дали. Я дійсно ціную це.
Біжань
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.