OpenCL

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до: навігація, пошук
OpenCL
логотип OpenCL
Автор(и) Apple Inc.
Розробник(и) Khronos Group
Стабільний випуск 2.0 (22 липня 2013; 709 днів тому)
Операційна система крос-платформовий
Тип GPGPU, API
Ліцензія безоплатна
Сайт www.khronos.org/opencl

OpenCL (від англ. Open Computing Language) — фреймворк для створення комп'ютерних програм, пов'язаних з паралельними обчисленнями на різних графічних (англ. GPU) і центральних процесорах (англ. CPU). У фреймворк OpenCL входять мова програмування, яка базується на стандарті C99, та інтерфейс програмування комп'ютерних програм (англ. API). OpenCL забезпечує паралельність на рівні інструкцій та на рівні даних і є реалізацією техніки GPGPU. OpenCL — повністю відкритий стандарт, його використання доступне на базі вільних ліцензій.

Мета OpenCL полягає в тому, щоб доповнити OpenGL і OpenAL, які є відкритими галузевими стандартами для тривимірної комп'ютерної графіки і звуку, користуючись можливостями GPU. OpenCL розроблявся і підтримується некомерційним консорціумом Khronos Group, в який входять багато великих компаній, включаючи Apple, AMD, ARM, Intel, nVidia, Qualcomm, Sun Microsystems, Sony Computer Entertainment та інші.

Історія[ред.ред. код]

OpenCL був розроблений у компанії Apple Inc. Apple внесла пропозицію по розробці специфікації у комітет Khronos Group. 16 червня 2008 року, Khronos Compute Working Group була сформована з представниками компаній котрі займаються розробкую: CPU, GPU та програмного забезпечення.

OpenCL 1.0[ред.ред. код]

Був представлений разом з Mac OS X Snow Leopard 8 червня 2009 року.

OpenCL 1.1[ред.ред. код]

Був представлений 14 червня 2010 року

OpenCL 1.2[ред.ред. код]

Був представлений 15 листопада 2011 року

OpenCL 2.0[ред.ред. код]

Був представлений 22 липня 2013 року[1] та стандартизований 18 листопада 2013 року[2].


OpenCL. Що це таке і навіщо він потрібен? (якщо є CUDA)[ред.ред. код]

AMD (як прихильник відкритих стандартів - закритий PhysX vs. відкритий Havoc; дорогою Intel Thread Profiler vs. безкоштовний AMD CodeAnalyst) робила великі ставки на нову технологію, враховуючи що AMD Stream зовсім не вдавалося змагатися в популярності з NVidia CUDA - виною тому відставання Stream від CUDA в технічному плані. Влітку 2009 року компанія AMD зробила заяву про підтримку і відповідно стандарту OpenCL в новій версії Stream SDK. Насправді ж виявилося, що підтримка була реалізована тільки для CPU. Так, саме так, це нічому не суперечить - OpenCL стандарт для гетерогенних систем і нічого не заважає Вам запустити kernel на CPU, більше того - це дуже зручно у випадку якщо в системі немає іншого OpenCL пристрою. У такому випадку програма буде продовжувати працювати, тільки повільніше. Або ж ви можете задіяти всі обчислювальні потужності, які є в комп'ютері - як GPU так і CPU, хоча на практиці це не має особливого сенсу, оскільки час виконання kernel'ів, які виконуються на CPU буде набагато більше тих що виконуються на GPU - швидкість процесора стане вузьким місцем. Зате для налагодження додатків це більше ніж зручно. Підтримка OpenCL для графічних адаптерів AMD так само не змусила себе довго чекати - за останніми повідомленнями компанії версія для графічних чіпів зараз знаходиться на стадії підтвердження відповідності специфікаціям стандарту. Після чого вона стане доступна всім бажаючим. Так як OpenCL повинен працювати поверх деякої специфічної для заліза оболонки, а значить для того щоб можна цей стандарт дійсно став єдиним для різних гетерогенних систем - треба щоб відповідні оболонки (драйвери) були випущені і для IBM Cell і для Intel Larrabie. Поки від цих гігантів IT нічого не чути, таким чином OpenCL залишається ще одним засобом розробки для GPU на ряду з CUDA, Stream і DirectX Compute. Apple також заявляє про підтримку OpenCL, яка, втім, забезпечується за рахунок NVidia CUDA. Також в даний час сторонніми розробниками пропонується: OpenTK - бібліотека-обгортка над OpenGL, OpenAL і OpenCL для .Net. PyOpenCL - обгортка над OpenCL для Pyton. Java обгортка для OpenCL. Технологія OpenCL представляє інтерес для різних компаніЙ IT сфери - від розробників ігор до виробників чіпів, а це означає що у неї великі шанси стати фактичним стандартом для розробки високопродуктивних обчислень, відібравши цей титул у чільної в цьому секторі CUDA.

Деталі роботи технології[ред.ред. код]

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

Тому OpenCL виходить з найбільш загальних передумов, що дають уявлення про пристрій з підтримкою OpenCL: так як цей пристрій передбачається використовувати для обчислень - в ньому є якийсь «процесор» в загальному розумінні цього слова. Щось, що може виконувати команди. Так як OpenCL створений для паралельних обчислень, то такий процесор може, мати кошти паралелізму всередині себе (наприклад, кілька ядер одного CPU , кілька SPE процесорів в Cell). Також елементарним способом нарощування продуктивності паралельних обчислень є установка декількох таких процесорів на пристрої (наприклад, багатопроцесорні материнські плати PC ітд.). І природно в гетерогенній системі може бути декілька таких OpenCL-пристроїв (взагалі кажучи, з різною архітектурою).

Крім обчислювальних ресурсів пристрій має якийсь обсяг пам'яті. Причому ніяких вимог до цієї пам'яті не пред'являється, вона може бути як на пристрої, так і взагалі бути розмічена на ОЗУ хоста (як наприклад, це зроблено у вбудованих відеокарт).

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

OpenCL надає програмісту низькорівневий API, через який він взаємодіє з ресурсами пристрою. OpenCL API може або безпосередньо підтримуватися пристроєм, або працювати через проміжний API (як у випадку NVidia: OpenCL працює поверх CUDA Driver API, підтримуваний пристроями), це залежить від конкретної реалізації не описується стандартом.

4-х рівнева ієрархія OpenCL[ред.ред. код]

Для опису основних ідей OpenCL скористаємося ієрархією з 4х моделей:

Модель платформи (Platform Model);

Модель пам'яті (Memory Model);

Модель виконання (Execution Model);

Програмна модель (Programming Model);


Модель платформи (Platform Model).

Платформа OpenCL складається з хоста з'єднаного з пристроями, що підтримують OpenCL. Кожне OpenCL-пристрій складається з обчислювальних блоків (Compute Unit), які далі поділяються на один або більше елементи-обробники (Processing Elements, далі PE).

OpenCL-додаток виповнюється на хості відповідно до нативними моделями його платформи. OpenCL-додаток відправляє з хоста команди пристроям на виконання обчислень на PE. PE в рамках обчислювального блоку виконують один потік команд як SIMD блоки (одна інструкція виконується всіма одночасно, обробка наступної інструкції не почнеться, поки всі PE не завершать виконання поточної інструкції), або як SPMD блоки (у кожного PE власний лічильник інструкцій (program counter) ).

Модель виконання (Execution Model).

Виконання покрівельних OpenCL-програми складається з двох частин: хостової частина програми і kernels (ядра; з Вашого дозволу я далі буду вживати англійський термін, як більш звичний більшості з нас) виконуються на OpenCL-пристрої. Хостової частина програми визначає контекст, в якому виконуються kernel'и, і управляє їх виконанням.

Основна частина моделі виконання OpenCL описує виконання kernel'ов. Коли kernel ставиться в чергу на виконання, визначається простір індексів (NDRange, визначення буде дано нижче). Копія (instanse) kernel'а виконаються для кожного індексу з цього простору. Копія kernel'а виконується для конкретного індексу називається «Work-Item» (робочою одиницею) і визначається точкою в просторі індексів, тобто кожної «одиниці» надається глобальний ID. Кожен Work-Item виконує один і той же код, але конкретний шлях виконання (розгалуження ітп.) І дані, з якими він працює, можуть бути різними.

Work-Item'и організовуються в групи (Work-Groups). Групи надають більш велике розбиття в просторі індексів. Кожній групі приписується груповий ID з такою ж розмірністю, яка використовувалася для адресації окремих елементів. Кожному елементу зіставляється унікальний, в рамках групи, локальний ID. Таким чином, Work-Item'и можуть бути адресовані як по глобальному ID, так і по комбінації групового і локального ID.

Work-Item'и в групі виконуються конкурентно (паралельно) на PE одного обчислювального блоку.

У OpenCL kernel може бути двох категорій: OpenCL kernel: написані на OpenCL C і компілюється компілятором OpenCL. Всі реалізації OpenCL повинні підтримувати OpenCl-kernel. Реалізації можуть надавати інші механізми створення OpenCL-kernel. Naitive kernel: доступ до них здійснюється через хостової покажчики на функцію. Нативні kernel ставиться в чергу на виконання, так само як і OpenCL-kernel і використовує ті ж об'єкти пам'яті, що і OpenCL-kernel. Приміром, такі kernel'и можуть бути функціями, визначеними в коді програми або експортованими з бібліотеки. Відзначимо, що можливість виконувати нативні kernel'и є опціональною і їх семантика не визначається стандартом. API OpenCL включає функції для опитування можливостей пристрою на предмет підтримки таких kernel'ов.

Модель пам'яті (Memory Model).

Work-Item, виконуючий kernel може використовувати чотири різних типи пам'яті: -Глобальна пам'ять. Ця пам'ять надає доступ на читання і запис елементам всіх груп. Кожен Work-Item може писати і читати з будь-якої частини об'єкта пам'яті. Запис і читання глобальної пам'яті може кешуватися в залежності від можливостей пристрою. -Константна пам'ять. Область глобальної пам'яті, яка залишається постійною під час виконання kernel'а. Хост аллоцірует і ініціалізує об'єкти пам'яті, розташовані в константної пам'яті. -Локальна пам'ять. Область пам'яті, локальна для групи. Ця область пам'яті може використовуватися, щоб створювати змінні, що розділяються всією групою. Вона може бути реалізована як окрема пам'ять на OpenCL-пристрої. Альтернативно ця пам'ять може бути розмічена як область в глобальній пам'яті. -Приватна (private) пам'ять. Область пам'яті, що належить Work-Item. Змінні, визначені у приватній пам'яті одного Work-Item'а, що не видно іншим.

Програмна модель. (Programming Model)

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

Програмна модель з паралелізмом даних.

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

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

Програмна модель з паралелізмом завдань.

У цій моделі кожна копія kernel'а виповнюється незалежно від будь-якого простору індексів. Логічно це еквівалентно виконанню kernel'а на обчислювальному блоці (CU) з групою, що складається з одного елемента. У такій моделі користувачі висловлюють паралелізм наступними способами: використовують векторні типи даних, реалізовані в пристрої; встановлюють в чергу безліч завдань; встановлюють в чергу нативні kernel'и, що використовують програмну модель, ортогональную до OpenCL;

З чого складається платформа OpenCL[ред.ред. код]

Платформа OpenCL дозволяє додаткам використовувати хост і одне або декілька OpenCL-пристроїв як одну гетерогенную паралельну комп'ютерну систему. Платформа складається з наступних компонент: OpenCL Platform Layer: дозволяє хосту виявляти OpenCL-пристрої, опитувати їх властивості та створювати контекст. OpenCL Runtime: середовище виконання дозволяє програмі на хості управляти контекстами після того як вони були створені. Компілятор OpenCL: компілятор OpenCL створює виконувані файли, що містять OpenCL-kernel. Мова програмування OpenCL-C реалізується компілятором, який підтримує підмножина стандарту мови ISO C99 з розширеннями для паралелізму.

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

  • Створюємо контекст для виконання нашої програми на пристрої.
  • Вибираємо необхідний пристрій (можна відразу вибрати пристрій з найбільшою кількістю Flops).
  • Ініціалізіруем вибраний пристрій створеним нами контекстом.
  • Створюємо чергу команд на основі ID пристрою і контексту.
  • Створюємо програму на основі вихідних кодів і контексту,
  • або на основі бінарних файлів і контексту.
  • Збираємо програму (build).
  • Створюємо kernel.
  • Створюємо об'єкти пам'яті для вхідних і вихідних даних.
  • Ставимо в чергу команду запису даних з області пам'яті з даними на хості в пам'ять пристрою.
  • Ставимо в чергу команду виконання створеного нами kernel.
  • Ставимо в чергу команду зчитування даних з пристрою.
  • Чекаємо завершення операцій.

OpenCL код[ред.ред. код]

Створення OpenCL коду, який потрібно виконувати за допомогою OpenCL C99 мови; Хост Код:

Створення своєї програми (з використанням C #, наприклад); Створення даних, які ви хочете обробити; Використання API OpenCL для передачі даних на прискорювачі; Використання API OpenCL для операцій обчислення-виконання; Заключна генерація всіх необхідних даних.

Семпли коду:

/Starts using OpenCLTemplate to set up OpenCL

       using OpenCLTemplate; 
       private void Test_Click(object sender, EventArgs e)
       {
           //Initializes devices and sets up everything
           CLCalc.InitCL();
           //Creates variables that will be passed to OpenCL
           float[] x = new float[] { 1, 2, 3, 0.123f };
           float[] y = new float[] { 1, 2, 1, 1 };
           //This is the OpenCL source code. A string! It will not be compiled
           //by your compiler. It will be compiled by the OpenCL compiler.
           string s = @"
                      kernel void
                      sum (global float4 * x, global float4 * y)
                      {
                          x[0] = x[0] + y[0];
                      }";
           //Use the API to compile the program
           CLCalc.Program.Compile(new string[] { s });
           //Gets a handle to the OpenCL function we will call
           CLCalc.Program.Kernel sum = new CLCalc.Program.Kernel("sum");
           
           //Copies variables x and y to the OpenCL device memory
           CLCalc.Program.Variable varx=new CLCalc.Program.Variable(x);
           CLCalc.Program.Variable vary=new CLCalc.Program.Variable(y);
           //Tells OpenCL that the arguments of the "sum" program are x and y
           CLCalc.Program.Variable[] args = { varx, vary };
           //This is the number of work_items. We will discuss later.
           int[] max = new int[] { 1 };
           //Use the OpenCL API to execute the sum code with the 
           //arguments and work_items we specified
           sum.Execute(args, max);
           //Reads the x variable from video memory and stores it in x.
           varx.ReadFromDeviceTo(x);
       }


Так в чому ж підступ? Чому движок OpenCL так корисний для обчислень? Тому що він може зробити обробку паралельно-багатопотокової. Розглянемо це на прикладі підсумовування двох n-мірних векторів _kernel void

           floatVectorSum(__global       float * v1,
                          __global       float * v2)
                           {
                               // Vector element index
                               int i = get_global_id(0);
                               v1[i] = v1[i] + v2[i];
                           }

Використовуючи OpenCL ми можемо розбивати невелику частину завдання на безліч потоків, які обробляються прискорювачами паралельно, а без OpenCL завдання виконується повністю послідовно в один потік. Але слід мати на увазі, що використання OpenCL можливо тільки тому, що всі значення вектора v3 [i] залежать тільки від значень векторів v1 і v2.

Мова[ред.ред. код]

Мова OpenCL виділяється тим, що дозволяє програмам динамічно визначати, які процесори доступні, включаючи багатоядерні центральні процесори і графічні процесори. Це дозволяє розробникам динамічно масштабувати продуктивність своїх програм в залежності від доступного апаратного забезпечення клієнтів.[3]

Мова OpenCL котра використовується для написання ядра (Kernel), частини що буде розпаралелюватися, має особливості:

  • Відсутня підтримка вказівників на функції, рекурсії, бітових полів, масивів змінної довжини, стандартних заголовних файлів.
  • Розширення мови для паралелізму: векторні типи, синхронізація, функції для Work-items/Work-Groups.
  • Модифікатори доступу: __global, __local, __constant, __private.


Див. також[ред.ред. код]

Примітки[ред.ред. код]

Посилання[ред.ред. код]