Розподілені обчислення gpu. GPU-оптимізація – великі істини. Майнінг на відеокарті – легкі гроші чи невиправдані витрати

Головна / Корисне ПЗ

Говорячи про паралельні обчислення на GPU ми повинні пам'ятати, в який час ми живемо, сьогодні це час коли все у світі пришвидшено настільки, що ми з вами втрачаємо рахунок часу, не помічаючи, як воно пролітатиме повз. Все, що ми робимо, пов'язано з високою точністю та швидкістю обробки інформації, в таких умовах нам неодмінно потрібні інструменти для того, щоб обробити всю інформацію, яка у нас є і перетворити її на дані, до того ж кажучи про такі завдання треба пам'ятати, що ці завдання необхідні не тільки великим організаціям або мегакорпораціям, вирішення таких завдань зараз потребують і рядові користувачі, які вирішують свої життєві завдання, пов'язані з високими технологіями у себе вдома на персональних комп'ютерах! Поява NVIDIA CUDA була не дивовижною, а, швидше, обгрунтованою, тому, як незабаром буде необхідно обробляти значно трудомісткіші завдання на ПК, ніж раніше. Робота, яка раніше займала дуже багато часу, тепер займатиме лічені хвилини, відповідно, це вплине на загальну картину всього світу!

Що таке обчислення на GPU

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

Що таке CUDA

CUDA — технологія програмування спрощеною мовою Сі алгоритмів, які виконуються на графічних процесорах прискорювачів GeForce восьмого покоління і старше, а також відповідних карток Quadro і Tesla від компанії NVIDIA. CUDA дозволяє включати до тексту Сі програми спеціальні функції. Ці функції пишуться спрощеною мовою програмування Сі і виконуються на графічному процесорі. Початкова версія CUDA SDK була представлена ​​15 лютого 2007 року. Для успішної трансляції коду цією мовою до складу CUDA SDK входить власний Сі-компілятор командного рядка nvcc компанії NVIDIA. Компілятор nvcc створений на основі відкритого компілятора Open64 і призначений для трансляції host-коду (головного, керуючого коду) і device-коду (апаратного коду) (файлів з розширенням .cu) в об'єктні файли, придатні в процесі складання кінцевої програми або бібліотеки в будь-якій середовище програмування, наприклад Microsoft Visual Studio.

Можливості технології

  1. Стандартна мова C для паралельної розробки додатків на GPU.
  2. Готові бібліотеки чисельного аналізу для швидкого перетворення Фур'є та базового пакету програм лінійної алгебри.
  3. Спеціальний драйвер CUDA для обчислень із швидкою передачею даних між GPU та CPU.
  4. Можливість взаємодії драйвера CUDA з графічними драйверами OpenGL і DirectX.
  5. Підтримка операційних систем Linux 32/64-bit, Windows XP 32/64-bit та MacOS.

Переваги технології

  1. Інтерфейс програмування програм CUDA (CUDA API) базується на стандартній мові програмування Сі з деякими обмеженнями. Це спрощує і згладжує процес вивчення архітектури CUDA.
  2. Пам'ять (shared memory) розміром 16 Кб, що розділяється між потоками, може бути використана під організований користувачем кеш з ширшою смугою пропускання, ніж при вибірці зі звичайних текстур.
  3. Більш ефективні транзакції між пам'яттю центрального процесора та відеопам'яттю.
  4. Повна апаратна підтримка цілих і побітових операцій.

Приклад застосування технології

cRark

Найважче в цій програмі — це настоянка. Програма має консольний інтерфейс, але завдяки інструкції, яка додається до самої програми, вона може користуватися. Далі наведено коротка інструкціяз налаштування програми. Ми перевіримо програму на працездатність і порівняємо її з іншою подібною програмою, яка не використовує NVIDIA CUDA, в даному випадку це відома програма Advanced Archive Password Recovery.

З скаченого архіву cRark нам потрібно лише три файли: crark.exe, crark-hp.exe і password.def. Сrark.exe - це консольна утилітарозкриття паролів RAR 3.0 без шифрованих файлів усередині архіву (тобто розкриваючи архів ми бачимо назви, але не можемо розпакувати архів без пароля).

Сrark-hp.exe - це консольна утиліта розтину паролів RAR 3.0 із шифруванням всього архіву (тобто розкриваючи архів ми не бачимо ні назви, ні самих архівів і не можемо розпакувати архів без пароля).

Password.def - це будь-який перейменований текстовий файл з дуже невеликим змістом (наприклад: 1-й рядок: ## 2-й рядок: ?*, у цьому випадку розтин пароля відбуватиметься з використанням усіх символів). Password.def – це керівник програми cRark. У файлі містяться правила розкриття пароля (або область знаків, яку crark.exe буде використовувати у своїй роботі). Докладніше про можливості вибору цих знаків написано в текстовому файлі отриманому при розтині завантаженого на сайті автора програми cRark: russian.def .

Підготовка

Відразу скажу, що програма працює тільки якщо ваша відеокарта заснована на GPU за допомогою рівня прискорення CUDA 1.1. Так що серія відеокарт, заснованих на чіпі G80, таких як GeForce 8800 GTX відпадає, тому що вони мають апаратну підтримку прискорення CUDA 1.0. Програма підбирає за допомогою CUDA лише паролі на архіви RAR версій 3.0+. Необхідно встановити все програмне забезпечення, пов'язане з CUDA , а саме:

  • Драйвери NVIDIA , що підтримують CUDA , починаючи з 169.21
  • NVIDIA CUDA SDK, починаючи з версії 1.1
  • NVIDIA CUDA Toolkit, починаючи з версії 1.1

Створюємо будь-яку папку в будь-якому місці (наприклад на диску С:) і називаємо будь-яким ім'ям, наприклад, «3.2». Поміщаємо туди файли: crark.exe, crark-hp.exe та password.def та запаролений/зашифрований архів RAR.

Далі слід запустити консоль командної рядки Windowsі перейти до неї створену папку. У Windows Vista і 7 слід викликати меню "Пуск" і в полі пошуку ввести "cmd.exe", у Windows XP з меню "Пуск" спочатку слід викликати діалог "Виконати" і вже в ньому вводити "cmd.exe". Після відкриття консолі слід ввести команду виду: cd C:\папка\, cd C:\3.2 у цьому випадку.

Набираємо в текстовому редакторідва рядки (можна також зберегти текст як файл .bat у папці з cRark) для вибору пароля запароленого RAR-архіву з незашифрованими файлами:

echo off;
cmd /K crark (назва архіву).rar

для підбору пароля запароленого та зашифрованого RAR-архіву:

echo off;
cmd /K crark-hp (назва архіву).rar

Копіюємо 2 рядки текстового файлуу консоль та натискаємо Enter (або запускаємо.bat файл).

Результати

Процес розшифровки показаний малюнку:

Швидкість підбору на cRark за допомогою CUDA становила 1625 паролів/секунду. За одну хвилину тридцять шість секунд був підібраний пароль із трьома символами: «q)$». Для порівняння: швидкість перебору Advanced Archive Password Recovery на моєму двоядерному процесорі Athlon 3000+ дорівнює максимум 50 паролів/секунду і перебір мав би тривати 5 годин. Тобто підбір по bruteforce в cRark архіву RAR за допомогою відеокарти GeForce 9800 GTX+ відбувається у 30 разів швидше, ніж на CPU.

Для тих, у кого процесор Intel, гарна системна платаз високою частотою системної шини (FSB 1600 МГц), показник CPU rate та швидкість перебору будуть вищими. А якщо у вас чотириядерний процесор і пари відеокарт рівня GeForce 280 GTX, то швидкодія перебору паролів прискорюється в рази. Підбиваючи підсумки прикладу треба сказати, що це завдання було вирішено із застосуванням технології CUDA всього за якихось 2 хвилини замість 5-ти годин, що говорить про високий потенціал можливостей для даної технології!

Висновки

Розглянувши сьогодні технологію для паралельних обчислень CUDA ми наочно побачили всю потужність і величезний потенціал для розвитку даної технології на прикладі програми відновлення пароля для RAR архівів. Треба сказати про перспективи цієї технології, дана технологіянеодмінно знайде місце в житті кожної людини, яка вирішить їй скористатися, чи то наукові завдання, чи завдання, пов'язані з обробкою відео, чи навіть економічні завдання, які вимагають швидкого точного розрахунку, все це призведе до неминучого підвищення продуктивності праці, яке не можна буде не помітити . На сьогоднішній день до лексикону вже починає входити словосполучення «домашній суперкомп'ютер»; Цілком очевидно, що для втілення такого предмета в реальність у кожному будинку вже є інструмент під назвою CUDA. Починаючи з моменту виходу карт, заснованих на чіпі G80 (2006 р.), випущено величезну кількість прискорювачів на базі NVIDIA, що підтримують технологію CUDA, яка здатна втілити мрії про суперкомп'ютери в кожному будинку в реальність. Просуваючи технологію CUDA, NVIDIA піднімає свій авторитет в очах клієнтів у вигляді надання додаткових можливостейїх обладнання, яке у багатьох уже куплено. Залишається тільки вірити, що незабаром CUDA буде розвиватися дуже швидко і дасть користувачам повною мірою скористатися всіма можливостями паралельних обчислень на GPU.

Особливості архітектури AMD/ATI Radeon

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

Проводимо аналогії далі – після довгої еволюції на суші ссавці проникли в море, де потіснили звичайних морських мешканців. У конкурентній боротьбі ссавці використовували як нові просунуті здібності, що з'явилися на земній поверхні, так і спеціально придбані для адаптації до життя у воді. Так само GPU, ґрунтуючись на перевагах архітектури для 3D-графіки, все більше і більше мають спеціальні функціональні можливості, корисні для виконання далеких від графіки завдань.

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

GPU складається з кількох десятків (30 для Nvidia GT200, 20 – для Evergreen, 16 – для Fermi) процесорних ядер, які в термінології Nvidia називаються Streaming Multiprocessor, а в термінології ATI – SIMD Engine. У рамках цієї статті ми будемо називати їх мініпроцесорами, тому що вони виконують кілька сотень програмних ниток і вміють майже все те саме, що і звичайний CPU, але все-таки не все.

Маркетингові назви заплутують - у них, для більшої важливості, вказують кількість функціональних модулів, які вміють віднімати та множити: наприклад, 320 векторних "cores" (ядер). Ці ядра більше нагадують зерна. Краще представляти GPU як якийсь багатоядерний процесор з великою кількістюядер, що виконують одночасно безліч ниток.

Кожен мініпроцесор має локальну пам'ять, розміром 16 KБ для GT200, 32 KБ – для Evergreen та 64 KБ – для Fermi (по суті, це програмований L1 кеш). Вона має схоже з кешем першого рівня стандартного CPU час доступу і виконує аналогічні функції якнайшвидшої доставки даних до функціональних модулів. В архітектурі Fermi частина локальної пам'яті може бути налаштована як звичайний кеш. У GPU локальна пам'ять служить для швидкого обміну даними між нитками, що виконуються. Одна із звичайних схем GPU-програми така: на початку локальну пам'ять завантажуються дані з глобальної пам'яті GPU. Це просто звичайна відеопам'ять, розташована (як і системна пам'ять) окремо від «свого» процесора - у разі відео вона розпаяна кількома мікросхемами на текстоліті відеокарти. Далі кілька сотень ниток працюють із цими даними локальної пам'яті і записують результат у глобальну пам'ять, після чого той передається в CPU. До обов'язку програміста входить написання інструкцій завантаження та вивантаження даних із локальної пам'яті. По суті це розбиття даних [конкретної задачі] для паралельної обробки. GPU підтримує також інструкції запису/читання в пам'ять, але вони неефективні і затребувані зазвичай на завершальному етапі для «склейки» результатів обчислень всіх мініпроцесорів.

Локальна пам'ять загальна для всіх ниток, що виконуються в мініпроцесорі, тому, наприклад, в термінології Nvidia вона навіть називається shared, а терміном local memory позначається прямо протилежне, а саме: якась персональна область окремої нитки в глобальній пам'яті, видима і доступна тільки їй. Але крім локальної пам'яті в мініпроцесор є ще одна область пам'яті, у всіх архітектурах приблизно в чотири рази більша за обсягом. Вона розділена порівну між усіма нитками, що виконуються, це регістри для зберігання змінних і проміжних результатів обчислень. На кожну нитку припадає кілька десятків регістрів. Точна кількість залежить від того, скільки ниток виконує мініпроцесор. Ця кількість дуже важлива, так як латентність глобальної пам'яті дуже велика, сотні тактів, і без кешів немає де зберігати проміжні результати обчислень.

І ще одна важлива риса GPU: "м'яка" векторність. Кожен мініпроцесор має велику кількість обчислювальних модулів (8 для GT200, 16 для Radeon і 32 для Fermi), але всі вони можуть виконувати тільки одну і ту ж інструкцію, з однією програмною адресою. Операнди ж можуть бути різні, у різних ниток свої. Наприклад, інструкція скласти вміст двох регістрів: вона одночасно виконується всіма обчислювальними пристроями, але регістри беруться різні. Передбачається, що всі нитки GPU-програми, здійснюючи паралельну обробку даних, загалом рухаються паралельним курсом за кодом програми. Таким чином, усі обчислювальні модулі завантажуються рівномірно. А якщо нитки через розгалуження у програмі розійшлися у своєму шляху виконання коду, то відбувається так звана серіалізація. Тоді використовуються в повному обсязі обчислювальні модулі, оскільки нитки подають виконання різні інструкції, а блок обчислювальних модулів може виконувати, як ми вже сказали, лише інструкцію з однією адресою. І, зрозуміло, продуктивність у своїй падає стосовно максимальної.

Плюсом є те, що векторизація відбувається повністю автоматично, це не програмування з використанням SSE, MMX тощо. І GPU сам обробляє розбіжності. Теоретично можна взагалі писати програми для GPU, не думаючи про векторну природу виконуючих модулів, але швидкість такої програми буде не дуже високою. Мінус полягає у великій ширині вектора. Вона більша, ніж номінальна кількість функціональних модулів, і становить 32 для GPU Nvidia та 64 для Radeon. Нитки обробляються блоками відповідного розміру. Nvidia називає цей блок ниток терміном warp, AMD - wave front, що те саме. Таким чином, на 16 обчислювальних пристроях "хвильовий фронт" довжиною 64 нитки обробляється за чотири такти (за умови звичайної довжини інструкції). Автор віддає перевагу в даному випадку терміну warp, через асоціацію з морським терміном warp, що позначає пов'язаний зі скручених мотузок канат. Так і нитки «скручуються» та утворюють цільну зв'язку. Втім, "wave front" теж може асоціюватися з морем: інструкції так само прибувають до виконавчих пристроїв, як хвилі одна за одною накочуються на берег.

Якщо всі нитки однаково просунулися у виконанні програми (перебувають у одному місці) і, таким чином, виконують одну інструкцію, то все чудово, але якщо ні – відбувається уповільнення. У цьому випадку нитки з одного warp або wave front знаходяться в різних місцях програми, вони розбиваються на групи ниток, що мають однакове значення номера інструкції (іншими словами, покажчика інструкцій (instruction pointer)). І як і раніше виконуються одночасно часу нитки однієї групи - всі виконують однакову інструкцію, але з різними операндами. У результаті warp здійснюється в стільки разів повільніше, на скільки груп він розбитий, а кількість ниток у групі не має значення. Навіть якщо група складається з однієї нитки, все одно вона буде виконуватися стільки ж часу, скільки повний warp. У залізі це реалізовано за допомогою маскування певних ниток, тобто інструкції формально виконуються, але результати виконання нікуди не записуються і надалі не використовуються.

Хоча в кожен момент часу кожен мініпроцесор (Streaming MultiProcessor або SIMD Engine) виконує інструкції, що належать лише одному warp (зв'язці ниток), він має кілька десятків активних варпів у пулі, що виконується. Виконавши інструкції одного варпа, мініпроцесор виконує не наступну по черзі інструкцію ниток даного варпа, а інструкції когось іншого варпа. Той варп може бути в зовсім іншому місці програми, це не впливатиме на швидкість, тому що тільки всередині варпа інструкції всіх ниток повинні бути однаковими для виконання з повною швидкістю.

У даному випадку кожен з 20 SIMD Engine має чотири активні wave front, у кожному з яких 64 нитки. Кожна нитка позначена короткою лінією. Всього: 64×4×20=5120 ниток

Таким чином, з огляду на те, що кожен warp або wave front складається з 32-64 ниток, мініпроцесор має кілька сотень активних ниток, які виконуються практично одночасно. Нижче ми побачимо, які архітектурні вигоди обіцяє така велика кількість паралельних ниток, але спочатку розглянемо, які обмеження є у складових GPU мініпроцесорів.

Головне, що в GPU немає стека, де могли б зберігатись параметри функцій та локальні змінні. Через велику кількість ниток для стека просто немає місця на кристалі. Дійсно, так як GPU одночасно виконує близько 10000 ниток, при розмірі стека однієї нитки в 100 КБ сукупний об'єм складе 1 ГБ, що дорівнює стандартному об'єму відеопам'яті. Тим більше, немає ніякої можливості помістити стек скільки-небудь істотного розміру в самому ядрі GPU. Наприклад, якщо покласти 1000 байт стека на нитку, то тільки на один мініпроцесор знадобиться 1 МБ пам'яті, що майже в п'ять разів більше за сукупний обсяг локальної пам'яті мініпроцесора і пам'яті, відведеної на зберігання регістрів.

Тому в GPU-програмі немає рекурсії, і з викликами функцій особливо не розгорнешся. Усі функції безпосередньо підставляються код при компіляції програми. Це обмежує сферу застосування GPU завданнями обчислювального типу. Іноді можна використовувати обмежену емуляцію стека з використанням глобальної пам'яті рекурсійних алгоритмів з відомою невеликою глибиною ітерацій, але це нетипове застосування GPU. Для цього необхідно спеціально розробляти алгоритм, досліджувати можливість реалізації без гарантії успішного прискорення в порівнянні з CPU.

У Fermi вперше з'явилася можливість використовувати віртуальні функції, але їх застосування лімітовано відсутністю великого швидкого кеша для кожної нитки. На 1536 ниток припадає 48 КБ або 16 КБ L1, тобто віртуальні функції в програмі можна використовувати відносно рідко, інакше для стека також використовуватиметься повільна глобальна пам'ять, що уповільнить виконання і, швидше за все, не принесе вигод порівняно з CPU-варіантом.

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

Переваги архітектури

Але вважає GPU дуже швидко. І цьому йому допомагає його висока мультипоточность. Велика кількість активних ниток дозволяє частково приховати велику латентність розташованої окремо глобальної відеопам'яті, що становить близько 500 тактів. Особливо добре вона нівелюється для коду з високою густиною арифметичних операцій. Таким чином, не потрібна дорога з точки зору транзисторів ієрархія кешів L1-L2-L3. Замість неї на кристалі можна розмістити множину обчислювальних модулів, забезпечивши видатну арифметичну продуктивність. А поки виконуються інструкції однієї нитки чи варпа, решта сотень ниток спокійно чекає на свої дані.

У Fermi було введено кеш другого рівня розміром близько 1 МБ, але його не можна порівнювати з кешами сучасних процесорів, він більше призначений для комунікації між ядрами та різноманітними програмними трюками. Якщо його розмір розділити між усіма десятками тисяч ниток, на кожну прийдеться зовсім незначний обсяг.

Але крім латентності глобальної пам'яті, в обчислювальному пристрої існує ще безліч латентностей, які треба приховати. Це латентність передачі всередині кристала від обчислювальних пристроїв до кешу першого рівня, тобто локальної пам'яті GPU, і до регістрів, а також кешу інструкцій. Регістровий файл, як і локальна пам'ять, розташовані окремо від функціональних модулів, і швидкість доступу до них становить приблизно півтора десятки тактів. І знову ж таки велика кількість ниток, активних варпів, дозволяє ефективно приховати цю латентність. Причому загальна смуга пропускання (bandwidth) доступу до локальної пам'яті всього GPU, з урахуванням кількості складових мініпроцесорів, значно більше, ніж bandwidth доступу до кешу першого рівня у сучасних CPU. GPU може переробити значно більше даних за одиницю часу.

Можна відразу сказати, що якщо GPU не буде забезпечений великою кількістю паралельних ниток, то він матиме майже нульову продуктивність, тому що він працюватиме з тим же темпом, начебто повністю завантажений, а виконуватиме набагато менший обсяг роботи. Наприклад, нехай замість 10000 ниток залишиться лише одна: продуктивність впаде приблизно в тисячу разів, бо не тільки не всі блоки будуть завантажені, а й позначаться всі латентності.

Проблема приховування латентностей є гострою і для сучасних високочастотних CPU, для її усунення використовуються витончені способи - глибока конвеєризація, позачергове виконання інструкцій (out-of-order). Для цього потрібні складні планувальники виконання інструкцій, різні буфери і т. п., що займає місце на кристалі. Це все потрібне для кращої продуктивності в однопотоковому режимі.

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

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

приклад

Одне з класичних завдань для GPU - це завдання обчислення взаємодії N тіл, що створюють гравітаційне поле. Але якщо нам, наприклад, знадобиться розрахувати еволюцію системи Земля-Місяць-Сонце, то GPU нам поганий помічник: мало об'єктів. До кожного об'єкта треба обчислити взаємодії з усіма іншими об'єктами, які всього два. У разі руху Сонячної системи з усіма планетами та їх місяцями (приблизно кілька сотень об'єктів) GPU все ще не надто ефективний. Втім, і багатоядерний процесор через високі накладні витрати на управління потоками теж не зможе проявити всю свою міць, працюватиме в однопоточному режимі. Але якщо потрібно також розрахувати траєкторії комет і об'єктів поясу астероїдів, то це вже завдання для GPU, так як об'єктів достатньо, щоб створити необхідну кількість паралельних потоків розрахунку.

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

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

Деталі мікроархітектури AMD Radeon

Ми розглянули базові принципи організації GPU, вони спільні для відеоприскорювачів усіх виробників, оскільки вони спочатку мали одне цільове завдання - шейдерні програми. Проте виробники знайшли можливість розійтися в деталях мікроархітектурної реалізації. Хоча і CPU різних вендорів часом сильно відрізняються, навіть сумісними, як, наприклад, Pentium 4 і Athlon або Core. Архітектура Nvidia вже досить широко відома, зараз ми розглянемо Radeon та виділимо основні відмінності у підходах цих вендорів.

Відеокарти AMD отримали повноцінну підтримку обчислень загального призначення починаючи з сімейства Evergreen, в якому також були вперше реалізовані специфікації DirectX 11. Картки сімейства 47xx мають низку суттєвих обмежень, які будуть розглянуті нижче.

Відмінності у розмірі локальної пам'яті (32 КБ у Radeon проти 16 КБ у GT200 і 64 КБ у Fermi) загалом не важливі. Як і розмір wave front у 64 нитках у AMD проти 32 ниток у warp у Nvidia. Практично будь-яку GPU-програму можна легко переконфігурувати та налаштувати на ці параметри. Продуктивність може змінитися на десятки відсотків, але у випадку з GPU це не так важливо, бо GPU-програма зазвичай працює в десять разів повільніше, ніж аналог для CPU, або в десять разів швидше, або взагалі не працює.

Більш важливим є використання AMD технології VLIW (Very Long Instruction Word). Nvidia використовує скалярні прості інструкції, що оперують зі скалярними регістрами. Її прискорювачі реалізують простий класичний RISC. Відеокартки AMD мають таку ж кількість регістрів, як GT200, але векторні регістри 128-бітні. Кожна VLIW-інструкція оперує кількома чотирикомпонентними 32-бітними регістрів, що нагадує SSE, але можливості VLIW набагато ширші. Це не SIMD (Single Instruction Multiple Data), як SSE - тут інструкції для кожної пари операнда можуть бути різними і навіть залежними! Наприклад, нехай компоненти регістру А називаються a1, a2, a3, a4; у регістра B – аналогічно. Можна обчислити за допомогою однієї інструкції, яка виконується за один такт, наприклад, число a1×b1+a2×b2+a3×b3+a4×b4 або двовимірний вектор (a1×b1+a2×b2, a3×b3+a4×b4 ).

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

Завдяки векторним інструкціям, пікова продуктивність Radeon у числах одинарної точності дуже висока і вже становить терафлопи.

Один векторний регістр може замість чотирьох чисел одинарної точності зберігати число подвійної точності. І одна VLIW-інструкція може або скласти дві пари чисел double, або помножити два числа або помножити два числа і скласти з третім. Таким чином, пікова продуктивність у double приблизно в п'ять разів нижче, ніж у float. Для старших моделей Radeon вона відповідає продуктивності Nvidia Tesla на новій архітектурі Fermi та набагато вище, ніж продуктивність у double карток на архітектурі GT200. У споживчих відеокартах Geforce на основі Fermi максимальна швидкість double-обчислень була зменшена вчетверо.


Принципова схема роботи Radeon. Представлено лише один мініпроцесор із 20 паралельно працюючих

Виробники GPU, на відміну від виробників CPU (передусім x86-сумісних), не пов'язані питаннями сумісності. GPU-програма спочатку компілюється в якийсь проміжний код, а при запуску програми драйвер компілює цей код у машинні інструкції, специфічні для конкретної моделі. Як було описано вище, виробники GPU скористалися цим, придумавши зручні ISA (Instruction Set Architecture) для своїх GPU та змінюючи їх від покоління до покоління. Це у будь-якому випадку додало якісь відсотки продуктивності через відсутність (через непотрібність) декодера. Але компанія AMD пішла ще далі, вигадавши власний форматрозташування інструкцій у машинному коді. Вони розташовані не послідовно (згідно з листингом програми), а по секціях.

Спочатку йде секція інструкцій щодо умовних переходів, які мають посилання на секції безперервних арифметичних інструкцій, що відповідають різним гілкам переходів. Вони називаються VLIW bundles (зв'язки VLIW-інструкцій). У цих секціях містяться лише арифметичні вказівки з даними з регістрів або локальної пам'яті. Така організація спрощує управління потоком інструкцій та доставку їх до виконавчих пристроїв. Це тим більше корисно, враховуючи, що VLIW-інструкції мають порівняно великий розмір. Існують також секції для інструкцій звернень до пам'яті.

Секції інструкцій умовних переходів
Секція 0Розгалуження 0Посилання на секцію №3 безперервних арифметичних інструкцій
Секція 1Розгалуження 1Посилання на секцію №4
Секція 2Розгалуження 2Посилання на секцію №5
Секції безперервних арифметичних інструкцій
Секція 3VLIW-інструкція 0VLIW-інструкція 1VLIW-інструкція 2VLIW-інструкція 3
Секція 4VLIW-інструкція 4VLIW-інструкція 5
Секція 5VLIW-інструкція 6VLIW-інструкція 7VLIW-інструкція 8VLIW-інструкція 9

GPU обох виробників (і Nvidia, і AMD) також мають вбудовані інструкції швидкого обчислення за кілька тактів основних математичних функцій, квадратного кореня, експоненти, логарифмів, синусів і косінусів для чисел одинарної точності. І тому є спеціальні обчислювальні блоки. Вони «відбулися» від необхідності реалізації швидкої апроксимації цих функцій у геометричних шейдерах.

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

Але більш очевидна риса, що видає графічне походження пристрою, це блоки читання двовимірних та тривимірних текстур за допомогою білінійної інтерполяції. Вони широко використовуються в GPU-програмах, оскільки забезпечують прискорене та спрощене читання масивів даних read-only. Одним із стандартних варіантів поведінки GPU-додатку є читання масивів вихідних даних, обробка їх у обчислювальних ядрах та запис результату в інший масив, який передається далі назад у CPU. Така схема стандартна та поширена, тому що зручна для архітектури GPU. Завдання, що вимагають інтенсивно читати та писати в одну велику область глобальної пам'яті, що містять, таким чином, залежність за даними, важко розпаралелити та ефективно реалізувати на GPU. Також їхня продуктивність сильно залежатиме від латентності глобальної пам'яті, яка дуже велика. А от якщо завдання описується шаблоном «читання даних – обробка – запис результату», то майже напевно можна отримати великий приріст від її виконання на GPU.

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

Хоча розмір кешів L1-L2 у картках Nvidia і AMD приблизно подібний, що, очевидно, викликано вимогами оптимальності з погляду графіки ігор, латентність доступу до цих кешів суттєво відрізняється. Латентність доступу у Nvidia більша, і текстурні кеші Geforce в першу чергу допомагають скоротити навантаження на шину пам'яті, а не безпосередньо прискорити доступ до даних. Це не помітно у графічних програмах, але важливо для програм загального призначення. У Radeon латентність текстурного кеша нижче, зате вище латентність локальної пам'яті мініпроцесорів. Можна навести такий приклад: для оптимального перемноження матриць на картках Nvidia краще скористатися локальною пам'яттю, завантажуючи туди матрицю побічно, а AMD кращепокластися на низьколатентний текстурний кеш, читаючи елементи матриці в міру потреби. Але це вже досить тонка оптимізація, і вже принципово перекладеного на GPU алгоритму.

Ця відмінність також проявляється у разі використання 3D-текстури. Один із перших бенчмарків обчислень на GPU, який показував серйозну перевагу AMD, якраз і використовував 3D-текстури, оскільки працював із тривимірним масивом даних. А латентність доступу до текстур у Radeon істотно швидше, і 3D-випадок додатково оптимізовано в залозі.

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

Обмеження серії Radeon 47xx

У цьому сімействі підтримка обчислень на GPU неповна. Можна відзначити три важливих моменту. По-перше, немає локальної пам'яті, тобто вона фізично є, але не має можливості універсального доступу, необхідного сучасним стандартом GPU-програм. Вона емулює програмно в глобальній пам'яті, тобто її використання на відміну від повнофункціонального GPU не принесе вигод. Другий момент – обмежена підтримка різних інструкцій атомарних операцій із пам'яттю та інструкцій синхронізації. І третій момент - це досить невеликий розмір кешу вказівок: починаючи з деякого розміру програми відбувається уповільнення швидкості в рази. Є й інші дрібні обмеження. Можна сказати, тільки програми, які ідеально підходять для GPU, будуть добре працювати на цій відеокартці. Нехай у простих тестових програмах, які оперують лише з регістрами, відеокарта може показувати хороший результат у Gigaflops, щось складне ефективно запрограмувати під неї проблематично.

Переваги та недоліки Evergreen

Якщо порівняти продукти AMD та Nvidia, то, з точки зору обчислень на GPU, серія 5xxx виглядає дуже потужним GT200. Такий потужний, що за піковою продуктивністю перевершує Fermi приблизно в два з половиною рази. Особливо після того, як параметри нових відеокарт Nvidia були урізані, скорочено кількість ядер. Але поява в Fermi кешу L2 спрощує реалізацію на GPU деяких алгоритмів, таким чином розширюючи сферу застосування GPU. Що цікаво, для добре оптимізованих під минуле покоління GT200 CUDA-програм архітектурні нововведення Fermi часто нічого не дали. Вони прискорилися пропорційно збільшенню кількості обчислювальних модулів, тобто менш ніж удвічі (для чисел одинарної точності), або навіть менше, бо ПСП пам'яті не збільшилася (чи з інших причин).

І в задачах, що добре лягають на архітектуру GPU, що мають виражену векторну природу (наприклад, перемноженні матриць), Radeon показує відносно близьку до теоретичного піку продуктивність і обганяє Fermi. Не кажучи вже про багатоядерні CPU. Особливо в задачах із числами з одинарною точністю.

Але Radeon має меншу площу кристала, менший тепловиділення, енергоспоживання, більший вихід придатних і, відповідно, меншу вартість. І безпосередньо в завданнях 3D-графіки виграш Fermi, якщо він взагалі є, набагато менший від різниці в площі кристала. Багато в чому це пояснюється тим, що обчислювальна архітектура Radeon з 16 обчислювальними пристроями на мініпроцесор, розміром wave front в 64 нитки та векторними VLIW-інструкціями є прекрасною для його головного завдання - обчислення графічних шейдерів. Для більшості звичайних користувачів продуктивність в іграх і ціна пріоритетні.

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

Наприклад, у повністю паралельній задачі підбору ключів Radeon, що легко векторизується, в кілька разів швидше Geforce і в кілька десятків разів швидше CPU.

Це відповідає загальній концепції AMD Fusion, згідно з якою GPU повинні доповнювати CPU, і в майбутньому інтегруватися в саме ядро ​​CPU, як раніше математичний співпроцесор був перенесений з окремого кристала в ядро ​​процесора (це сталося років двадцять тому, перед появою перших процесорів Pentium). GPU буде інтегрованим графічним ядром та векторним співпроцесором для потокових завдань.

Radeon використовується хитра техніка змішування інструкцій з різних wave front при виконанні функціональними модулями. Це легко зробити, оскільки інструкції є повністю незалежними. Принцип аналогічний до конвеєрного виконання незалежних інструкцій сучасними CPU. Очевидно, це дозволяє ефективно виконувати складні, що займають багато байт, векторні VLIW-інструкції. У CPU для цього потрібен складний планувальник для виявлення незалежних інструкцій або використання технології Hyper-Threading, яка також забезпечує CPU свідомо незалежними інструкціями з різних потоків.

такт 0такт 1такт 2такт 3такт 4такт 5такт 6такт 7VLIW-модуль
wave front 0wave front 1wave front 0wave front 1wave front 0wave front 1wave front 0wave front 1
інстр. 0інстр. 0інстр. 16інстр. 16інстр. 32інстр. 32інстр. 48інстр. 48VLIW0
інстр. 1VLIW1
інстр. 2VLIW2
інстр. 3VLIW3
інстр. 4VLIW4
інстр. 5VLIW5
інстр. 6VLIW6
інстр. 7VLIW7
інстр. 8VLIW8
інстр. 9VLIW9
інстр. 10VLIW10
інстр. 11VLIW11
інстр. 12VLIW12
інстр. 13VLIW13
інстр. 14VLIW14
інстр. 15VLIW15

128 інструкцій двох wave front, кожен із яких складається з 64 операцій, виконуються 16 VLIW-модулями за вісім тактів. Відбувається чергування, і кожен модуль насправді має два такти на виконання цілої інструкції за умови, що він на другому такті почне виконувати нову паралельно. Ймовірно, це допомагає швидко виконати VLIW-інструкцію типу a1×a2+b1×b2+c1×c2+d1×d2, тобто виконати вісім таких інструкцій за вісім тактів. (Формально виходить, одну за такт.)

У Nvidia, мабуть, такої технології немає. І без VLIW, для високої продуктивності з використанням скалярних інструкцій потрібно висока частотароботи, що автоматично підвищує тепловиділення та висуває високі вимоги до технологічного процесу(щоб змусити працювати схему більш високої частоті).

Недоліком Radeon з точки зору GPU-обчислень є велика нелюбов до розгалужень. GPU взагалі не шанують розгалуження через вищеописану технологію виконання інструкцій: відразу групою ниток з однією програмною адресою. (До речі, така техніка називається SIMT: Single Instruction - Multiple Threads (одна інструкція - багато ниток), за аналогією з SIMD, де одна інструкція виконує одну операцію з різними даними.) Однак Radeon розгалуження не люблять особливо: це викликано більшим розміром зв'язування ниток . Зрозуміло, що якщо програма не повністю векторна, то чим більший розмір warp або wave front, тим гірше, тому що при розбіжності в дорозі за програмою сусідніх ниток утворюється більше груп, які необхідно виконувати послідовно (серіалізовано). Припустимо, всі нитки розбрелися, тоді у разі розміру warp у 32 нитки програма працюватиме у 32 рази повільніше. А у разі розміру 64, як у Radeon, – у 64 рази повільніше.

Це помітне, але не єдине прояв «неприязні». У відеокартах Nvidia кожен функціональний модуль, який називається CUDA core, має спеціальний блок обробки розгалужень. А у відеокартах Radeon на 16 обчислювальних модулів - всього два блоки управління розгалуженнями (вони виведені з домену арифметичних блоків). Так що навіть проста обробка інструкції умовного переходу, нехай її результат і однаковий для всіх ниток у wave front, займає додатковий час. І швидкість просідає.

Компанія AMD виробляє ще й CPU. Вони вважають, що для програм з великою кількістю розгалужень все одно краще підходить CPU, а GPU призначений для векторних програм.

Так що Radeon надає в цілому менше можливостей для ефективного програмування, але забезпечує найкраще співвідношення ціна-продуктивність у багатьох випадках. Іншими словами, програм, які можна ефективно (з користю) перевести з CPU на Radeon, менше, ніж програм, які ефективно працюють на Fermi. Проте ті, які ефективно перенести можна, працюватимуть на Radeon ефективніше в багатьох сенсах.

API для GPU-обчислень

Самі технічні специфікації Radeon виглядають привабливо, нехай і не варто ідеалізувати та абсолютизувати обчислення на GPU. Але не менш важливе для продуктивності програмне забезпечення, необхідне для розробки та виконання GPU-програми – компілятори з мови високого рівня та run-time, тобто драйвер, який здійснює взаємодію між частиною програми, що працює на CPU, та безпосередньо GPU. Воно навіть важливіше, ніж у випадку CPU: для CPU не потрібен драйвер, який здійснюватиме менеджмент передачі даних, і з погляду компілятора GPU більш вибагливий. Наприклад, компілятор повинен обійтися мінімальною кількістю регістрів для зберігання проміжних результатів обчислень, а також акуратно вбудовувати виклики функцій, знов-таки використовуючи мінімум регістрів. Адже чим менше регістрів використовує нитку, тим більше ниток можна запустити і повніше навантажити GPU, краще приховуючи час доступу до пам'яті.

І ось програмна підтримка продуктів Radeon поки що відстає від розвитку заліза. (На відміну від ситуації з Nvidia, де відкладався випуск заліза, і продукт вийшов у урізаному вигляді.) Ще недавно OpenCL-компілятор виробництва AMD мав статус бета, з безліччю недоробок. Він дуже часто генерував помилковий код або відмовлявся компілювати код із правильного вихідного тексту, або сам видавав помилку роботи та зависав. Тільки наприкінці весни вийшов реліз із високою працездатністю. Він теж не позбавлений помилок, але їх значно поменшало, і вони, як правило, виникають на бічних напрямках, коли намагаються запрограмувати щось на межі коректності. Наприклад, працюють з типом uchar4, який задає 4-байтову чотирикомпонентну змінну. Цей тип є в специфікаціях OpenCL, але працювати з ним на Radeon не варто, бо регістри-то 128-бітові: ті ж чотири компоненти, але 32-бітові. А така змінна uchar4 все одно займе цілий регістр, тільки потрібні будуть додаткові операції упаковки і доступу до окремих байтових компонентів. Компілятор не повинен мати жодних помилок, але компіляторів без недоліків не буває. Навіть Intel Compiler після 11-ти версій має помилки компіляції. Виявлені помилки виправлені у наступному релізі, який вийде ближче до осені.

Але є ще безліч речей, які потребують доопрацювання. Наприклад, стандартний GPU-драйвер для Radeon досі не має підтримки GPU-обчислень з використанням OpenCL. Користувач повинен завантажувати та встановлювати додатковий спеціальний пакет.

Але найголовніше - це відсутність будь-яких бібліотек функцій. Для дійсних чисел подвійної точності немає навіть синуса, косинуса та експоненти. Що ж, для складання-множення матриць цього не потрібно, але якщо ви хочете запрограмувати щось складніше, треба писати всі функції з нуля. Або чекати на новий реліз SDK. Незабаром має вийти ACML (AMD Core Math Library) для GPU-родини Evergreen з підтримкою основних матричних функцій.

На даний момент, на думку автора статті, реальним для програмування відеокарт Radeon є використання API Direct Compute 5.0, природно враховуючи обмеження: орієнтацію на платформу Windows 7 та Windows Vista. Microsoft має великий досвід у створенні компіляторів, і можна очікувати повністю працездатний реліз дуже скоро, Microsoft безпосередньо в цьому зацікавлена. Але Direct Compute орієнтований потреби інтерактивних додатків: щось порахувати і відразу візуалізувати результат - наприклад, перебіг рідини поверхнею. Це не означає, що його не можна використовувати просто для розрахунків, але це не є його природним призначенням. Скажімо, Microsoft не планує додавати в Direct Compute бібліотечні функції - саме ті, яких немає зараз у AMD. Тобто те, що зараз можна ефективно порахувати на Radeon – деякі не надто витончені програми, – можна реалізувати і на Direct Compute, який набагато простіше OpenCL і має бути стабільнішим. Плюс, він повністю портабельний, працюватиме і на Nvidia, і на AMD, так що компілювати програму доведеться лише один раз, тоді як реалізації OpenCL SDK компаній Nvidia та AMD не зовсім сумісні. (У тому сенсі, що якщо розробити OpenCL-програму на системі AMD з використанням AMD OpenCL SDK, вона може не піти так просто на Nvidia. Можливо, потрібно компілювати той самий текст із використанням Nvidia SDK. І, зрозуміло, навпаки.)

Потім, у OpenCL багато надмірної функціональності, оскільки OpenCL задумана як універсальна мова програмування та API для широкого кола систем. І GPU, і CPU, і Cell. Так що на випадок, якщо треба просто написати програму для типової системи користувача (процесор плюс відеокарта), OpenCL не представляється, так би мовити, «високопродуктивним». Кожна функція має десять параметрів, і дев'ять із них мають бути встановлені в 0. А для того, щоб встановити кожен параметр, треба викликати спеціальну функцію, яка теж має параметри.

І найголовніший поточний плюс Direct Compute – користувачу не треба встановлювати спеціальний пакет: все, що необхідно, вже є у DirectX 11.

Проблеми розвитку GPU-обчислень

Якщо взяти сферу персональних комп'ютерів, Ситуація така: існує не так багато завдань, для яких потрібна велика обчислювальна потужність і сильно не вистачає звичайного двоядерного процесора. Начебто з моря на сушу вилізли великі ненажерливі, але неповороткі чудовиська, а на суші й є майже нічого. І споконвічні обителі земної поверхні зменшуються у розмірах, вчаться менше споживати, як завжди буває при дефіциті природних ресурсів. Якби зараз була така ж потреба у продуктивності, як 10-15 років тому, GPU-обчислення прийняли б на ура. А так проблеми сумісності та відносної складності GPU-програмування виходять на перший план. Краще написати програму, яка б працювала на всіх системах, ніж програму, яка працює швидко, але запускається тільки на GPU.

Дещо краще перспективи GPU з точки зору використання у професійних додатках та секторі робочих станцій, оскільки там більше потреби у продуктивності. З'являються плагіни для 3D-редакторів за допомогою GPU: наприклад, для рендерингу за допомогою трасування променів - не плутати зі звичайним GPU-рендеренгом! Щось з'являється і для 2D-редакторів та редакторів презентацій з прискоренням створення складних ефектів. Програми обробки відео також поступово мають підтримку GPU. Вищенаведені завдання через свою паралельну сутність добре лягають на архітектуру GPU, але зараз створена дуже велика база коду, налагодженого, оптимізованого під всі можливості CPU, так що потрібен час, щоб з'явилися хороші GPU-реалізації.

У цьому сегменті виявляються такі слабкі сторони GPU, як обмежений обсяг відеопам'яті - приблизно в 1 ГБ для звичайних GPU. Одним із головних факторів, що знижують продуктивність GPU-програм, є необхідність обміну даними між CPU та GPU по повільній шині, а через обмежений обсяг пам'яті доводиться передавати більше даних. І тут перспективною виглядає концепція AMD щодо поєднання GPU та CPU в одному модулі: можна пожертвувати високою пропускною здатністюграфічної пам'яті для легкого і простого доступу до загальної пам'яті, до того ж з меншою латентністю. Ця висока ПСП нинішньої відеопам'яті DDR5 набагато більше затребувана безпосередньо графічними програмамичим більшістю програм GPU-обчислень. Взагалі, загальна пам'ять GPU і CPU просто істотно розширить сферу застосування GPU, уможливить використання його обчислювальних можливостей у невеликих підзавданнях програм.

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

Якщо серед усіх завдань сучасних комп'ютеріввибрати одну, то це буде комп'ютерна графіка- Зображення світу, в якому ми живемо. І оптимальна для цієї мети архітектура не може бути поганою. Це настільки важливе та фундаментальне завдання, що спеціально розроблене для неї залізо має нести в собі універсальність і бути оптимальним для різних завдань. Тим більше, що відеокартки успішно еволюціонують.

Використання GPU для обчислень за допомогою C++ AMP

Досі в обговоренні прийомів паралельного програмування ми розглядали лише ядра процесора. Ми придбали деякі навички розпаралелювання програм з кількох процесорів, синхронізації доступу до спільно використовуваних ресурсів та використання високошвидкісних примітивів синхронізації без застосування блокувань.

Однак, існує ще один спосіб розпаралелювання програм - графічні процесори (GPU), що мають більшу кількість ядер, ніж навіть високопродуктивні процесори. Ядра графічних процесорів чудово підходять для реалізації паралельних алгоритмів обробки даних, а велика їхня кількість з лишком окупає незручності виконання програм на них. У цій статті ми познайомимося з одним із способів виконання програм на графічному процесорі з використанням комплекту розширень мови C++ під назвою C++ AMP.

Розширення C++ AMP засновані мовою C++ і саме тому у цій статті демонструватимуться приклади мовою C++. Однак, при помірному використанні механізму взаємодій. NET, ви зможете використовувати алгоритми C++ AMP у своїх програмах для .NET. Але про це ми поговоримо наприкінці статті.

Введення у C++ AMP

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

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

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

    Підтримка синхронізації між ядрами графічного процесора, що виконують одне завдання, дуже мізерна, і повністю відсутня між ядрами графічного процесора, що виконують різні завдання. Ця обставина вимагає синхронізації графічного процесора зі звичайним процесором.

Відразу постає питання, які завдання підходять для вирішення на графічному процесорі? Майте на увазі, що не всякий алгоритм підходить для виконання на графічному процесорі. Наприклад, графічні процесори не мають доступу до пристроїв вводу/виводу, тому у вас не вдасться підвищити продуктивність програми, яка отримує стрічки RSS з інтернету, за рахунок використання графічного процесора. Однак на графічний процесор можна перенести багато обчислювальних алгоритмів і забезпечити масове їх розпаралелювання. Нижче наводиться кілька прикладів таких алгоритмів (цей список далеко не повний):

    збільшення та зменшення різкості зображень та інші перетворення;

    швидке перетворення Фур'є;

    транспонування та множення матриць;

    сортування чисел;

    інверсія хеша "в лоб".

Відмінним джерелом додаткових прикладів може бути блог Microsoft Native Concurrency, де наводяться фрагменти коду та пояснення до них для різних алгоритмів, реалізованих на C++ AMP.

C++ AMP - це фреймворк, що входить до складу Visual Studio 2012, що дає розробникам на C++ простий спосіб виконання обчислень на графічному процесорі і вимагає лише наявності драйвера DirectX 11. Корпорація Microsoft випустила C++ AMP як відкриту специфікацію, яку може реалізувати будь-який виробник комп'ютерів.

Фреймворк C++ AMP дозволяє виконувати код на графічних прискорювачів (accelerators), що є обчислювальними пристроями. За допомогою драйвера DirectX 11 фреймворк C++ AMP динамічно виявляє усі прискорювачі. До складу C++ AMP входять також програмний емулятор прискорювача та емулятор на базі звичайного процесора, WARP, які служить запасним варіантом у системах без графічного процесора або з графічним процесором, але без драйвера DirectX 11, і використовує кілька ядер та інструкції SIMD.

А тепер приступимо до дослідження алгоритму, який можна розпаралелити для виконання на графічному процесорі. Реалізація нижче приймає два вектори однакової довжини та обчислює поточковий результат. Важко уявити щось більш прямолінійне:

Void VectorAddExpPointwise(float* first, float* second, float* result, int length) ( for (int i = 0; i< length; ++i) { result[i] = first[i] + exp(second[i]); } }

Щоб розпаралелити цей алгоритм на звичайному процесорі, потрібно розбити діапазон ітерацій на кілька піддіапазонів і запустити по одному потоку виконання для кожного з них. Ми присвятили досить багато часу у попередніх статтях саме такому способу розпаралелювання нашого першого прикладу пошуку простих чисел- ми бачили, як це можна зробити, створюючи потоки вручну, передаючи завдання пулу потоків і використовуючи Parallel.For і PLINQ для автоматичного розпаралелювання. Згадайте також, що при розпаралелювання схожих алгоритмів на звичайному процесорі ми особливо дбали, щоб не роздробити завдання на дрібні завдання.

Для графічного процесора ці попередження непотрібні. Графічні процесори мають безліч ядер, що виконують потоки дуже швидко, а вартість перемикання контексту значно нижча, ніж у звичайних процесорах. Нижче наводиться фрагмент, який намагається використовувати функцію parallel_for_eachіз фреймворку C++ AMP:

#include #include using namespace concurrency; void VectorAddExpPointwise(float* first, float* second, float* result, int length) ( array_view avFirst (length, first); array_view avSecond(length, second); array_view avResult(length, result); avResult.discard_data(); parallel_for_each(avResult.extent, [=](index<1>i) restrict(amp) (avResult[i] = avFirst[i] + fast_math::exp(avSecond[i]); )); avResult.synchronize(); )

Тепер досліджуємо кожну частину коду окремо. Відразу зауважимо, що загальна форма головного циклу збереглася, але цикл, що використовувався спочатку, був замінений викликом функції parallel_for_each. Насправді принцип перетворення циклу на виклик функції або методу для нас не новий - раніше вже демонструвався такий прийом із застосуванням методів Parallel.For() і Parallel.ForEach() з бібліотеки TPL.

Далі, вхідні дані (параметри first, second та result) обгортаються екземплярами array_view. Клас array_view служить для обгортання даних, які передаються графічному процесору (прискорювачу). Його шаблонний параметр визначає тип даних та їх розмірність. Щоб виконати на графічному процесорі інструкції, що звертаються до даних, спочатку оброблюваним на звичайному процесорі, хтось чи щось має подбати про копіювання даних у графічний процесор, оскільки більшість сучасних графічних карток є окремими пристроями з власною пам'яттю. Це завдання вирішують екземпляри array_view – вони забезпечують копіювання даних на вимогу і тільки коли вони дійсно необхідні.

Коли графічний процесор виконає завдання, копіюються дані назад. Створюючи екземпляри array_view з аргументом типу const, ми гарантуємо, що first і second будуть скопійовані на згадку про графічний процесор, але не копіюватимуться назад. Аналогічно, викликаючи discard_data(), ми виключаємо копіювання результату з пам'яті звичайного процесора в пам'ять прискорювача, але ці дані копіюватимуться у зворотному напрямку.

Функція parallel_for_each приймає об'єкт extent, що визначає форму даних і функцію для застосування до кожного елемента в об'єкті extent. У цьому прикладі ми використовували лямбда-функцію, підтримка яких з'явилася в стандарті ISO C++2011 (C++11). Ключове слово restrict (amp) доручає компілятор перевірити можливість виконання тіла функції на графічному процесорі і відключає більшу частину синтаксису C++, який не може бути скомпільований в інструкції графічного процесора.

Параметр лямбда-функції, index<1>об'єкта представляє одномірний індекс. Він повинен відповідати об'єкту extent, що використовується - якби ми оголосили об'єкт extent двовимірним (наприклад, визначивши форму вихідних даних у вигляді двовимірної матриці), індекс також повинен був би бути двомірним. Приклад такої ситуації наводиться трохи нижче.

Зрештою, виклик методу synchronize()Наприкінці методу VectorAddExpPointwise гарантує копіювання результатів обчислень з array_view avResult, вироблених графічним процесором, назад у масив результату.

На цьому ми закінчуємо наше перше знайомство зі світом C++ AMP, і тепер ми готові до докладніших досліджень, а також до більш цікавих прикладів, що демонструють вигоди від використання паралельних обчислень на графічному процесорі. Складання векторів - не найкращий алгоритм і не найкращий кандидат для демонстрації використання графічного процесора через великі накладні витрати на копіювання даних. У наступному підрозділі будуть показані два цікавіші приклади.

Розмноження матриць

Перший «справжній» приклад, який ми розглянемо, – множення матриць. Для реалізації ми візьмемо простий кубічний алгоритм множення матриць, а чи не алгоритм Штрассена, має час виконання, близьке до кубічного ~O(n 2.807). Для двох матриць: матриці A розміром m x w та матриці B розміром w x n, наступна програма виконає їх множення та поверне результат - матрицю C розміром m x n:

Void MatrixMultiply(int * A, int m, int w, int * B, int n, int * C) ( for (int i = 0; i< m; ++i) { for (int j = 0; j < n; ++j) { int sum = 0; for (int k = 0; k < w; ++k) { sum += A * B; } C = sum; } } }

Розпаралелити цю реалізацію можна декількома способами, і при бажанні розпаралелити цей код для виконання на звичайному процесорі правильним вибором був прийом розпаралелювання зовнішнього циклу. Однак графічний процесор має досить велику кількість ядер і розпаралелив тільки зовнішній цикл, ми не зможемо створити достатню кількість завдань, щоб завантажити роботою всі ядра. Тому має сенс розпаралелити два зовнішні цикли, залишивши внутрішній цикл незайманим:

Void MatrixMultiply (int * A, int m, int w, int * B, int n, int * C) ( array_view avA(m, w, A); array_view avB(w, n, B); array_view avC(m, n, C); avC.discard_data(); parallel_for_each (avC.extent, [=](index<2>idx) restrict(amp) ( int sum = 0; for (int k = 0; k< w; ++k) { sum + = avA(idx*w, k) * avB(k*w, idx); } avC = sum; }); }

Ця реалізація все ще близько нагадує послідовну реалізацію множення матриць і приклад складання векторів, що наводилися вище, за винятком індексу, який є двовимірним і доступний у внутрішньому циклі із застосуванням оператора . Наскільки ця версія швидше за послідовну альтернативу, що виконується на звичайному процесорі? Помноження двох матриць (цілих чисел) розміром 1024 х 1024 послідовна версія на звичайному процесорі виконує в середньому 7350 мілісекунд, тоді як версія для графічного процесора – тримайтеся міцніше – 50 мілісекунд, у 147 разів швидше!

Моделювання руху частинок

Приклади розв'язання задач на графічному процесорі, представлені вище, мають дуже просту реалізацію внутрішнього циклу. Зрозуміло, що так не завжди буде. У блозі Native Concurrency, посилання на який вже наводилося вище, показується приклад моделювання гравітаційних взаємодій між частинками. Моделювання включає нескінченну кількість кроків; на кожному кроці обчислюються нові значення елементів вектора прискорень кожної частки і потім визначаються їх нові координати. Тут розпаралелювання піддається вектор частинок - при досить велику кількість частинок (від кількох тисяч і вище) можна створити досить велику кількість завдань, щоб завантажити роботою всі ядра графічного процесора.

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

// тут float4 - це вектори з чотирма елементами, // репрезентують частинки, що беруть участь в операціях . використовується float absDist = dist.x * dist.x + dist.y * dist.y + dist.z * dist.z; float invDist = 1.0f / sqrt (absDist); = dist*PARTICLE_MASS*invDistCube;

Вихідними даними на кожному кроці моделювання є масив з координатами та швидкостями руху частинок, а в результаті обчислень створюється новий масив з координатами та швидкостями частинок:

Struct particle ( float4 position, velocity; // реалізації конструктора, конструктора копіювання та // оператора = з restrict (amp) опущені для економії місця); void simulation_step (array & previous, array & next, int bodies) (extent<1>ext(bodies); parallel_for_each (ext, [&](index<1>idx) restrict(amp) ( particle p = previous; float4 acceleration(0, 0, 0, 0); for (int body = 0; body)< bodies; ++body) { bodybody_interaction (acceleration, p.position, previous.position); } p.velocity + = acceleration*DELTA_TIME; p.position + = p.velocity*DELTA_TIME; next = p; }); }

Із залученням відповідного графічного інтерфейсу, моделювання може бути дуже цікавим. Повний приклад, представлений командою розробників C++ AMP, можна знайти у блозі Native Concurrency. На моїй системі з процесором Intel Core i7 та відеокартою Geforce GT 740M, моделювання руху 10 000 частинок виконується зі швидкістю ~2.5 кадру в секунду (кроків в секунду) з використанням послідовної версії, що виконується на звичайному процесорі, та 160 кадрів в секунду з використанням оптимізований версії, що виконується на графічному процесорі – величезне збільшення продуктивності.

Перш ніж завершити цей розділ, необхідно розповісти ще одну важливу особливість фреймворку C++ AMP, яка може ще більше підвищити продуктивність коду, що виконується на графічному процесорі. Графічні процесори підтримують програмований кеш даних(часто званий пам'яттю, що розділяється (shared memory)). Значення, що зберігаються в цьому кеші, спільно використовуються всіма потоками виконання однієї мозаїці (tile). Завдяки мозаїчній організації пам'яті, програми на основі фреймворку C++ AMP можуть читати дані з пам'яті графічної карти в пам'ять мозаїки, що розділяється, і потім звертатися до них з декількох потоків виконання без повторного вилучення цих даних з пам'яті графічної карти. Доступ до пам'яті мозаїки виконується приблизно в 10 разів швидше, ніж до пам'яті графічної карти. Іншими словами, у вас є причини читання.

Щоб забезпечити виконання мозаїчної версії паралельного циклу методу parallel_for_each передається домен tiled_extent, який ділить багатовимірний об'єкт extent на багатовимірні фрагменти мозаїки, і лямбда-параметр tiled_index, що визначає глобальний та локальний ідентифікатор потоку всередині мозаїки. Наприклад, матрицю 16x16 можна розділити на фрагменти мозаїки розміром 2x2 (як показано на малюнку нижче) і потім передати функції parallel_for_each:

Extent<2>matrix(16,16); tiled_extent<2,2>tiledMatrix = matrix.tile<2,2>(); parallel_for_each (tiledMatrix, [=](tiled_index<2,2>idx) restrict (amp) ( // ...));

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

При виконанні операцій з матрицями, в ядрі графічного процесора, замість стандартного індексу index<2>, як у прикладах вище, можна використовувати idx.global. Грамотне використання локальної мозаїчної пам'яті та локальних індексів може забезпечити суттєвий приріст продуктивності. Щоб оголосити мозаїчну пам'ять, поділювану всіма потоками виконання однієї мозаїці, локальні змінні можна оголосити зі специфікатором tile_static.

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

Parallel_for_each(tiledMatrix, [=](tiled_index<2,2>idx) restrict(amp) ( // 32 байти спільно використовуються всіма потоками в блоці tile_static int local; // присвоїти значення елементу для цього потоку виконання local = 42; ));

Очевидно, що будь-які вигоди від використання пам'яті, що розділяється, можна отримати тільки в разі синхронізації доступу до цієї пам'яті; тобто потоки не повинні звертатися до пам'яті, доки вона не буде ініціалізована одним із них. Синхронізація потоків у мозаїці виконується за допомогою об'єктів tile_barrier(що нагадує клас Barrier з бібліотеки TPL) - вони зможуть продовжити виконання лише після виклику методу tile_barrier.Wait(), який поверне керування лише коли всі потоки викличуть tile_barrier.Wait. Наприклад:

Parallel_for_each (tiledMatrix, (tiled_index<2,2>idx) restrict(amp) ( // 32 байти спільно використовуються всіма потоками в блоці tile_static int local; // присвоїти значення елементу для цього потоку виконання local = 42; // idx.barrier - екземпляр tile_barrier idx.barrier.wait(); // Тепер цей потік може звертатися до масиву "local", // використовуючи індекси інших потоків виконання!));

Тепер саме час втілити отримані знання у конкретний приклад. Повернемося до реалізації множення матриць, виконаної без застосування мозаїчної організації пам'яті, і додамо до нього оптимізацію, що описується. Припустимо, що розмір матриці кратний числу 256 - це дозволить нам працювати з блоками 16 х 16. Природа матриць допускає можливість побічного їх множення, і ми можемо скористатися цією особливістю (фактично, розподіл матриць на блоки є типовою оптимізацією алгоритму множення матриць, що забезпечує більш ефективне використання кешу процесора).

Суть цього прийому зводиться до наступного. Щоб знайти C i,j (елемент у рядку i і в стовпці j в матриці результату), потрібно обчислити скалярний добуток між A i, * (i-й рядок першої матриці) і B *, j (j-й стовпець у другій матриці ). Однак це еквівалентно обчисленню часткових скалярних творів рядка і стовпця з подальшим підсумовуванням результатів. Ми можемо використовувати цю обставину для перетворення алгоритму множення матриць на мозаїчну версію:

Void MatrixMultiply(int * A, int m, int w, int * B, int n, int * C) ( array_view avA(m, w, A); array_view avB(w, n, B); array_view avC(m, n, C); avC.discard_data(); parallel_for_each (avC.extent.tile<16,16>(), [=](tiled_index<16,16>idx) restrict(amp) ( int sum = 0; int localRow = idx.local, localCol = idx.local; for (int k = 0; k

Суть оптимізації, що описується в тому, що кожен потік в мозаїці (для блоку 16 х 16 створюється 256 потоків) ініціалізує свій елемент в 16 х 16 локальних копіях фрагментів вихідних матриць A і B. Кожному потоку в мозаїці потрібно тільки один рядок і один стовпець з цих блоків, але всі потоки разом будуть звертатися до кожного рядка і кожного стовпця по 16 разів. Такий підхід суттєво знижує кількість звернень до основної пам'яті.

Щоб обчислити елемент (i,j) у матриці результату, алгоритму потрібно повний i-й рядок першої матриці та j-й стовпець другої матриці. Коли потоки мозаїці 16x16, представлені на діаграмі і k=0, заштриховані області першої і другої матрицях будуть прочитані в пам'ять, що розділяється. Потік виконання, що обчислює елемент (i,j) у матриці результату, обчислить частковий скалярний добуток перших k елементів з i-го рядка та j-го стовпця вихідних матриць.

У цьому прикладі застосування мозаїчної організації забезпечує величезний приріст продуктивності. Мозаїчна версія множення матриць виконується набагато швидше за просту версію і займає приблизно 17 мілісекунд (для тих же вихідних матриць розміром 1024 х 1024), що в 430 швидше за версію, що виконується на звичайному процесорі!

Перш ніж закінчити обговорення фреймворку C++ AMP, нам хотілося б згадати інструменти (в Visual Studio), які є у розпорядженні розробників. Visual Studio 2012 пропонує налагоджувач для графічного процесора (GPU), що дозволяє встановлювати контрольні точки, досліджувати стек викликів, читати та змінювати значення локальних змінних (деякі прискорювачі підтримують налагодження для GPU безпосередньо; для інших Visual Studio використовує програмний симулятор), та профільник, що дає можливість оцінювати вигоди, одержувані додатком від розпаралелювання операцій із застосуванням графічного процесора. За додатковою інформацією щодо можливостей налагодження у Visual Studio звертайтеся до статті «Покроковий посібник. Налагодження програми «C++ AMP» на сайті MSDN.

Альтернативи обчислень на графічному процесорі В.NET

До цих пір у цій статті демонструвалися приклади тільки мовою C++, проте є кілька способів використовувати потужність графічного процесора в керованих додатках. Один із способів – використовувати інструменти взаємодій, що дозволяють перекласти роботу з ядрами графічного процесора на низькорівневі компоненти C++. Це рішення відмінно підходить для тих, хто бажає використовувати фреймворк C++ AMP або може використовувати вже готові компоненти C++ AMP в керованих додатках.

Інший спосіб - використовувати бібліотеку, що безпосередньо працює з графічним процесором з керованого коду. Нині є кілька таких бібліотек. Наприклад, GPU.NET та CUDAfy.NET (обидві є комерційними пропозиціями). Нижче наведено приклад з репозиторію GPU.NET GitHub, що демонструє реалізацію скалярного твору двох векторів:

Public static void MultiplyAddGpu(double a, double b, double c) (int ThreadId = BlockDimension.X * BlockIndex.X + ThreadIndex.X; int TotalThreads = BlockDimension.X * GridDimension.X; for (int ElementIdx = ThreadId

Я дотримуюся думки, що набагато простіше та ефективніше освоїти розширення мови (на основі C++ AMP), ніж намагатися організовувати взаємодії на рівні бібліотек або вносити суттєві зміни до мови IL.

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

Бібліотека Task Parallel Library дає нам унікальну можливість включити в роботу всі наявні ядра центрального процесора, хоча при цьому доведеться вирішувати деякі цікаві проблеми синхронізації, надмірного дроблення завдань і нерівного розподілу роботи між потоками виконання.

Фреймворк C++ AMP та інші багатоцільові бібліотеки організації паралельних обчислень на графічному процесорі успішно можна використовувати для розпаралелювання обчислень між сотнями ядер графічного процесора. Нарешті, є, недосліджена раніше, можливість отримати приріст продуктивності від застосування хмарних технологій розподілених обчислень, які останнім часом перетворилися на один з основних напрямів розвитку інформаційних технологій.

Якось довелося мені поговорити на комп'ютерному ринку з технічним директором однієї з численних компаній, що займаються продажем ноутбуків. Цей «фахівець» намагався з піною біля рота пояснити, яка конфігурація ноутбука мені потрібна. Головне посилання його монологу полягало в тому, що час центральних процесорів (CPU) закінчився, і зараз всі програми активно використовують обчислення на графічному процесорі (GPU), а тому продуктивність ноутбука повністю залежить від графічного процесора, а на CPU можна не звертати ніякого уваги. Зрозумівши, що сперечатися і намагатися навчити цього технічного директора абсолютно безглуздо, я не став марнувати часу і купив потрібний мені ноутбук в іншому павільйоні. Проте сам факт такої кричущої некомпетентності продавця мене вразив. Було б зрозуміло, якби він намагався обдурити мене як покупця. Не. Він щиро вірив у те, що говорив. Так, мабуть, маркетологи в NVIDIA і AMD не дарма їдять свій хліб, і їм таки вдалося навіяти деяким користувачам ідею про домінуючу роль графічного процесора в сучасному комп'ютері.

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

Взагалі, обчислення на GPU переважно виконуються на спеціалізованих HPC-системах для наукових розрахунків. А ось додатки користувача, в яких застосовуються обчислення на GPU, можна перерахувати на пальцях. При цьому слід відразу ж зазначити, що термін «обчислення на GPU» в даному випадку не цілком коректний і може ввести в оману. Справа в тому, що якщо програма використовує обчислення на GPU, то це зовсім не означає, що центральний процесор не діє. Обчислення на GPU передбачає перенесення навантаження з центрального процесора на графічний. Як правило, центральний процесор при цьому залишається завантаженим, а використання графічного процесора, поряд із центральним, дозволяє підвищити продуктивність, тобто скоротити час виконання завдання. Причому сам GPU тут виступає у ролі своєрідного співпроцесора для CPU, але в жодному разі не замінює його повністю.

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

Відмінності в архітектурах GPU та CPU

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

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

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

Графічні та центральні процесори різняться і за принципами доступу до пам'яті. У GPU доступ до пам'яті легко передбачуваний: якщо з пам'яті читається текстура текстури, то через деякий час прийде термін і для сусідніх текселів. При записі відбувається те саме: якщо якийсь піксел записується у фреймбуфер, то через кілька тактів записуватиметься піксел, розташований поруч з ним. Тому GPU, на відміну від CPU, просто не потрібна кешпам'ять великого розміру, а для текстур потрібно лише кілька кілобайт. Різний і принцип роботи з пам'яттю у GPU та CPU. Так, всі сучасні GPU мають кілька контролерів пам'яті, та й сама графічна пам'ять швидша, тому графічні процесори мають набагато більше обільшу пропускну здатність пам'яті, порівняно з універсальними процесорами, що дуже важливо для паралельних розрахунків, оперують величезними потоками даних.

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

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

У графічному процесорі, навпаки, основну площу займають саме численні виконавчі блоки, що дозволяє одночасно обробляти кілька тисяч потоків команд.

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

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

Можна навести безліч прикладів наукових розрахунків, де перевага GPU над CPU у плані ефективності обчислень незаперечна. Так, безліч наукових додатків з молекулярного моделювання, газової динаміки, динаміки рідин та іншого відмінно пристосовано для розрахунків на GPU.

Отже, якщо алгоритм розв'язання задачі може бути розпаралелений на тисячі окремих потоків, то ефективність розв'язання такої задачі із застосуванням GPU може бути вищою, ніж її розв'язання засобами тільки процесора загального призначення. Однак не можна так просто взяти і перенести рішення якоїсь задачі з CPU на GPU, хоча б просто тому, що CPU та GPU використовують різні команди. Тобто коли програма пишеться під рішення на CPU, то застосовується набір команд х86 (або набір команд, сумісний із конкретною архітектурою процесора), а ось для графічного процесора використовуються вже зовсім інші набори команд, які знов-таки враховують його архітектуру та можливості. При розробці сучасних 3D-ігор застосовуються API DirectX і OrenGL, що дозволяють програмістам працювати з шейдерами та текстурами. Однак використання API DirectX і OrenGL для неграфічних обчислень на графічному процесорі - це не найкращий варіант.

NVIDIA CUDA та AMD APP

Саме тому, коли почали робити перші спроби реалізувати неграфічні обчислення на GPU (General Purpose GPU, GPGPU), виник компілятор BrookGPU. До створення розробникам доводилося отримувати доступом до ресурсів відеокарти через графічні API OpenGL чи Direct3D, що значно ускладнювало процес програмування, оскільки вимагало специфічних знань - доводилося вивчати принципи роботи з 3D-об'єктами (шейдерами, текстурами тощо.). Це стало причиною обмеженого застосування GPGPU в програмних продуктах. BrookGPU став своєрідним перекладачем. Ці потокові розширення до мови Сі приховували від програмістів тривимірний API і за його використання потреба у знаннях 3D-програмування майже відпала. Обчислювальні потужності відеокарт стали доступними програмістам у вигляді додаткового співпроцесора для паралельних розрахунків. Компілятор BrookGPU обробляв файл із кодом Cі та розширеннями, вибудовуючи код, прив'язаний до бібліотеки з підтримкою DirectX або OpenGL.

Багато в чому завдяки BrookGPU, компанії NVIDIA і ATI (нині AMD) звернули увагу на технологію обчислень загального призначення на графічних процесорах, що зароджується, і почали розробку власних реалізацій, що забезпечують прямий і більш прозорий доступ до обчислювальних блоків 3D-прискорювачів.

В результаті компанія NVIDIA розробила програмно-апаратну архітектуру паралельних обчислень CUDA (Compute Unified Device Architecture). Архітектура CUDA дає змогу реалізувати неграфічні обчислення на графічних процесорах NVIDIA.

Реліз публічної бета-версії CUDA SDK відбувся у лютому 2007 року. В основі API CUDA лежить спрощений діалект мови Сі. Архітектура CUDA SDK забезпечує програмістам реалізацію алгоритмів, здійснених на графічних процесорах NVIDIA, та включення спеціальних функцій до тексту програми на Cі. Для успішної трансляції коду цією мовою до складу CUDA SDK входить власний Сикомпілятор командного рядка nvcc компанії NVIDIA.

CUDA - це кросплатформне програмне забезпечення для таких операційних систем, як Linux, Mac OS X та Windows.

Компанія AMD (ATI) також розробила свою версію технології GPGPU, яка раніше називалася ATI Stream, а тепер – AMD Accelerated Parallel Processing (APP). Основу AMD APP складає відкритий індустріальний стандарт OpenCL (Open Computing Language). Стандарт OpenCL забезпечує паралелізм на рівні інструкцій та на рівні даних та є реалізацією техніки GPGPU. Це повністю відкритий стандарт, його використання не обкладається ліцензійними відрахуваннями. Зазначимо, що AMD APP та NVIDIA CUDA несумісні один з одним, проте остання версія NVIDIA CUDA підтримує і OpenCL.

Тестування GPGPU у відеоконвертерах

Отже, з'ясували, що з реалізації GPGPU на графічних процесорах NVIDIA призначено технологія CUDA, але в графічних процесорах AMD - API APP. Як зазначалося, використання неграфічних обчислень на GPU доцільно лише тому випадку, якщо вирішуване завдання то, можливо розпаралелена на безліч потоків. Однак більшість додатків користувача не задовольняють цьому критерію. Втім, є деякі винятки. Наприклад, більшість сучасних відеоконвертерів підтримують можливість використання обчислень на графічних процесорах NVIDIA та AMD.

Для того, щоб з'ясувати, наскільки ефективно використовуються обчислення на GPU в відеоконвертерах, ми відібрали три популярні рішення: Xilisoft Video Converter Ultimate 7.7.2, Wondershare Video Converter Ultimate 6.0.3.2 і Movavi Video Converter 10.2.1. Ці конвертери підтримують можливість використання графічних процесорів NVIDIA та AMD, причому у налаштуваннях відеоконвертерів можна вимкнути цю можливість, що дозволяє оцінити ефективність застосування GPU.

Для відеоконвертування ми застосовували три різні відеоролики.

Перший відеоролик мав тривалість 3 хв 35 с та розмір 1,05 Гбайт. Він був записаний у форматі зберігання даних (контейнер) mkv і мав такі характеристики:

  • відео:
    • формат - MPEG4 Video (H264),
    • роздільна здатність - 1920*um*1080,
    • режим бітрейту - Variable,
    • середній відеобітрейт – 42,1 Мбіт/с,
    • максимальний відеобітрейт – 59,1 Мбіт/с,
    • частота кадрів – 25 fps;
  • аудіо:
    • формат - MPEG-1 Audio,
    • аудіобітрейт - 128 Кбіт/с,
    • кількість каналів - 2,

Другий відеоролик мав тривалість 4 хв 25 с та розмір 1,98 Гбайт. Він був записаний у форматі зберігання даних (контейнер) MPG і мав такі характеристики:

  • відео:
    • формат - MPEG-PS (MPEG2 Video),
    • роздільна здатність - 1920*um*1080,
    • режим бітрейту – Variable.
    • середній відеобітрейт – 62,5 Мбіт/с,
    • максимальний відеобітрейт – 100 Мбіт/с,
    • частота кадрів – 25 fps;
  • аудіо:
    • формат - MPEG-1 Audio,
    • аудіобітрейт - 384 Кбіт/с,
    • кількість каналів - 2,

Третій відеоролик мав тривалість 3 хв 47 с та розмір 197 Мбайт. Він був записаний у форматі зберігання даних (контейнер) MOV і мав такі характеристики:

  • відео:
    • формат - MPEG4 Video (H264),
    • роздільна здатність - 1920*um*1080,
    • режим бітрейту - Variable,
    • відеобітрейт - 7024 Кбіт/с,
    • частота кадрів – 25 fps;
  • аудіо:
    • формат - AAC,
    • аудіобітрейт - 256 Кбіт/с,
    • кількість каналів - 2,
    • частота семплювання – 48 кГц.

Усі три тестових відеоролики конвертувалися з використанням відеоконвертерів у формат зберігання даних MP4 (кодек H.264) для перегляду на планшеті iPad 2. Роздільна здатність вихідного відеофайлу становила 1280*um*720.

Зазначимо, що ми не почали використовувати абсолютно однакові налаштування конвертування у всіх трьох конвертерах. Саме тому за часом конвертування некоректно порівнювати ефективність відеоконвертерів. Так, у відеоконвертері Xilisoft Video Converter Ultimate 7.7.2 для конвертування застосовувався пресет iPad 2 – H.264 HD Video. У цьому пресеті використовуються такі параметри кодування:

  • кодек – MPEG4 (H.264);
  • роздільна здатність - 1280*um*720;
  • частота кадрів – 29,97 fps;
  • відеобітрейт – 5210 Кбіт/с;
  • аудіокодек – AAC;
  • аудіобітрейт – 128 Кбіт/с;
  • кількість каналів – 2;
  • частота семплювання – 48 кГц.

У відеоконвертері Wondershare Video Converter Ultimate 6.0.3.2 використовувався пресет iPad 2 з наступними додатковими налаштуваннями:

  • кодек – MPEG4 (H.264);
  • роздільна здатність - 1280*um*720;
  • частота кадрів – 30 fps;
  • відеобітрейт – 5000 Кбіт/с;
  • аудіокодек – AAC;
  • аудіобітрейт – 128 Кбіт/с;
  • кількість каналів – 2;
  • частота семплювання – 48 кГц.

У конвертері Movavi Video Converter 10.2.1 застосовувався пресет iPad (1280*um*720, H.264) (*.mp4) з такими додатковими налаштуваннями:

  • відеоформат – H.264;
  • роздільна здатність - 1280*um*720;
  • частота кадрів – 30 fps;
  • відеобітрейт – 2500 Кбіт/с;
  • аудіокодек – AAC;
  • аудіобітрейт – 128 Кбіт/с;
  • кількість каналів – 2;
  • частота семплювання – 44,1 кГц.

Конвертування кожного вихідного відеоролика проводилося по п'ять разів на кожному відеоконвертері, причому з використанням як графічного процесора, так і тільки CPU. Після кожного конвертування комп'ютер перезавантажується.

У підсумку кожен відеоролик конвертувався десять разів у кожному відеоконвертері. Для автоматизації цієї рутинної роботи було написано спеціальну утиліту з графічним інтерфейсом, що дозволяє повністю автоматизувати процес тестування.

Конфігурація стенду для тестування

Стенд для тестування мав таку конфігурацію:

  • процесор – Intel Core i7-3770K;
  • материнська плата – Gigabyte GA-Z77X-UD5H;
  • чіпсет системної плати – Intel Z77 Express;
  • пам'ять – DDR3-1600;
  • обсяг пам'яті – 8 Гбайт (два модулі GEIL по 4 Гбайт);
  • режим роботи пам'яті – двоканальний;
  • відеокарта – NVIDIA GeForce GTX 660Ti (відеодрайвер 314.07);
  • накопичувач – Intel SSD 520 (240 Гбайт).

На стенді встановлювалась операційна система Windows 7 Ultimate (64-bit).

Спочатку ми провели тестування в штатному режимі роботи процесора та решти всіх компонентів системи. При цьому процесор Intel Core i7-3770K працював на штатній частоті 3,5 ГГц із активованим режимом Turbo Boost (максимальна частота процесора в режимі Turbo Boost становить 3,9 ГГц).

Потім ми повторили тестування, але при розгоні процесора до фіксованої частоти 4,5 ГГц (без використання режиму Turbo Boost). Це дозволило виявити залежність швидкості конвертування частоти процесора (CPU).

На наступному етапі тестування ми повернулися до штатних налаштувань процесора та повторили тестування вже з іншими відеокартами:

  • NVIDIA GeForce GTX 280 (драйвер 314.07);
  • NVIDIA GeForce GTX 460 (драйвер 314.07);
  • AMD Radeon HD6850 (драйвер 13.1).

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

Старша відеокарта NVIDIA GeForce 660Ti заснована на однойменному графічному процесорі з кодовим позначенням GK104 (архітектура Kepler), що виробляється за 28-нм техпроцесом. Цей графічний процесор містить 3,54 млрд. транзисторів, а площа кристала становить 294 мм2.

Нагадаємо, що графічний процесор GK104 включає чотири кластери графічної обробки (Graphics Processing Clusters, GPC). Кластери GPC є незалежними пристроями у складі процесора і здатні працювати як окремі пристрої, оскільки мають всі необхідні ресурси: розтеризатори, геометричні двигуни і текстурні модулі.

Кожен такий кластер має два потокові мультипроцесори SMX (Streaming Multiprocessor), але в процесорі GK104 в одному з кластерів один мультипроцесор заблокований, тому є сім мультипроцесорів SMX.

Кожен потоковий мультипроцесор SMX містить 192 потокові обчислювальні ядра (ядра CUDA), тому в сукупності процесор GK104 налічує 1344 обчислювальних ядра CUDA. Крім того, кожен SMX-мультипроцесор містить 16 текстурних модулів (TMU), 32 блоки спеціальних функцій (Special Function Units, SFU), 32 блоки завантаження та зберігання (Load-Store Unit, LSU), двигун PolyMorph та багато іншого.

Відеокарта GeForce GTX 460 заснована на графічному процесорі з кодовим позначенням GF104 на базі архітектури Fermi. Цей процесор виробляється по 40-нм техпроцесу і містить близько 1,95 млрд. транзисторів.

Графічний процесор GF104 включає два кластери графічної обробки GPC. Кожен з них має чотири потокові мультипроцесори SM, але в процесорі GF104 в одному з кластерів один мультипроцесор заблокований, тому існує всього сім мультипроцесорів SM.

Кожен потоковий мультипроцесор SM містить 48 потокових обчислювальних ядра (CUDA), тому в сукупності процесор GK104 налічує 336 обчислювальних ядра CUDA. Крім того, кожен SM-мультипроцесор містить вісім текстурних модулів (TMU), вісім блоків спеціальних функцій (Special Function Units, SFU), 16 блоків завантаження та зберігання (Load-Store Unit, LSU), двигун PolyMorph та багато іншого.

Графічний процесор GeForce GTX 280 відноситься до другого покоління уніфікованої архітектури графічних процесорів NVIDIA і за своєю архітектурою сильно відрізняється від архітектури Fermi та Kepler.

Графічний процесор GeForce GTX 280 складається з кластерів обробки текстур (Texture Processing Clusters, TPC), які, хоч і схожі, але в той же час дуже відрізняються від кластерів графічної обробки GPC в архітектурах Fermi та Kepler. Усього таких кластерів у процесорі GeForce GTX 280 налічується десять. Кожен TPC-кластер включає три потокові мультипроцесори SM і вісім блоків текстурної вибірки та фільтрації (TMU). Кожен мультипроцесор складається із восьми потокових процесорів (SP). Мультипроцесори також містять блоки вибірки та фільтрації текстурних даних, що використовуються як у графічних, так і деяких розрахункових задачах.

Таким чином, в одному TPC-кластері - 24 потокові процесори, а в графічному процесорі GeForce GTX 280 їх вже 240.

Зведені характеристики використовуваних у тестуванні відеокарт на графічних процесорах NVIDIA представлені у таблиці.

У наведеній таблиці немає відеокарти AMD Radeon HD6850, що цілком природно, оскільки за технічними характеристиками важко порівнювати з відеокартами NVIDIA. А тому розглянемо її окремо.

Графічний процесор AMD Radeon HD6850, що має кодову назву Barts, виготовляється по 40-нм техпроцесу і містить 1,7 млрд транзисторів.

Архітектура процесора AMD Radeon HD6850 є уніфікованою архітектурою з масивом загальних процесорів для потокової обробки численних видів даних.

Процесор AMD Radeon HD6850 складається з 12 SIMD-ядер, кожне з яких містить по 16 блоків суперскалярних потокових процесорів та чотири текстурні блоки. Кожен суперскалярний потоковий процесор містить п'ять універсальних потокових процесорів. Таким чином, всього в графічному процесорі AMD Radeon HD6850 налічується 12*um*16*um*5=960 універсальних потокових процесорів.

Частота графічного процесора відеокарти AMD Radeon HD6850 становить 775 МГц, а ефективна частота пам'яті GDDR5 – 4000 МГц. У цьому обсяг пам'яті становить 1024 Мбайт.

Результати тестування

Отже, звернімося до результатів тестування. Почнемо з першого тесту, коли використовується відеокарта NVIDIA GeForce GTX 660Ti та штатний режим роботи процесора Intel Core i7-3770K.

На рис. 1-3 показані результати конвертування трьох тестових відеороликів трьома конвертерами в режимах із застосуванням графічного процесора та без.

Як видно за результатами тестування, ефект від використання графічного процесора є. Для відеоконвертера Xilisoft Video Converter Ultimate 7.7.2 у разі застосування графічного процесора час конвертування скорочується на 14, 9 та 19% для першого, другого та третього відеоролика відповідно.

Для відеоконвертера Wondershare Video Converter Ultimate 6.0.32 використання графічного процесора дозволяє скоротити час конвертування на 10, 13 та 23% для першого, другого та третього відеоролика відповідно.

Але найбільше від застосування графічного процесора виграє конвертер Movavi Video Converter 10.2.1. Для першого, другого та третього відеоролика скорочення часу конвертування становить 64, 81 та 41% відповідно.

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

Тепер подивимося, який буде виграш за часом конвертування при розгоні процесора Intel Core i7-3770K до 4,5 ГГц. Якщо вважати, що в штатному режимі всі ядра процесора при конвертуванні завантажені і в режимі Turbo Boost працюють на частоті 3,7 ГГц, збільшення частоти до 4,5 ГГц відповідає розгону по частоті на 22%.

На рис. 4-6 показані результати конвертування трьох тестових відеороликів при розгоні процесора в режимах з використанням графічного процесора та без. У разі застосування графічного процесора дозволяє отримати виграш за часом конвертування.

Для відеоконвертера Xilisoft Video Converter Ultimate 7.7.2 у разі застосування графічного процесора час конвертування скорочується на 15, 9 та 20% для першого, другого та третього відеоролика відповідно.

Для відеоконвертера Wondershare Video Converter Ultimate 6.0.32 використання графічного процесора дозволяє скоротити час конвертування на 10, 10 та 20% для першого, другого та третього відеоролика відповідно.

Для конвертера Movavi Video Converter 10.2.1 застосування графічного процесора дозволяє скоротити час конвертування на 59, 81 та 40% відповідно.

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

На рис. 7-9 представлені результати порівняння часу конвертування відео без використання графічного процесора в штатному режимі роботи процесора і в режимі розгону. Оскільки в цьому випадку конвертування проводиться лише засобами CPU без обчислень на GPU, очевидно, що збільшення тактової частоти роботи процесора призводить до скорочення часу конвертування (збільшення швидкості конвертування). Так само очевидно, що скорочення швидкості конвертування має бути приблизно однаковим для всіх тестових відеороликів. Так, для відеоконвертера Xilisoft Video Converter Ultimate 7.7.2 при розгоні процесора час конвертування скорочується на 9, 11 та 9% для першого, другого та третього відеоролика відповідно. Для відеоконвертера Wondershare Video Converter Ultimate 6.0.32 час конвертування скорочується на 9, 9 та 10% для першого, другого та третього відеоролика відповідно. Ну а для відеоконвертера Movavi Video Converter 10.2.1 час конвертування скорочується на 13, 12 та 12% відповідно.

Таким чином, при розгоні процесора частотою на 20% час конвертування скорочується приблизно на 10%.

Порівняємо час конвертування відеороликів з використанням графічного процесора у штатному режимі роботи процесора та режимі розгону (рис. 10-12).

Для відеоконвертера Xilisoft Video Converter Ultimate 7.7.2 при розгоні процесора час конвертування скорочується на 10, 10 та 9% для першого, другого та третього відеоролика відповідно. Для відеоконвертера Wondershare Video Converter Ultimate 6.0.32 час конвертування скорочується на 9, 6 та 5% для першого, другого та третього відеоролика відповідно. Ну а для відеоконвертера Movavi Video Converter 10.2.1 час конвертування скорочується на 0,2, 10 та 10% відповідно.

Як бачимо, для конвертерів Xilisoft Video Converter Ultimate 7.7.2 та Wondershare Video Converter Ultimate 6.0.32 скорочення часу конвертування при розгоні процесора приблизно однаково як при використанні графічного процесора, так і без його застосування, що логічно, оскільки ці конвертери не дуже ефективно використовують обчислення на GPU. А ось для конвертера Movavi Video Converter 10.2.1, який ефективно використовує обчислення на GPU, розгін процесора в режимі використання обчислень на GPU мало позначається на скороченні часу конвертування, що також зрозуміло, оскільки в цьому випадку основне навантаження лягає на графічний процесор.

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

Здавалося б, чим потужніша відеокарта і чим більше в графічному процесорі ядер CUDA (або універсальних потокових процесорів для відеокарт AMD), тим ефективнішим має бути відеоконвертування у разі застосування графічного процесора. Але на практиці виходить не зовсім так.

Що стосується відеокарт на графічних процесорах NVIDIA, ситуація наступна. При використанні конвертерів Xilisoft Video Converter Ultimate 7.7.2 та Wondershare Video Converter Ultimate 6.0.32 час конвертування практично не залежить від типу використовуваної відеокарти. Тобто для відеокарт NVIDIA GeForce GTX 660Ti, NVIDIA GeForce GTX 460 та NVIDIA GeForce GTX 280 в режимі використання обчислень на GPU час конвертування виходить те саме (рис. 13-15).

Рис. 1. Результати конвертування першого
тестового відеоролика у штатному режимі
роботи процесора

процесора відеокарт в режимі використання графічного процесора

Рис. 14. Результати порівняння часу конвертування другого відеоролика

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

Пояснити це можна лише тим, що алгоритм обчислень на графічному процесорі, реалізований у конвертерах Xilisoft Video Converter Ultimate 7.7.2 та Wondershare Video Converter Ultimate 6.0.32, просто неефективний і не дозволяє активно використовувати всі графічні ядра. До речі, саме цим пояснюється і той факт, що для цих конвертерів різниця в часі конвертування в режимах використання GPU і без використання невелика.

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

А ось з відеокартою AMD Radeon HD 6850 все як завжди. Чи то драйвер відеокарти «кривий», чи то алгоритми, реалізовані в конвертерах, потребують серйозного доопрацювання, але у разі застосування обчислень на GPU результати або не покращуються, або погіршуються.

Якщо говорити конкретніше, ситуація наступна. Для конвертера Xilisoft Video Converter Ultimate 7.7.2 під час використання графічного процесора для конвертування першого тестового відеоролика час конвертування збільшується на 43%, при конвертуванні другого ролика - на 66%.

Причому конвертер Xilisoft Video Converter Ultimate 7.7.2 характеризується ще й нестабільністю результатів. Розкид часу конвертування може досягати 40%! Саме тому ми повторювали всі тести десять разів і розраховували середній результат.

А ось для конвертерів Wondershare Video Converter Ultimate 6.0.32 та Movavi Video Converter 10.2.1 під час використання графічного процесора для конвертування всіх трьох відеороликів час конвертування не змінюється взагалі! Конвертери Wondershare Video Converter Ultimate 6.0.32 і Movavi Video Converter 10.2.1 або не використовують технологію AMD APP при конвертуванні, або відеодрайвер AMD просто «кривий», в результаті чого технологія AMD APP не працює.

Висновки

З проведеного тестування можна зробити такі важливі висновки. У сучасних відеоконвертерах справді може застосовуватися технологія обчислень на GPU, що дозволяє підвищити швидкість конвертування. Однак це зовсім не означає, що всі обчислення повністю переносяться на GPU та CPU залишається незадіяним. Як показує тестування, під час використання технології GPGPU центральний процесор залишається завантаженим, отже, застосування потужних, багатоядерних центральних процесорів у системах, що використовуються конвертування відео, залишається актуальним. Винятком цього правила є технологія AMD APP на графічних процесорах AMD. Наприклад, при використанні конвертера Xilisoft Video Converter Ultimate 7.7.2 з активованою технологією AMD APP навантаження на CPU дійсно знижується, але це призводить до того, що час конвертування не скорочується, а навпаки збільшується.

Загалом, якщо говорити про конвертування відео з додатковим використанням графічного процесора, то для вирішення цього завдання доцільно застосовувати відеокарти з графічними процесорами NVIDIA. Як показує практика, тільки в цьому випадку можна досягти збільшення швидкості конвертування. Причому слід пам'ятати, що реальний приріст у швидкості конвертування залежить від багатьох чинників. Це вхідний та вихідний формати відео, і, звичайно ж, сам відеоконвертер. Конвертери Xilisoft Video Converter Ultimate 7.7.2 та Wondershare Video Converter Ultimate 6.0.32 для цього завдання підходять погано, а ось конвертер та Movavi Video Converter 10.2.1 здатний дуже ефективно використовувати можливості NVIDIA GPU.

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

Яка програма потрібна для майнінгу криптовалюти? Що враховувати при виборі обладнання для майнінгу? Як майнути біткоїни та ефіріум за допомогою відеокарти на комп'ютері?

Виявляється, потужні відеокарти потрібні не лише фанатам видовищних ігор. Тисячі користувачів по всьому світу використовують графічні адаптери для заробітку криптовалюти! З кількох карт з потужними процесорами майнеристворюють ферми- Обчислювальні центри, які видобувають цифрові гроші практично з повітря!

З вами Денис Кудерін – експерт журналу «ХітерБобер» з питань фінансів та їхнього грамотного множення. Я розповім, що собою представляє майнінг на відеокартіу 17-18 роках, як правильно вибрати пристрій для заробітку криптовалюти, і чому видобувати біткоїни на відеокартах вже не вигідно.

Ви дізнаєтеся також, де купити саму продуктивну та потужну відеокартудля професійного майнінгу, та отримайте експертні поради щодо підвищення ефективності своєї майнінг-ферми.

1. Майнінг на відеокарті – легкі гроші чи невиправдані витрати

Хороша відеокарта – не просто адаптер цифрових сигналів, а й потужний процесор, здатний вирішувати найскладніші обчислювальні завдання. І в тому числі – обчислювати хеш-код для ланцюжка блоків (блокчейна). Це робить графічні плати ідеальним інструментом для майнінгу- Видобування криптовалюти.

Запитання:Чому саме процесор відеокарти? Адже у будь-якому комп'ютері є центральний процесор? Хіба не логічно проводити обчислення за його допомогою?

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

Для тих, хто не має уявлення про те, як видобуваються цифрові гроші, невеликий лікнеп. Майнінг - основний, а іноді й єдиний спосіб виробництва криптовалюти.

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

Крім обчислень коду, майнінг виконує ще кілька найважливіших завдань:

  • підтримка децентралізації системи:відсутність прихильності до серверів - основа блокчейна;
  • підтвердження транзакцій– без майнінгу операції не зможуть увійти до нового блоку;
  • формування нових блоків системи– і занесення їх у єдиний всім комп'ютерів реєстр.

Відразу хочу охолодити запал початківців: процес майнінгу з кожним роком стає все важче. Наприклад, за допомогою відеокарти вже давно нерентабельний.

Битки за допомогою GPU добувають зараз лише уперті любителі, оскільки на зміну відеокартам прийшли спеціалізовані процесори ASIC. Ці чіпи споживають менше електроенергії і більш ефективні щодо обчислень. Всім хороші, але стоять порядку 130-150 тисяч рублів .

Потужна модель Antminer S9

На щастя для майнерів, біткоін – не єдина на планеті криптовалюта, а одна із сотень. Інші цифрові гроші – ефіріуми, Zcash, Expanse, догкоїниі т.д. як і раніше, вигідно видобувати за допомогою відеокарт. Винагорода стабільна, а обладнання окупається приблизно через 6-12 місяців.

Але є ще одна проблема – дефіцит потужних відеокарт. Ажіотаж навколо криптовалюти призвів до подорожчання цих пристроїв. Купити нову, придатну для майнінгу, відеокарту в Росії не так просто.

Майнерам-початківцям доводиться замовляти відеоадаптери в інтернет-магазинах (у тому числі закордонних) або купувати вживаний товар. Останнє, до речі, робити не раджу: обладнання для майнінгу застаріває та зношується з фантастичною швидкістю.

На Авіті навіть продають цілі ферми для видобутку криптовалюти.

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

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

Інша річ, що гравців на цьому полі стає дедалі більше. Причому сумарна кількість цифрових монет від цього не зростає. Навпаки, нагорода стає меншою.

Так, шість років тому нагорода за один блокчейн мережі біткоїн дорівнювала 50 монет, зараз це лише 12,5 БТК. Складність обчислень при цьому збільшилась у 10 тисяч разів. Щоправда, і вартість самого біткоїну зросла за цей час багаторазово.

2. Як майнути криптовалюту за допомогою відеокарти – покрокова інструкція

Є два варіанти майнінгу – сольний та у складі пулу. Поодиноким видобутком займатися складно – потрібно мати величезну кількість хешрейту(одиниць потужності), щоб розпочаті обчислення мали ймовірність успішного закриття.

99% усіх майнерів працює у пулах(англ. pool – басейн) – спільнотах, зайнятих розподілом обчислювальних завдань. Спільний майнінг нівелює фактор випадковості та гарантує стабільний прибуток.

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

Такі старателі схожі на золотошукачів 19 століття. Можна шукати роками свій самородок (у нашому випадку – біткоїн) і так і не знайти. Тобто блокчейн так і не буде закритий, а отже, жодної нагороди ви не отримаєте.

Трохи більше шансів у «самотніх мисливців» за ефірами та деякими іншими крипто-монетами.

Через своєрідний алгоритм шифрування ETH не видобувають за допомогою спеціальних процесорів (їх ще не придумали). Використовують для цього лише відеокарти. За рахунок ефірів та інших альткоїнів ще тримаються численні фермери сучасності.

Однією відеокарти для створення повноцінної ферми буде недостатньо: 4 штуки – «прожитковий мінімум» для майнера, що розраховує на стабільний прибуток. Не менш важлива потужна система охолодження відеоадаптерів. І не упускайте з уваги і таку статтю витрат, як плата за електроенергію.

Покрокова інструкція убезпечить від помилок та прискорить налаштування процесу.

Крок 1. Вибираємо пул

Найбільші у світі криптовалютні пули дислокуються на території КНР, а також в Ісландії та США. Формально ці спільноти не мають державної власності, але російськомовні сайти пулів – рідкість в інтернеті.

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

Вибираємо пул за такими критеріями:

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

На ринку криптовалют зміни відбуваються щодня. Це стосується і стрибків курсу, і появи нових цифрових грошей. форківбіткоїну. Трапляються і глобальні зміни.

Так, нещодавно стало відомо, що ефір у найближчому майбутньому переходить на іншу систему розподілу прибутку. У двох словах – дохід у мережі Etherium матимуть майнери, у яких є «багато кеце», тобто монет, а добувачам-початківцям залишиться або прикрити лавочку, або переключитися на інші гроші.

Але такі «дрібниці» ентузіастів ніколи не зупиняли. Тим більше, є програма під назвою Profitable Pool. Вона автоматично відстежує найвигідніші для видобутку альткоїни на даний момент. Є й сервіс пошуку самих пулів, а також їх рейтинги в реальному часі.

Крок 2. Встановлюємо та налаштовуємо програму

Зареєструвавшись на сайті пула, потрібно завантажити спеціальну програму-майнер – не обчислювати код вручну за допомогою калькулятора. Таких програм також достатньо. Для біткоїну це – 50 minerабо CGMiner, для ефіру Ethminer.

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

Крок 3. Реєструємо гаманець

Якщо у вас ще немає біткоїн-гаманця або ефіріум-сховища, потрібно їх обов'язково зареєструвати. Гаманці завантажуємо з офіційних сайтів.

Іноді допомогу у цій справі надають самі пули, але з безоплатно.

Крок 4. Запускаємо майнінг та стежимо за статистикою

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

Крок 5. Виводимо криптовалюту

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

Як переводити цифрову валюту у фіатну?Питання, гідне окремої статті. Якщо коротко, то найшвидший спосіб – обмінні пункти. Вони беруть собі відсотки за послуги, і ваше завдання знайти найвигідніший курс з мінімальною комісією. Зробити це допоможе професійний сервіс порівняння обмінників.

– найкращий у Рунеті ресурс такого плану. Цей моніторинг порівнює показники більше 300 обмінних пунктів і знаходить кращі котирування за валютними парами, що вас цікавлять. Понад те, сервіс показує резерви криптовалюти в касі. У списках моніторингу – лише перевірені та надійні обмінні сервіси.

3. На що звертати увагу при виборі відеокарти для майнінгу

Вибирати відеокарту потрібно з розумом. Перша, що попалася, або та, яка вже стоїть на вашому комп'ютері, теж майне, але цієї потужності навіть для ефірів буде дуже мало.

Основні показники такі: продуктивність (потужність), енергоспоживання, охолодження, перспективи розгону.

1) Потужність

Тут все просто – що вища продуктивність процесора, краще для обчислення хеш-коду. Відмінні показники забезпечують карти з об'ємом пам'яті більше ніж 2 ГБ. І вибирайте пристрої із 256-розрядною шиною. 128-розрядні для цієї справи не годяться.

2) Енергоспоживання

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

3) Охолодження

Стандартна складається із 4-16 карт. Вона виробляє надмірну кількість тепла, згубне заліза і небажане самого фермера. В однокімнатній квартирі без кондиціонера житиме і працюватиме, м'яко кажучи, некомфортно.

Якісне охолодження процесора - неодмінна умова успішного майнінгу

Тому при виборі двох карток з однаковою продуктивністю віддавайте перевагу тій, у якої менше показник теплової потужності (TDP) . Найкращі параметри охолодження показують карти Radeon. Ці ж пристрої найдовше інших карт працюють в активному режимі без зносу.

Додаткові кулери не лише відведуть зайве тепло від процесорів, а й продовжать термін їхнього життя.

4) Можливість розгону

Розгін - примусове підвищення робочих показників відеокарти. Можливість "розігнати карту" залежить від двох параметрів - частоти графічного процесора та частоти відеопам'яті. Саме їх ви і розганятимете, якщо захочете підвищити обчислювальні потужності.

Які відеокарти купувати?Вам знадобляться пристрої останнього покоління або щонайменше графічні прискорювачі, випущені не раніше 2-3 років тому. Майнери використовують карти AMD Radeon, Nvidia, Geforce GTX.

Погляньте на таблицю окупності відеокарт (дані актуальні на кінець 2017 року):

4. Де купити відеокарту для майнінгу – огляд ТОП-3 магазинів

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

Вам допоможе наш огляд найкращих точок онлайн-продажів.

1) TopComputer

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

На момент написання статті у продажу є карти AMD, Nvidia(8 Gb) та інші різновиди, що підходять для майнінгу.

2) Мybitcoinshop

Спеціалізований магазин, торгуючи виключно товарами для майнінгу. Тут ви знайдете все для будівництва домашньої ферми - відеокарти необхідної конфігурації, блоки живлення, перехідники і навіть ASIC-майнери (для майнерів нового покоління). Є платна доставка та самовивіз зі складу у Москві.

Компанія неодноразово отримувала неофіційне звання найкращого в РФ магазину для майнерів. Оперативний сервіс, доброзичливе ставлення до клієнтів, передове обладнання – основні складові успіху.

3) Ship Shop America

Купівля та доставка товарів зі США. Посередницька компанія для тих, кому потрібні справді ексклюзивні та передові товари для майнінгу.

Прямий партнер провідного виробника відеокарт для ігор та майнінгу – Nvidia. Максимальний термін очікування товару – 14 днів.

5. Як збільшити дохід від майнінгу на відеокарті – 3 корисні поради

Нетерплячі читачі, які бажають розпочати майнінг прямо зараз і отримувати доходи вже з завтрашнього ранку, неодмінно запитають - скільки заробляють майнери?

Заробітки залежать від обладнання, курсу криптовалюти, ефективності пулу, потужності ферми, кількості хешрейту та купи інших факторів. Одним вдається отримувати щомісяця до 70 000 у рублях , інші задовольняються 10 доларамив тиждень. Це нестабільний та непередбачуваний бізнес.

Корисні поради допоможуть підвищити доходи та оптимізувати витрати.

Майнете валюту, що стрімко зростає в ціні, заробите більше. Для прикладу - ефір зараз стоїть близько 300 доларів, Біткоін - більше 6000 . Але треба враховувати не тільки поточну вартість, а й темпи зростання за тиждень.

Порада 2. Використовуйте калькулятор майнінгу для вибору оптимального обладнання

Калькулятор майнінгу на сайті пула або на іншому спеціалізованому сервісі допоможе вибрати оптимальну програму та навіть відеокарту для майнінгу.

© 2022 androidas.ru - Все про Android