Знайомство з технологією CUDA

12 хв. читання

Складність обчислювальних завдань вимагає різкого збільшення ресурсів і швидкодії комп'ютерів. Найбільш перспективним напрямком збільшення швидкості розв'язку прикладних завдань є широке впровадження ідей паралелізму в роботу обчислювальних систем. Сьогодні спроектовано і випробувано сотні різних комп'ютерів, що використовують у своїй архітектурі той чи інший вид паралельної обробки даних. Основна складність при проектуванні паралельних програм – забезпечення правильної послідовності взаємодій між різними обчислювальними процесами, а також координація ресурсів, що розділяються між ними.

Сьогодні поговоримо про те, що таке CUDA і як ця технологія допомагає пришвидшити обробку даних. Коду писати не будемо, а більше розглянемо все в теорії. І якщо вам буде цікаво, то вже у наступній статті я розповім про те, як писати програми використовуючи дану технологію.

Вступ

CUDA— програмно-апаратна архітектура паралельних обчислень, яка дозволяє істотно збільшити обчислювальну продуктивність завдяки використанню графічних процесорів NVIDIA.

При використанні цієї технології слід знати такі основні поняття:

  • пристрій (device) – сама відеокарта, графічний процесор (GPU) – виконує команди центрального процесора;
  • хост (host) – центральний процесор (CPU) – запускає різні завдання на пристрої, виділяє пам'ять тощо;
  • ядро (kernel) – функція (завдання), що буде виконуватися на GPU.

CUDA дозволяє програмістам реалізовувати на спеціальному спрощеному діалекті мови програмування С алгоритми, що виконуються на графічних процесорах Nvidia, і включати спеціальні функції в текст програми на С. Архітектура CUDA дає розробнику можливість на свій розсуд організовувати доступ до набору інструкцій GPU й управляти його пам'яттю.

Дана технологія підтримує декілька мов програмування. Серед них є і Java, і Python, і багато інших. Хто читав мою попередню статтю, то помітив, що я згадував про виклик функції з C програми для взаємодії з графічним процесором. Чому я так робив, коли підтримується такий великий список мов програмування? Все тому, що для більшості мов, які підтримує CUDA написані лише бібліотеки-обгортки з використанням того ж JNI для Java, та інших технологій для інших мов програмування. Та і я використовував CUDA в поєднанні з іншою бібліотекою, для якої немає обгортки на Java.

Етапи запуску програми на GPU або як все відбувається

Розглянемо, як проходить запуск програми на графічному процесорі.

  1. Хост виділяє потрібну кількість пам'яті на пристрої;
  2. Хост копіює дані зі своєї пам'яті в пам'ять пристрою;
  3. Хост запускає ядро на пристрої;
  4. Пристрій виконує це ядро;
  5. Хост копіює результати з пам'яті пристрою в свою пам'ять.
Знайомство з технологією CUDA
Processing flow on CUDA

На рисунку продемонстровано всі кроки запуску програми, окрім першого (не знаю чому його пропустили, WIKI).

Знайомство з технологією CUDA
Взаємодія CPU та GPU

Як видно з рисунка, центральний процесор взаємодіє з графічним через CUDA Runtime API, CUDA Driver API та CUDA Libraries. Runtime та Driver API відрізняються між собою рівнем абстракції. Тобто, перший варіант є більш високого рівня у плані програмування, більш абстрактний, а другий – навпаки більш низького (на рівні драйвера). Загалом, Runtime API є абстрактною обгорткою над Driver API. Під час програмування, ви можете використовувати будь-який варіант. З власного досвіду можу сказати, що при використанні Driver API потрібно писати трохи «зайвого» коду та й цей варіант трошки складніший.

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

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

Поясню, що я написав. Для того, щоб запустити певні задачі на GPU – треба витратити «трохи» часу на виділення пам'яті, копіювання результату тощо, тому не потрібно виконувати на графічному процесорі легкі завдання (які виконуються за мілісекунди). Навіщо виконувати на GPU те, з чим легко, а головне швидше може справитися і центральний процесор?

У Вас може виникнути питання типу: «Тоді для чого взагалі використовувати GPU, якщо потрібно витрачати дорогоцінний час на виділення пам'яті та інші непотрібні речі?». Коли я тільки почав вивчати CUDA, то сам так думав, але з часом зрозумів, що це дуже потужна технологія. Далі розповім чому.

Їдемо далі.

Апаратна частина

Архітектура GPU побудована трохи інакше, ніж CPU. Оскільки графічні процесори спочатку використовувалися тільки для графічних розрахунків, що припускають незалежну паралельну обробку даних, то GPU призначений саме для паралельних обчислень. Він спроектований так, щоб виконувати велику кількість потоків (елементарних паралельних процесів).

Знайомство з технологією CUDA
Архітектура CPU та GPU

Як видно з рисунка – GPU містить дуже багато простих арифметико-логічних пристроїв (АЛП), які об'єднані в декілька груп і мають спільну пам'ять. Це допомагає підвищити продуктивність в обчислювальних завданнях, але трохи ускладнює програмування. Для досягнення найкращого прискорення необхідно продумувати стратегії доступу до пам'яті й враховувати апаратні особливості.

GPU орієнтований на виконання програм з великим об'ємом даних та розрахунків і являє собою масив потокових процесорів (Streaming Processor Array), що складається з кластерів текстурних процесорів (Texture Processor Clusters, TPC). TPC складається з набору мультипроцесорів (SM – Streaming Multi-processor), кожен з яких містить кілька потокових процесорів (SP – Streaming Processors) або ядер (у сучасних графічних процесорах к-сть ядер перевищує 1024). Набір ядер кожного мультипроцесора працює за принципом SIMD (проте, з деякою відмінністю) – реалізація, що дозволяє групі процесорів, що працюють паралельно, працювати з різними даними, але при цьому всі вони в будь-який момент часу повинні виконувати однакову команду. Якщо по-простому, то декілька потоків виконують одне і те ж саме завдання.

Знайомство з технологією CUDA
Мультипроцесори, SM

В результаті GPU фактично став пристроєм, що реалізує потокову обчислювальну модель (stream computing model) – є потоки вхідних і вихідних даних, що складаються з однакових елементів, які можуть бути оброблені незалежно один від одного.

Знайомство з технологією CUDA
Stream

Обчислювальні можливості

Кожна відеокарта має так звані compute capabilities – кількісна характеристика швидкості виконання певних операцій на графічному процесорі. Це число показує те, наскільки швидко відеокарта буде виконувати свою роботу.

У Nvidia цю характеристику позначають Compute Capability Version. В таблиці наведені деякі відеокарти й відповідні їм обчислювальні можливості.

Compute Capability Version GPU Відеокарта
1.0 G80, G92, G92b, G94, G94b GeForce 8800GTX/Ultra, Tesla C/D/S870, FX4/5600, 360M, GT 420
1.1 G86, G84, G98, G96, G96b, G94, G94b, G92, G92b GeForce 8400GS/GT, 8600GT/GTS, 8800GT/GTS, 9400GT, 9600 GSO, 9600GT, 9800GTX/GX2, 9800GT, GTS 250, GT 120/30/40, FX 4/570, 3/580, 17/18/3700, 4700x2, 1xxM, 32/370M, 3/5/770M, 16/17/27/28/36/37/3800M, NVS420/50
1.2 GT218, GT216, GT215 GeForce 210, GT 220/40, FX380 LP, 1800M, 370/380M, NVS 2/3100M
1.3 GT200, GT200b GeForce GTX 260, GTX 275, GTX 280, GTX 285, GTX 295, Tesla C/M1060, S1070, Quadro CX, FX 3/4/5800
2.0 GF100, GF110 GeForce (GF100) GTX 465, GTX 470, GTX 480, Tesla C2050, C2070, S/M2050/70, Quadro Plex 7000, Quadro 4000, 5000, 6000, GeForce (GF110) GTX 560 TI 448, GTX570, GTX580, GTX590
........ ......... ........
5.0 GM107, GM108 GeForce GTX 750 Ti, GeForce GTX 750, GeForce GTX 860M, GeForce GTX 850M, GeForce 840M, GeForce 830M
........ ......... ........

Повний перелік можна знайти тут. Compute Capability Version описує дуже багато параметрів, серед яких: к-сть потоків на блок, максимальна к-сть блоків та потоків, розмір warp та багато іншого.

Потоки, блоки та сітки

CUDA використовує велику кількість окремих потоків для розрахунків. Всі вони групуються в ієрархію – grid / block / thread.

Знайомство з технологією CUDA
Структура блоків

Верхній рівень – grid – відповідає ядру й об'єднує всі потоки, що виконують дане ядро. Grid – одновимірний або двомірний масив блоків (block). Кожен блок (block) являє собою 1 / 2 / 3 -мірний масив потоків (threads). При цьому кожен блок являє собою повністю незалежний набір скоординованих між собою потоків. Потоки з різних блоків не можуть між собою взаємодіяти.

Вище я згадував про відмінність від SIMD архітектури. Є ще таке поняття, як warp – група з 32 потоків (залежно від архітектури GPU, але майже завжди 32). Так ось, тільки потоки в межах однієї групи (warp) можуть фізично виконуватися одночасно. Потоки різних варпів можуть знаходитися на різних стадіях виконання програми. Такий метод обробки даних позначається терміном SIMT (Single Instruction – Multiple Theads). Управління роботою варпів виконується на апаратному рівні.

Чому інколи центральний процесор виконує завдання швидше ніж графічний?

Як я вже писав раніше – не потрібно виконувати на GPU надто легкі завдання. Тут потрібно уточнити два поняття:

  1. Затримка – в загальному випадку, це час очікування між запитом на якийсь певний ресурс та отриманням доступу до цього ресурсу;
  2. Пропускна здатність – кількість операцій, що виконуються за одиницю часу.

Отже, головне питання: чому графічний процесор іноді тупить? Поясню на простому прикладі, який я колись прочитав в одній статті.

Є у нас два автомобілі:

  • легковий фургон – швидкість 120 км/год, здатен вмістити 9 людей;
  • автобус – швидкість 90 км/год, здатен вмістити 30 людей.

Якщо, одна операція – переміщення однієї людини на певну відстань, хай буде 1 кілометр, то затримка (час, за який одна людина проїде 1 км) для першого авто 3600/120 = 30 с, а пропускна здатність 9/30 = 0.3. Для автобуса – 3600/90 = 40 с, та 30/40 = 0.75.

Так ось, CPU – фургон, GPU – автобус: він має велику затримку, але також і велику пропускну здатність. Якщо для вашого завдання затримка кожної конкретної операції не так важлива як кількість цих операцій в секунду – то варто розглянути застосування GPU.

Висновки

Відмінними рисами GPU (в порівнянні з CPU) є:

  • архітектура, максимально націлена на збільшення швидкості розрахунку текстур і складних графічних об'єктів;
  • пікова потужність типового GPU набагато вище, ніж у CPU;
  • завдяки спеціалізованій конвеєрній архітектурі, GPU набагато ефективніший в обробці графічної інформації, ніж центральний процесор.

Головним мінусом, на мою думку, є те, що ця технологія підтримується тільки відеокартами Nvidia.

Графічний процесор не завжди може дати прискорення при виконанні певних алгоритмів. Тому перед використанням GPU для обчислень потрібно добре подумати, чи потрібен він в даному випадку взагалі. Ви можете використовувати відеокарту для складних обчислень: робота з графікою чи зображеннями, інженерні розрахунки тощо, але не використовуйте GPU для простих завдань (звичайно, Ви можете, але тоді ефективність буде дорівнювати 0).

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

До зустрічі! І пам'ятайте на майбутнє:

Використовуючи графічний процесор – сповільнити програму набагато простіше, ніж прискорити.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 6.2K
Приєднався: 7 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація