THE BELL

Є ті, хто прочитали цю новину раніше вас.
Підпишіться, щоб отримувати статті свіжими.
Email
ім'я
Прізвище
Як ви хочете читати The Bell
без спаму

saul 9 вересня 2015 о 13:38

Реалізація багатопотокової архітектури ігрового движка

  • Прес-центр компанії Intel,
  • Розробка ігор,
  • Паралельне програмування,
  • Розробка веб-сайтів
  • Переклад

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

1. Введення

1.1. огляд

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

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

2. Стан паралельного виконання

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

2.1 Стани виконання

Щоб менеджер станів виконання працював ефективно, рекомендується синхронізувати операції за певним тактовому імпульсу. Це дозволяє всім системам працювати одночасно. При цьому частота тактів не обов'язково повинна відповідати частоті передачі кадрів. Та й тривалість тактів може надаватися незалежно від частоти. Її можна вибрати таким чином, щоб один такт відповідав часу, необхідного на передачу одного кадру (незалежно від його розміру). Іншими словами, частоту або тривалість тактів визначає конкретна реалізація менеджера станів. На малюнку 1 показаний «вільний» покроковий режимроботи, в якому не потрібно, щоб всі системи завершували виконання операції за один і той же такт. Режим, при якому всі системи завершують виконання операцій за один такт, називається «жорстким» покроковим режимом. Він схематично зображено на малюнку 2.


Малюнок 1. Стан виконання у вільному покроковому режимі

2.1.1. Вільний покроковий режим
У вільному покроковому режимі всі системи працюють безперервно протягом заздалегідь заданого проміжку часу, необхідного для завершення чергової порції обчислень. Однак назва «вільний» не слід розуміти буквально: системи синхронізуються не в довільний момент часу, вони лише «вільні» у виборі числа тактів, необхідного на виконання чергового етапу.
Як правило, в цьому режимі недостатньо відправити менеджеру станів просте повідомлення про зміну стану. Необхідно також передати оновлені дані. Це викликано тим, що система, яка змінила загальні дані, може перебувати в стані виконання, в той час як інша система, яка очікує ці дані, уже готова виконати оновлення. В цьому випадку потрібно більше пам'яті, так як потрібно створювати більше копій даних. Тому «вільний» режим не можна вважати універсальним рішенням на всі випадки життя.
2.1.2. Жорсткий крок за кроком режим
В цьому режимі виконання завдань всіх систем завершується за один такт. Такий механізм простіше в реалізації і не вимагає передачі оновлених даних разом з повідомленням. Дійсно, при необхідності одна система може просто запитати нові значення в іншої системи (зрозуміло, в кінці циклу виконання).
У жорсткому режимі можна реалізувати псевдосвободний покроковий режим роботи, розподіляючи обчислення між різними кроками. Зокрема, це може знадобитися для розрахунків ІІ, де за перший такт обчислюється початкова «загальна мета», яка поступово уточнюється на наступних етапах.


Малюнок 2. Стан виконання в жорсткому покроковому режимі

2.2. Синхронізація даних

Зміна загальних даних декількома системами може привести до конфлікту змін. На цей випадок у системі обміну повідомленнями необхідно передбачити алгоритм вибору правильного підсумкового значення. Існує два основні підходи, заснованих на таких критеріях.
  • Час: підсумковим значенням стає останнім внесена зміна.
  • Пріоритет: підсумковим значенням стає зміна, виконане системою з найбільшим пріоритетом. Якщо пріоритет систем збігається, можна також враховувати час внесення змін.
Всі застарілі дані (за допомогою одного з критеріїв) можна просто перезаписати або виключити з черги повідомлень.
Оскільки підсумкове значення може залежати від порядку внесення змін, використовувати відносні значення загальних даних може виявитися дуже складно. У таких випадках слід використовувати абсолютні значення. Тоді при оновленні локальних даних системи можуть просто замінити старі значення новими. Оптимальне рішення - вибирати абсолютні або відносні значення в залежності від конкретної ситуації. Наприклад, загальні дані, такі як положення і орієнтація, повинні мати абсолютні значення, оскільки для них важливий порядок внесення змін. Відносні значення можна використовувати, наприклад, для системи генерації часток, оскільки вся інформація про частки зберігається тільки в ній самій.

3. Двигун

При розробці движка основна увага приділяється гнучкості, необхідної для подальшого розширення його функціональності. Це дозволить оптимізувати його для використання в умовах певних обмежень (наприклад, по пам'яті).
Движок можна умовно розділити на дві частини: фреймворк і менеджери. Фреймворк (див. Розділ 3.1) включає в себе частини гри, які тиражуються в процесі виконання, тобто існують в декількох примірниках. У нього також входять елементи, які беруть участь у виконанні основного циклу гри. Менеджери (див. Розділ 3.2) являють собою Singleton-об'єкти, що відповідають за виконання логічної складової гри.
Нижче представлена ​​схема ігрового движка.


Малюнок 3. Загальна архітектура движка

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

Взаємодія движка і систем здійснюється за допомогою інтерфейсів. Вони реалізовані таким чином, щоб надати движку доступ до функцій систем, а системам - до менеджерів движка.
Детальна схема движка представлена ​​в додатку A, «Схема движка».

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

  • щоб повідомити іншій системі про зміну загальних даних (наприклад, положення або орієнтації об'єктів);
  • щоб виконати функції, недоступні для даної системи (наприклад, система ІІ звертається до системи розрахунку геометричних або фізичних властивостей об'єкта, щоб виконати тест на перетин променів).
У першому випадку для управління обміном інформацією можна використовувати менеджер станів, описаний в попередньому розділі. (Детальніше про менеджера станів див. Розділ 3.2.2, «Менеджер станів».)
У другому випадку необхідно реалізувати спеціальний механізм, який дозволить надати служби однієї системи для використання іншого. Повний описцього механізму приведено в розділі 3.2.3, «Менеджер служб».

3.1. фреймворк

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


Малюнок 4. Основний цикл гри

Движок працює в віконної середовищі, тому на першому кроці циклу гри необхідно обробити всі незавершені повідомлення вікон ОС. Якщо цього не зробити, движок не буде реагувати на повідомлення ОС. На другому кроці планувальник призначає завдання за допомогою менеджера завдань. Цей процес детально описаний в розділі 3.1.1 нижче. Після цього менеджер станів (див. Розділ 3.2.2) розсилає інформацію про виконані зміни системам движка, на роботу яких вона може вплинути. На останньому кроці, в залежності від статусу виконання, фреймворк визначає, чи слід завершити або продовжити роботу движка, наприклад, для переходу до наступної сцени. Інформація про стан движка зберігається у менеджера середовища. Детальніше див. У розділі 3.2.4.

3.1.1. планувальник
Планувальник генерує опорний тактовий сигнал виконання із заданою частотою. Якщо в режимі еталонного тестування потрібно, щоб наступна операція починалася відразу після завершення попередньої, не чекаючи закінчення такту, частота може бути необмеженою.
За тактовою сигналу планувальник за допомогою менеджера завдань переводить системи в режим виконання. У вільному покроковому режимі (розділ 2.1.1) планувальник опитує системи, щоб визначити, скільки тактів їм знадобиться на завершення завдання. За результатами опитування планувальник визначає, які системи готові до виконання, а які завершать роботу в конкретний такт. Планувальник може змінити кількість тактів, якщо який-небудь системі потрібно більше часу на виконання. У жорсткому покроковому режимі (розділ 2.1.2) всі системи починають і закінчують виконання в один і той же такт, тому планувальник чекає, коли завершиться виконання всіх систем.
3.1.2. Універсальна сцена і об'єкти
Універсальна сцена і об'єкти є контейнерами для функціональності, реалізованої в інших системах. Вони призначені виключно для взаємодії з движком і не виконують ніяких інших функцій. Однак їх можна розширити, щоб використовувати функції, доступні іншим системам. Це дозволяє домогтися слабкою пов'язаності. Дійсно, універсальна сцена і об'єкти можуть використовувати властивості інших систем, не будучи прив'язаними до них. Саме це властивість виключає залежність систем один від одного і дає їм можливість працювати одночасно.
На схемі нижче зображено розширення універсальної сцени і об'єкта.


Малюнок 5. Розширення універсальної сцени і об'єкта

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

Детальна схема взаємодії движка і систем наведена в додатку B, «Схема взаємодії движка і систем».
Слід зауважити, що універсальна сцена і універсальний об'єкт відповідають за реєстрацію всіх своїх «розширень» в менеджері станів, для того, щоб все розширення могли отримувати повідомлення про зміни, внесені іншими розширеннями (тобто іншими системами). Як приклад можна привести графічне розширення, зареєстроване для отримання повідомлень про зміни положення і орієнтації, виконаних фізичними розширенням.
Детальну інформацію про компоненти системи див. Розділ 5.2, «Компоненти системи».

3.2. Менеджери

Менеджери керують роботою движка. Вони є Singleton-об'єктами, тобто менеджер кожного типу доступний тільки в одному екземплярі. Це необхідно, оскільки дублювання ресурсів менеджерів неминуче призведе до надмірності і негативно позначиться на продуктивності. Крім того, менеджери відповідають за реалізацію загальних функцій для всіх систем.
3.2.1. Менеджер завдань
Менеджер завдань відповідає за управління системними завданнями в пулі потоків. Щоб забезпечити оптимальне n-кратне масштабування і запобігти призначення зайвих потоків, виключаючи невиправдані витрати на перемикання завдань в операційній системі, пул потоків створює по одному потоку на кожен процесор.

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


Малюнок 6. Приклад пулу потоків, що використовується менеджером завдань

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

3.2.2. Менеджер станів
Менеджер станів є частиною механізму обміну повідомленнями. Він відстежує зміни і розсилає повідомлення про них всім системам, яких ці зміни можуть торкнутися. Щоб не розсилати непотрібних повідомлень, менеджер станів зберігає інформацію про те, які системи сповіщати в тому чи іншому випадку. Цей механізм реалізований на основі шаблону «Спостерігач» (див. Додаток C, «Спостерігач (шаблон проектування)»). Якщо говорити коротко, даний шаблонпередбачає використання «спостерігача», який стежить за будь-якими змінами суб'єкта, при цьому роль посередника між ними виконує контролер змін.

Механізм працює наступним чином. 1. Спостерігач повідомляє контролеру змін (або менеджеру станів), зміни яких суб'єктів він хоче відстежувати. 2. Суб'єкт повідомляє контролер про всі свої зміни. 3. За сигналом фреймворка контролер сповіщає спостерігача про зміни суб'єкта. 4. Спостерігач відправляє суб'єкту запит на отримання оновлених даних.

У режимі вільного покрокового виконання (див. Розділ 2.1.1) реалізація цього механізму дещо ускладнюється. По-перше, оновлені дані доведеться відправляти разом з повідомленням про зміну. В цьому режимі відправка за запитом непридатна. Дійсно, якщо на момент отримання запиту система, відповідальна за зміни, ще не закінчить виконання, вона не зможе надати оновлені дані. По-друге, якщо якась система ще не готова отримати зміни в кінці такту, менеджер станів повинен буде утримувати змінені дані до тих пір, поки всі зареєстровані для їх отримання системи не прийдуть в стан готовності.

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

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


Малюнок 7. Повідомлення про внутрішні зміни універсального об'єкта

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

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


Малюнок 8. Приклад менеджера служб

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

3.2.4. Менеджер середовища
  • Менеджер середовища забезпечує роботу середовища виконання движка. Його функції умовно можна розділити на наступні групи.
  • Змінні: імена і значення загальних змінних, використовуваних усіма частинами движка. Зазвичай значення змінних визначаються при завантаженні сцени або певних налаштувань. Движок і різні системи можуть отримати до них доступ, відправивши відповідний запит.
  • Виконання: дані про виконання, наприклад про завершення виконання сцени або програми. Ці параметри можуть встановлювати і запитувати як самі системи, так і движок.
3.2.5. Менеджер платформи
Менеджер платформи реалізує абстракцію для викликів операційної системи, а також забезпечує додаткову функціональність крім простий абстракції. Перевагою такого підходу є інкапсуляція кількох типових функцій в рамках одного виклику. Тобто їх не доведеться реалізовувати окремо для кожного викликає елемента, перевантажуючи його подробицями про виклики ОС.
Розглянемо як приклад виклик менеджера платформи для завантаження динамічної бібліотеки системи. Він не тільки завантажує систему, але також отримує точки входу функції і викликає функцію ініціалізації бібліотеки. Менеджер також зберігає дескриптор бібліотеки і вивантажує його після завершення роботи движка.

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

4. Інтерфейси

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

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

4.1. Інтерфейси суб'єкта і спостерігача

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

4.2. інтерфейси менеджерів

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

4.3. інтерфейси системи

Щоб фреймворк міг отримати доступ до компонентів системи, їй необхідні інтерфейси. Без них підтримку кожної нової системидвижка довелося б реалізовувати окремо.
Кожна система включає в себе чотири компоненти, тому і інтерфейсів повинно бути чотири. А саме: система, сцена, об'єкт і завдання. Докладний описсм. в розділі 5, «Системи». Інтерфейси - це кошти отримання доступу до компонентів. Інтерфейси системи дозволяють створювати і видаляти сцени. Інтерфейси сцени, в свою чергу, дозволяють створювати і знищувати об'єкти, а також запитувати інформацію про основне завдання системи. Інтерфейс завдань в основному використовується менеджером завдань при постановці завдань в пул потоків.
Оскільки сцена і об'єкт, як частини системи, повинні взаємодіяти один з одним і з універсальної сценою і об'єктом, до яких вони прив'язані, їх інтерфейси також створюють на основі інтерфейсів суб'єкта і спостерігача.

4.4. інтерфейси змін

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

5. Системи

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

5.1. типи

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

5.2. компоненти системи

Для кожної системи необхідно реалізувати декілька компонентів. Ось деякі з них: система, сцена, об'єкт і завдання. Всі ці компоненти служать для взаємодії з різними частинами движка.
На схемі нижче зображені взаємодії між різними компонентами.


Малюнок 9. Компоненти системи

Детальна схема зв'язків між системами движка приведена в додатку B, «Схема взаємодії движка і систем».

5.2.1. система
Компонент «система», або просто система, відповідає за ініціалізацію системних ресурсів, які практично не будуть змінюватися в процесі роботи движка. Наприклад, графічна система аналізує адреси ресурсів для визначення місця їх знаходження та підвищити швидкість завантаження при використанні ресурсу. Вона також задає дозвіл екрана.
Система є основною вхідний точкою для фреймворка. Вона надає інформацію про себе (наприклад, тип системи), а також методи створення і видалення сцен.
5.2.2. сцена
Компонент «сцена», або системна сцена, відповідає за управління ресурсами, які відносяться до поточної сцені. Універсальна сцена використовує системні сцени для розширення функціональності за рахунок використання їх функцій. Як приклад можна привести фізичну сцену, яка використовується при створенні нового ігрового світу і при ініціалізації сцени визначає в ньому сили гравітації.
У сценах передбачені методи створення і знищення об'єктів, а також компонент «завдання» для обробки сцени і метод доступу до нього.
5.2.3. об'єкт
Компонент «об'єкт», або системний об'єкт, належить сцені і зазвичай пов'язаний з тим, що користувач бачить на екрані. Універсальний об'єкт використовує системний об'єкт для розширення функціональності, надаючи його властивості як свої власні.
Прикладом може послужити геометричне, графічне і фізичне розширення універсального об'єкта для відображення дерев'яної балки на екрані. Геометричні властивості будуть включати в себе положення, орієнтацію і масштаб об'єкта. Для його відображення графічна система буде використовувати спеціальну сітку. А фізична система наділить його властивостями твердого тіла для розрахунку взаємодій з іншими тілами і діючих сил гравітації.

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

5.2.4. завдання
Компонент «завдання», або системна задача, використовується для обробки сцени. Завдання отримує команду на оновлення сцени від менеджера завдань. Це сигнал для запуску системних функційна об'єктах сцени.
Виконання завдання можна розбити на підзадачі, розподіляючи їх також за допомогою менеджера завдань на ще більшу кількість потоків. Це зручний спосіб масштабування движка на кілька процесорів. Такий метод називають декомпозицией даних.
Інформація про зміну об'єктів в процесі оновлення завдань сцени передається менеджеру станів. Детальну інформацію про менеджера станів див. Розділ 3.2.2.

6. Об'єднуючи все компоненти

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

6.1. етап ініціалізації

Робота движка починається з ініціалізації менеджерів і фреймворка.
  • Фреймворк викликає завантажувач сцени.
  • Визначивши, які системи сцена буде використовувати, завантажувач викликає менеджера платформи для завантаження відповідних модулів.
  • Менеджер платформи завантажує відповідні модулі і передає їх менеджеру інтерфейсів, потім викликає їх для створення нової системи.
  • Модуль повертає завантажувачу покажчик на екземпляр системи, яка реалізує системний інтерфейс.
  • Менеджер служб реєструє всі служби, які надає системний модуль.


Малюнок 10. Ініціалізація менеджерів і систем движка

6.2. Етап завантаження сцени

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


Малюнок 11. Ініціалізація універсальної сцени і об'єкта

6.3. Етап циклу гри

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


Малюнок 12. Менеджер завдань і завдання

6.3.2. Ефективно використовувати час
Після виконання всіх завдань поточного такту основний цикл гри звертається до менеджера станів, щоб запустити етап оновлення даних.
  • Менеджер станів по черзі викликає кожен зі своїх контролерів змін для розсилки накопичених повідомлень. Контролер перевіряє, яким спостерігачам відправляти повідомлення про зміни для кожного з суб'єктів.
  • Потім він викликає потрібного спостерігача і повідомляє йому про зміну (повідомлення також включає в себе покажчик на інтерфейс суб'єкта). У режимі вільного покрокового виконання спостерігач отримує змінені дані від контролера змін, але в режимі жорсткого покрокового виконання він повинен запитувати їх у самого суб'єкта.
  • Зазвичай спостерігачами, зацікавленими в отриманні повідомлень про зміни системного об'єкта, є інші системні об'єкти, пов'язані з одним і тим же універсальним об'єктом. Це дозволяє розділити процес внесення змін на кілька завдань, які можна виконувати паралельно. Щоб спростити процес синхронізації, можна об'єднати в одному завданню всі пов'язані розширення універсального об'єкта.
6.3.3. Перевірка виконання і вихід
Підсумковий етап циклу гри являє собою перевірку стану середовища виконання. Існує кілька таких станів: робота, пауза, наступна сцена і т. П. Якщо вибрано стан «робота», буде запущена наступна ітерація циклу. Стан «вихід» означає завершення роботи циклу, звільнення ресурсів і вихід з програми. Можна реалізувати і інші стани, наприклад «пауза», «наступна сцена» і ін.

7. Висновок

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

Шаблон «Спостерігач» - це функція механізму обміну повідомленнями. Важливо добре розуміти принцип її роботи, щоб вибрати оптимальний спосіб її реалізації для движка. Фактично це механізм взаємодії між різними системами, який забезпечує синхронізацію спільних даних.

Важливу роль у розподілі навантажень відіграє управління завданнями. У додатку D наведені поради щодо створення ефективного менеджера завдань для ігрового движка.

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

Додаток A. Схема движка

Запуск обробки виконується з основного циклу гри (див. Рис. 4, «Основний цикл гри»).


Додаток B. Схема взаємодії движка і систем


Додаток C. Спостерігач (шаблон проектування)

Шаблон «Спостерігач» докладно описаний в книзі «Прийоми об'єктно-орієнтованого проектування. Патерни проектування », Е. Гамма, Р. Хельм, Р. Джонсон, Дж. Вліссідес ​​(« Design Patterns: Elements of Reusable Object-Oriented Software », Gamma E., Helm R., Johnson R., Vlissides J.). Англійською мовою вона вперше була видана в 1995 році видавництвом Addison-Wesley.

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


Малюнок 13. Шаблон «Спостерігач»

Нижче описаний процес використання даної моделі.

  1. Контролер змін реєструє спостерігача і суб'єкта, повідомлення про який він хоче отримувати.
  2. Контролер змін фактично є спостерігачем. Замість спостерігача разом з суб'єктом він реєструє самого себе. Контролер змін також зберігає свій список спостерігачів і зареєстрованих з ними суб'єктів.
  3. Суб'єкт вносить спостерігача (тобто контролера змін) до свого списку спостерігачів, які хочуть отримувати повідомлення про його зміни. Іноді додатково вказується тип змін, який визначає, в які саме зміни зацікавлений спостерігач. Це дозволяє оптимізувати процес розсилки повідомлень про зміни.
  4. Змінюючи дані або стан, суб'єкт повідомляє спостерігача за допомогою механізму зворотного виклику і передає інформацію про змінені типах.
  5. Контролер змін формує чергу повідомлень про зміни і чекає сигналу для їх розподілу по об'єктах і системам.
  6. Під час розподілу контролер змін звертається до реальних спостерігачам.
  7. Спостерігачі подають запит на інформацію про змінені даних або стані у суб'єкта (або отримують їх разом з повідомленнями).
  8. Перед видаленням спостерігача або якщо йому більше не потрібно отримувати повідомлення про суб'єкта, він видаляє підписку на даний суб'єкт в контролері змін.
існує безліч різних способівреалізувати розподіл завдань. Однак найкраще підтримувати кількість робочих потоків рівною кількості доступних логічних процесорів платформи. Намагайтеся не прив'язувати завдання до певного потоку. Час виконання завдань різних систем не завжди збігається. Це може привести до нерівномірного розподілу навантаження між робочими потоками і позначитися на ефективності. Щоб спростити цей процес, використовуйте бібліотеки управління задачами, наприклад

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

Підвищення тактової частоти;

Розміщення на одній мікросхемі двох процесорів;

Введення нових функціональних блоків;

Подовження конвеєра;

Використання багатопоточності.

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

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

Введення нових функціональних блоків також не представляє складності, але тут важливо дотримати баланс. Який сенс в десятці блоків АЛУ, якщо мікросхема не може видавати команди на конвеєр з такою швидкістю, яка дозволяє завантажити всі ці блоки?

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

Нарешті, можна реалізувати багатопоточність. Перевага цієї технології полягає у введенні додаткового програмного потоку, що дозволяє ввести в дію ті апаратні ресурси, які в іншому випадку простоювали б. За результатами експериментальних досліджень розробники Intel з'ясували, що збільшення площі мікросхеми на 5% при реалізації багатопоточності для багатьох додатків дає приріст продуктивності на 25%. Першим процесором Intel з підтримкою багатопоточності став Хеоn 2002 року. Згодом, починаючи з частоти 3,06 ГГц, багатопоточність була впроваджена в лінійку Pentium 4. Intel називає реалізацію багатопоточності в Pentium 4 гіперпоточностью (hyperthreading).

  • Tutorial

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

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

Попередження про знаках ®, ™, в статті

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

процесор

Звичайно ж, найдавніший, який найчастіше використовують і неоднозначний термін - це «процесор».

У сучасному світі процесор - це те (package), що ми купуємо в красивій Retail коробці або не дуже красивому OEM-пакетику. Неподільна сутність, що вставляється в роз'єм (socket) на материнської плати. Навіть якщо ніякого роз'єму немає і зняти його не можна, тобто якщо він намертво припаяний, це один чіп.

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

Підтримка декількох центральних процесорів в одній системі вимагає численних змін в її дизайні. Як мінімум, необхідно забезпечити їх фізичне підключення(Передбачити кілька гнізд на материнській платі), вирішити питання ідентифікації процесорів (див. Далі в цій статті, а також мою замітку), узгодження доступів до пам'яті і доставки переривань (контролер переривань повинен вміти маршрутизировать переривання на кілька процесорів) і, звичайно ж, підтримки з боку операційної системи. Я, на жаль, не зміг знайти документальної згадки моменту створення першої багатопроцесорноїсистеми на процесорах Intel, однак Вікіпедія стверджує, що Sequent Computer Systems поставляла їх вже в 1987 році, використовуючи процесори Intel 80386. Широко поширеною підтримка ж декількох чіпів в одній системі стає доступною , починаючи з Intel® Pentium.

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


До зльоту готовий! Intel® Desktop Board D5400XS

ядро

Історично багатоядерність в Intel IA-32 з'явилася пізніше Intel® HyperThreading, проте в логічній ієрархії вона йде наступною.

Здавалося б, якщо в системі більше процесорів, то вище її продуктивність (на завданнях, здатних задіяти всі ресурси). Однак, якщо вартість комунікацій між ними надто велика, то весь виграш від паралелізму побивається тривалими затримками на передачу загальних даних. Саме це спостерігається в багатопроцесорних системах - як фізично, так і логічно вони знаходяться дуже далеко один від одного. Для ефективної комунікації в таких умовах доводиться придумувати спеціалізовані шини, такі як Intel® QuickPath Interconnect. Енергоспоживання, розміри і ціна кінцевого рішення, звичайно, від усього цього не знижуються. На допомогу повинна прийти висока інтеграція компонент - схеми, які виконують частини паралельної програми, треба підтягти ближче один до одного, бажано на один кристал. Іншими словами, в одному процесорі слід організувати кілька ядер, В усьому ідентичних один одному, але працюють незалежно.

Перші багатоядерні процесори IA-32 від Intel були представлені в 2005 році. З тих пір середнє число ядер в серверних, десктопних, а нині і мобільних платформах неухильно зростає.

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


Мікроснімок чотирьохядерним процесора Intel з кодовим ім'ям Nehalem. Виділено окремі ядра, загальний кеш третього рівня, а також лінки QPI до інших процесорам і загальний контролер пам'яті.

Гіперпоток

До приблизно 2002 року єдиний спосіб отримати систему IA-32, здатну паралельно виконувати дві або більше програми, полягав у використанні саме багатопроцесорних систем. У Intel® Pentium® 4, а також лінійці Xeon з кодовим ім'ям Foster (Netburst) була представлена ​​нова технологія - гіпертреди або гіперпотокі, - Intel® HyperThreading (далі HT).

Ніщо не нове під місяцем. HT - це окремий випадок того, що в літературі іменується одночасної багатопоточність (simultaneous multithreading, SMT). На відміну від «справжніх» ядер, які є повними і незалежними копіями, в разі HT в одному процесорі дублюється лише частина внутрішніх вузлів, в першу чергу відповідають за зберігання архітектурного стану - регістри. Виконавчі ж вузли, відповідальні за організацію та обробку даних, залишаються в однині, і в будь-який момент часу використовуються максимум одним з потоків. Як і ядра, гіперпотокі ділять між собою кеші, однак починаючи з якого рівня - це залежить від конкретної системи.

Я не буду намагатися пояснити всі плюси і мінуси дизайнів з SMT взагалі і з HT зокрема. Цікавиться читач може знайти досить докладне обговорення технології у багатьох джерелах, і, звичайно ж, у Вікіпедії. Однак зазначу наступний важливий момент, Яка пояснювала б поточні обмеження на число гіперпотоков в реальному продукції.

обмеження потоків
В яких випадках наявність «нечесної» багатоядерності у вигляді HT виправдано? Якщо один потік програми не в змозі завантажити всі виконують вузли всередині ядра, то їх можна «позичити» іншому потоку. Це типово для додатків, що мають « вузьке місце»Не в обчисленнях, а при доступі до даних, тобто часто генеруючих промахи кеша і вимушених очікувати доставку даних з пам'яті. В цей час ядро ​​без HT буде змушене простоювати. Наявність же HT дозволяє швидко перемкнути вільні виконують вузли до іншого архітектурного станом (тому що воно якраз дублюється) і виконувати його інструкції. Це - окремий випадок прийому під назвою latency hiding, коли одна тривала операція, протягом якої корисні ресурси простоюють, маскується паралельним виконанням інших завдань. Якщо програма вже має високу ступінь утилізації ресурсів ядра, наявність гіперпотоков не дозволить отримати прискорення - тут потрібні «чесні» ядра.

Типові сценарії роботи десктопних і серверних додатків, розрахованих на машинні архітектури загального призначення, Мають потенціал до паралелізму, що реалізується за допомогою HT. Однак цей потенціал швидко «витрачається». Можливо, з цієї причини майже на всіх процесорах IA-32 число апаратних гіперпотоков не перевищує двох. На типових сценаріях виграш від використання трьох і більше гіперпотоков був би невеликий, а ось програш в розмірі кристала, його енергоспоживанні і вартості значний.

Інша ситуація спостерігається на типових задачах, що виконуються на відеоприскорювачах. Тому для цих архітектур характерно використання техніки SMT з більшим числом потоків. Так як співпроцесори Intel® Xeon Phi (представлені в 2010 році) ідеологічно і генеалогічно досить близькі до відеокарт, на них може бути чотиригіперпотока на кожному ядрі - унікальна для IA-32 конфігурація.

логічний процесор

З трьох описаних «рівнів» паралелізму (процесори, ядра, гіперпотокі) в конкретній системі можуть бути відсутні деякі або навіть всі. На це впливають настройки BIOS(Багатоядерність і багатопоточність відключаються незалежно), особливості мікроархітектури (наприклад, HT був відсутній в Intel® Core ™ Duo, але був повернутий з випуском Nehalem) і події при роботі системи (багатопроцесорні сервера можуть вимикати відмовили процесори в разі виявлення несправностей і продовжувати «летіти» на що залишилися). Яким чином цей багаторівневий зоопарк паралелізму видно операційній системі і, в кінцевому рахунку, прикладним програмам?

Далі для зручності позначимо кількості процесорів, ядер і потоків в деякій системі трійкою ( x, y, z), Де x- це число процесорів, y- число ядер в кожному процесорі, а z- число гіперпотоков в кожному ядрі. Далі я буду називати цю трійку топологією- усталений термін, мало що має з розділом математики. твір p = xyzвизначає число сутностей, іменованих логічними процесорамисистеми. Воно визначає повне число незалежних контекстів прикладних процесів в системі із загальною пам'яттю, виконуються паралельно, які операційна системазмушена враховувати. Я кажу «змушена», тому що вона не може керувати порядком виконання двох процесів, що знаходяться на різних логічних процесорах. Це відноситься в тому числі до гіперпотокам: хоча вони і працюють «послідовно» на одному ядрі, конкретний порядок диктується апаратурою і недоступний для спостереження або управління програмами.

Найчастіше операційна система ховає від кінцевих додатків особливості фізичної топології системи, на якій вона запущена. Наприклад, три наступні топології: (2, 1, 1), (1, 2, 1) і (1, 1, 2) - ОС буде представляти в вигляді двох логічних процесорів, хоча перша з них має два процесори, друга - два ядра, а третя - всього лише два потоки.


Windows Task Manager показує 8 логічних процесорів; але скільки це в процесорах, ядрах і гіперпотоках?


Linux top показує 4 логічних процесора.

Це досить зручно для творців прикладних програм - їм не доводиться мати справу з часто несуттєвими для них особливостями апаратури.

Програмне визначення топології

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

Інформація про топології системи в цілому, а також становище кожного логічного процесора в IA-32 доступна за допомогою інструкції CPUID. З моменту появи перших багатопроцесорних систем схема ідентифікації логічних процесорів кілька разів розширювалася. До теперішнього моменту її частини містяться в листах 1, 4 і 11 CPUID. Який з листів слід дивитися, можна визначити з наступної блок-схеми, взятої зі статті:

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

APIC ID
Local APIC (advanced programmable interrupt controller) - це пристрій (нині входить до складу процесора), що відповідає за роботу з перериваннями, що приходять до конкретного логічного процесора. Свій власний APIC є у кожного логічного процесора. І кожен з них в системі повинен мати унікальне значення APIC ID. Це число використовується контролерами переривань для адресації при доставці повідомлень, а всіма іншими (наприклад, операційною системою) - для ідентифікації логічних процесорів. Специфікація на цей контролер переривань еволюціонувала, пройшовши від мікросхеми Intel 8259 PIC через Dual PIC, APIC і xAPIC до x2APIC.

На даний момент ширина числа, що зберігається в APIC ID, досягла повних 32 біт, хоча в минулому воно було обмежено 16, а ще раніше - тільки 8 бітами. Нині залишки старих днів розкидані по всьому CPUID, проте в CPUID.0xB.EDX повертаються всі 32 біта APIC ID. На кожному логічному процесорі, незалежно виконуючому інструкцію CPUID, повертатися буде своє значення.

З'ясування родинних зв'язків
Значення APIC ID само по собі нічого не говорить про топології. Щоб дізнатися, які два логічних процесора знаходяться всередині однієї фізичної (тобто є «братами» гіпертредамі), які два - всередині одного процесора, а які виявилися і зовсім в різних процесорах, треба порівняти їх значення APIC ID. Залежно від ступеня споріднення деякі їх біти будуть збігатися. Ця інформація міститься в подлист CPUID.0xB, які кодуються за допомогою операнда в ECX. Кожен з них описує становище бітового поля одного з рівнів топології в EAX (точніше, число біт, які потрібно зрушити в APIC ID вправо, щоб прибрати нижні рівні топології), а також тип цього рівня - гіперпоток, ядро ​​або процесор, - в ECX.

У логічних процесорів, які перебувають всередині одного ядра, будуть збігатися все біти APIC ID, крім що належать полю SMT. Для логічних процесорів, які перебувають в одному процесорі, - все біти, крім полів Core і SMT. Оскільки число подлист у CPUID.0xB може рости, дана схема дозволить підтримати опис топологій і з більшим числом рівнів, якщо в майбутньому виникне необхідність. Більш того, можна буде ввести проміжні рівні між вже існуючими.

Важливе наслідок з організації даної схеми полягає в тому, що в наборі всіх APIC ID всіх логічних процесорів системи можуть бути «дірки», тобто вони не будуть йти послідовно. Наприклад, у багатоядерному процесорі з вимкненим HT все APIC ID можуть виявитися парними, так як молодший біт, що відповідає за кодування номера гіперпотока, буде завжди нульовим.

Зазначу, що CPUID.0xB - НЕ єдине джерелоінформації про логічних процесорах, доступний операційній системі. Список всіх процесорів, доступний їй, разом з їх значеннями APIC ID, кодується в таблиці MADT ACPI.

Операційні системи і топологія

Операційні системи надають інформацію про топології логічних процесорів додатків за допомогою своїх власних інтерфейсів.

У Linux інформація про топології міститься в псевдофайла / proc / cpuinfo, а також виведення команди dmidecode. У прикладі нижче я фільтрую вміст cpuinfo на деякій чотирьохядерним системі без HT, залишаючи тільки записи, які стосуються топології:

Прихований текст

[Email protected]: ~ $ Cat / proc / cpuinfo | grep "processor \ | physical \ id \ | siblings \ | core \ | cores \ | apicid" processor: 0 physical id: 0 siblings: 4 core id: 0 cpu cores: 2 apicid: 0 initial apicid: 0 processor: 1 physical id: 0 siblings: 4 core id: 0 cpu cores: 2 apicid: 1 initial apicid: 1 processor: 2 physical id: 0 siblings: 4 core id: 1 cpu cores: 2 apicid: 2 initial apicid: 2 processor: 3 physical id: 0 siblings: 4 core id: 1 cpu cores: 2 apicid: 3 initial apicid: 3

У FreeBSD топологія повідомляється через механізм sysctl в змінної kern.sched.topology_spec у вигляді XML:

Прихований текст

[Email protected]: ~ $ Sysctl kern.sched.topology_spec kern.sched.topology_spec: 0, 1, 2, 3, 4, 5, 6, 7 0, 1, 2, 3, 4, 5, 6, 7 0, 1 THREAD groupSMT group 2, 3 THREAD groupSMT group 4, 5 THREAD groupSMT group 6, 7 THREAD groupSMT group

У MS Windows 8 відомості про топології можна побачити в диспетчері завдань Task Manager.

для інформаційної індустріїпочаток XXI століття збіглося зі зрушеннями, які можна охарактеризувати як «тектонічні». До ознак нової епохи варто віднести використання сервіс-орієнтованих архітектур (service-oriented architecture, SOA), кластерних конфігурацій і багато-багато іншого, в тому числі багатоядерних процесорів. Але, зрозуміло, фундаментальна причина того, що відбувається - розвиток фізики напівпровідників, наслідком якого стало збільшення числа логічних елементів на одиницю площі, що підкоряється закону Гордона Мура. Кількість транзисторів на кристалі вже обчислюється сотнями мільйонів і скоро подолає мільярдний рубіж, в результаті чого неминуче виявляється дія відомого закону діалектики, постулює взаємозв'язок кількісних і якісних змін. В умовах, що змінилися на перший план виходить нова категорія - складність, Причому системи стають складними і на мікрорівні (процесори) і на макрорівні (корпоративні інформаційні системи).

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

Буквально в самий останній час уявлення про складність почало втрачати загальновживаний сенс, перетворившись на самостійний фактор. В цьому відношенні складність ще не цілком осмислена, а ставлення до неї не цілком визначено, хоча, як не дивно, вже майже 50 років існує окрема наукова дисципліна, яка так і називається - «теорія складних систем». (Нагадаємо, що в теорії «складною» називають систему, окремі компоненти якої об'єднані нелінійним способом; така система не є просто сумою компонентів, як буває в лінійних системах.) Можна лише дивуватися тому, що теорія систем поки не сприйнята тими фахівцями і компаніями, діяльність яких призводить їх до створення цих складних систем засобами інформаційних технологій.

«Темно-зелене горло» архітектури фон Неймана

На мікрорівні аналогом переходу від одноклітинних організмів до багатоклітинних може виявитися перехід від одноядерних процесорів до багатоядерним (Chip MultiProcessors, CMP). CMP дає одну з можливостей подолання вродженої слабкості сучасних процесорів - «пляшкового горла» архітектури фон Неймана.

Ось що говорив Джон Бекус на церемонії вручення йому Тьюрінговской премії в 1977 році: «Що таке комп'ютер по фон Нейманом? Коли 30 років тому Джон фон Нейман та інші запропонували свою оригінальну архітектуру, ідея здалася елегантною, практичною і дозволяє спростити рішення цілого ряду інженерних і програмістів завдань. І хоча за минулий час умови, що існували на момент її публікації, радикально змінилися, ми ототожнюємо наші уявлення про комп'ютери з цієї старої концепцій. У найпростішому викладі фон-Неймановская комп'ютер складається з трьох частин: це центральний процесор (CPU або ЦПУ), пам'ять і з'єднує їх канал, який служить для обміну даними між CPU і пам'яттю, причому маленькими порціями (лише по одному слову). Я пропоную назвати цей канал «пляшковим горлом фон Неймана». Напевно має бути менш примітивне рішення, ніж перекачування величезної кількості даних через «вузьке пляшкове горло». Такий канал не тільки створює проблему для трафіку, але ще і є «інтелектуальним пляшковим горлом», яке нав'язує програмістам «Послівний» мислення, не дозволяючи міркувати в більш високих концептуальних категоріях ».

Найбільшу популярність Бекуса принесло створення в середині 50-х років мови Fortran, який протягом кількох наступних десятиліть був найпопулярнішим засобом створення розрахункових програм. Але пізніше, мабуть, Бекус глибоко усвідомив його слабкості і зрозумів, що розробив «самий фон-Неймановская мову» з усіх мов високого рівня. Тому основний пафос його критики був звернений насамперед до недосконалим методам програмування.

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

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

  • SISD (Single Instruction Single Data)- «один потік команд, один потік даних» »;
  • SIMD (Single Instruction Multiply Data)- один потік команд, багато потоків даних;
  • MISD (Multiple Instruction Single Data)- багато потоків команд, один потік даних;
  • MIMD (Multiple Instruction Multiple Data)- багато потоків команд, багато потоків даних.

З цієї класифікації видно, що фон-неймановская машина є окремим випадком, що потрапляють в категорію SISD. Можливі вдосконалення в рамках архітектури SISD обмежуються включенням в неї конвеєрів та інших додаткових функціональних вузлів, а також використанням різних методів кешування. Дві інші категорії архітектур (SIMD, в яку входять векторні процесори, і конвеєрні архітектури MISD) були реалізовані в декількох проектах, але не стали масовими. Якщо залишатися в рамках цієї класифікації, то єдиною можливістю подолання обмежень «пляшкового горла» залишається розвиток архітектур класу MIMD. В їх рамках виявляється безліч підходів: це можуть бути і різні паралельні і кластерні архітектури, і багатопотокових процесори.

Ще кілька років тому в силу технологічних обмежень все багатопотокових процесори будувалися на базі одного ядра, і така багатопотоковості була названа «одночасної» - Simultaneous MultiThreading (SMT). А з появою багатоядерних процесорів з'явився альтернативний тип багатопотоковості - Chip MultiProcessors (CMP).

Особливості багатопотокових процесорів

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

  • принцип недетермінованости (indetermination principle). У багатопотоковому додатку процес розбивається на взаємодіючі між собою потоки-агенти без заздалегідь обумовленої визначеності;
  • принцип невідомості (uncertainty principle). Те, як саме ресурси будуть розподілятися між потоками-агентами, також невідомо заздалегідь.

Через цих особливостей робота багатопотокових процесорів принципово відрізняється від детермінованих обчислень по фон-неймановской схемою. В даному випадку поточний стан процесу не можна визначити як лінійну функцію попереднього стану і надійшли на вхід даних, хоча кожен з процесів можна розглядати як фон-неймановскую мікромашину. (У додатку до поведінки потоків можна навіть вжити термін «дивина», який використовується в квантовій фізиці.) Наявність цих особливостей наближає багатопотокових процесор до уявленням про складній системі, Але з чисто практичної точки зору зрозуміло, що на рівні виконання процесів ні про яку недетермінованости або невизначеності, а тим більше про дивацтва і мови бути не може. Коректно виконувана програма не може бути дивною.

У найзагальнішому вигляді багатопотокових процесор складається з двох типів примітивів. Перший тип - це ресурс, який підтримує виконання потоку, який називають mutex (від Mutual Exclusion - «взаємне виключення»), а другий - події. Те, як фізично реалізований той чи інший mutex, залежить від обраної схеми - SMT або CMP. У будь-якому випадку виконання процесу зводиться до того, що черговий потік захвативаает mutex на час свого виконання, а потім звільняє його. Якщо mutex зайнятий одним потоком, то другий потік не може його отримати. Конкретна процедура передачі повноважень на володіння mutex від одного потоку іншому може мати випадковий характер; вона залежить від реалізації управління, наприклад, в певній операційній системі. У будь-якому випадку управління повинно бути побудовано так, щоб ресурси, що складаються з mutex, розподілялися коректно і пригнічувався ефект невизначеності.

Події - це об'єкти (event), що сигналізують про про зміну у зовнішньому середовищі. Вони можуть переводити себе в режим очікування до настання іншої події або повідомляти про свій стан іншої події. Таким способом події можуть взаємодіяти між собою, і при цьому повинна забезпечуватися спадкоємність даних між подіями. Дзвінок виконання агент необхідно інформувати про готовність даних для нього. І як в розподілі mutex повинен придушуватися ефект невизначеності, так при роботі з подіями повинен придушуватися ефект невідомості. Вперше схема SMT була реалізована в процесорах Compaq Alpha 21464, а також в Intel Xeon MP і Itanium.

Логічно CMP простіше: тут паралелізм забезпечується тим, що кожен з потоків обробляється власним ядром. Але якщо програма не може бути розділене на потоки, то воно (при відсутності спеціальних заходів) обробляється одним ядром, і в такому випадку загальна продуктивність процесора обмежується швидкодією одного ядра. На перший погляд, процесор, побудований за схемою SMT, більш гнучкий, а отже, ця схема краща. Але таке твердження справедливе лише при невисокій щільності розміщення транзисторів. Якщо частота вимірюється мегагерцами і число транзисторів в кристалі наближається до мільярду, а затримки при передачі сигналів стають більшими, ніж час перемикання, то переваги отримує мікроархітектура CMP, в якій пов'язані обчислювальні елементи локалізовані.

Однак фізичне розпаралелювання призводить до того, що CMP не дуже ефективна при послідовних обчисленнях. Для подолання цього недоліку використовується підхід, який отримав назву «спекулятивна багатопотоковості» (Speculative Multithreading). У російській мові слово «спекулятивний» має негативний смисловий відтінок, тому ми назвемо таку багатопотоковості «умовної». Даний підхід передбачає апаратну або програмну підтримку поділу послідовного застосування на умовні потоки, узгодження їх виконання і інтеграцію результатів в пам'яті.

еволюція CMP

Перші масові CMP-процесори призначалися для серверного ринку. Незалежно від вендора вони, по суті, представляли собою два незалежних суперскалярні процесора на одній підкладці. Основна мотивація створення подібних конструкцій полягає в зменшенні обсягу, з тим щоб в одному конструктиві можна було «упаковувати» більше процесорів, підвищуючи питому потужність на одиницю об'єму (що критично важливо для сучасних центрів обробки даних). Тоді на загальному системному рівні досягається деяка додаткова економія, оскільки процесори, що знаходяться на одному кристалі, використовують загальні системні ресурси, такі як високошвидкісні комунікації. Зазвичай між сусідніми процесорами є лише загальний системний інтерфейс ( Мал. 1, Б).

Апологети використання CMP-процесорів обґрунтовують подальше (понад двох) збільшення числа ядер особливостями серверної навантаження, що відрізняє цей тип комп'ютерів від вбудованих або призначених для масивних обчислень систем. Від сервера потрібна велика загальна продуктивність, але затримка окремого звернення до системи є не такою критичною. Тривіальний приклад: користувач може просто не помітити мілісекунди затримку появи оновленої Web-сторінки, але дуже болісно реагує на перевантаження сервера, яка може стати причиною перебоїв в обслуговуванні.

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

Складність процесорів має ще одне важливе прояв. Проектування вироби, що нараховує мільярди компонентів, стає все більш трудомістким завданням - не дивлячись на використання засобів автоматизації. Показово, що ми є свідками більш ніж десятирічного «доведення до розуму» архітектури IA-64. Проектування CMP-процесора істотно простіше: якщо є відпрацьований ядро, то воно може тиражуватися в потрібних кількостях, а проектування обмежується створенням внутрішньої інфраструктури кристала. До того ж однотипність ядер спрощує проектування системних плат, Яке зводиться до масштабування, а в кінцевому рахунку, змінюються показники підсистем введення / виведення.

Незважаючи на наведені аргументи, поки немає достатніх підстав для однозначного твердження про переваги CMP в порівнянні з SMT. Досвід створення процесорів, що реалізують SMT, є набагато більшим: починаючи з середини 80-х років створені кілька десятків експериментальних виробів і кілька серійних процесорів. Історія розвитку CPM поки коротка: якщо не враховувати сімейство спеціалізованих сигнальних процесорів Texas Instruments TMS 320C8x, то першим успішним проектом став Hydra, виконаний в Стенфордському університеті. Серед університетських дослідницьких проектів, націлених на побудову CMP-процесорів, відомі ще три - Wisconsin Multiscalar, Carnegie-Mellon Stampede і MIT M-machine.

мікропроцесор Hydra

Кристал Hydra складається з чотирьох процесорних ядер на основі відомої RISC-архітектури MIPS. Кожне ядро ​​має кеш-пам'ять команд і кеш-пам'ять даних, а все ядра об'єднані в загальну кеш-пам'яті другого рівня. Процесори виконують звичайний набір команд MIPS плюс команди умовного зберігання (Store Conditional або SC), призначені для реалізації синхронізаційних примітивів. Процесори і кеш-пам'ять другого рівня об'єднуються шинами читання / запису, а крім того, є допоміжні адресні та керуючі шини. Всі ці шини є віртуальними, тобто логічно представляються провідними шинами, а фізично розділені на безліч сегментів, які використовують повторювачі, і буферів, що дозволяє підвищити швидкість роботи ядер.

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

Тестування Hydra при навантаженнях з явно вираженим паралелізмом на типових Web- і серверних додатках показало, що продуктивність чотирьох ядер в порівнянні з одним ядром зростає в 3-3,8 разів, тобто практично лінійно. Це дає підстави вважати, що процесори такого типу цілком вдало «впишуться» в ті додатки, в яких використовуються сервери з SMP-архітектурою. Але зрозуміло, що процесор повинен досить ефективно працювати і з послідовними додатками, тому одна з найважливіших завдань полягає в реалізації умовної багатопотоковості. В Hydra вона реалізована на апаратному рівні, і вибір цього підходу обгрунтований тим, що він не вимагає додаткових витрат на програмування паралельних додатків.

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

У 2000 році в обстановці суворої секретності була створена компанія Afara. Її засновниками стали професор Кунле Олукотун зі Стенфордського університету і відомий розробник процесорів Ліс Кон, який мав досвід роботи в Intel і Sun Microsystems. Кон був одним з авторів RISC-процесорів i860 і i960 в першій з цих корпорацій і UltraSPARC-I - у другій. Під його керівництвом здійснена переробка Hydra під процесорні ядра на базі процесора SPARC. У 2002 році Afara була куплена Sun Microsystems, і на цьому закінчилася історія проекту Hydra і почалася історія Niagara.

Niagara - «сплав» MAJC і Hydra

У процесора UltraSPARC T1, більш відомого як Niagara, два основних попередника - Hydra і MAJC.

В середині 90-х років, на хвилі захоплення спеціалізованими Java-процесорами, в Sun Microsystems була зроблена спроба створення процесора «з дуже довгим словом» - Very Long Instruction Word (VLIW). Ця ініціатива отримала назву MAJC (Microprocessor Architecture for Java Computing). Як і в інших проектах, які стартували в той час (Intel IA-64 Itanium), в даному випадку ставилося завдання перенесення деяких з найскладніших операцій у відання компілятора. Звільнилася транзисторную логіку можна використовувати для створення більш продуктивних функціональних вузлів (functional units), з тим щоб забезпечити продуктивний обмін командами і даними між CPU, кеш-пам'яттю і основною пам'яттю. Таким чином, долали фон-Неймановская «пляшкове горло».

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

Niagara втілює в собі найкраще з двох альтернативних підходів до реалізації багатопотоковості - SMT і CMP. На перший погляд, він дуже схожий на Hydra, але швидше за Hydra можна назвати «макетом» Niagara. Крім того що в останньому - вдвічі більше ядер, кожне з них може обробляти чотири потоки.

Процесор Niagara забезпечує апаратну підтримку виконання 32 потоків, які розділені на вісім груп (по чотири потоки в кожній). Для виконання кожної групи служить свій обробляє канал SPARC pipeline ( рис.2). Він являє собою процесорний ядро, побудоване відповідно до архітектури SPARC V9. Кожен SPARC pipeline містить кеш-пам'ять першого рівня для команд і даних. Спільно 32 потоку використовують кеш-пам'ять другого рівня ємністю 3 Мбайт, розділену на чотири банки. Комутатор з'єднує вісім ядер, банки кеш-пам'яті другого рівня і інші розподіляються ресурси CPU, причому підтримує швидкість обміну 200 Гбайт / с. Крім того, в комутаторі знаходиться порт для систем введення / виводу і канали до пам'яті типу DDR2 DRAM, що забезпечують швидкість обміну 20 Гбайт / с; максимальна ємність пам'яті становить до 128 Гбайт.

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

проект Cell

Власний підхід до створення багатоядерних процесорів запропонувала корпорація IBM, чий проект Cell названий «гетерогенним мультипроцесорним чіпом» (heterogeneous chip multiprocessor). Архітектуру Cell називають ще й Cell Broadband Engine Architecture (CBEA). Мультипроцессор Cell складається з ядра IBM 64-bit Power Architecture і восьми спеціалізованих співпроцесорів, що реалізують схему «одна команда багато даних». У компанії IBM цю архітектуру називають Synergistic Processor Unit (SPU). Вона може з успіхом використовуватися при необхідності обробляти великі потоки даних, наприклад в криптографії, в різних мультимедійних та наукових програмах, таких як швидке перетворення Фур'є або матричні операції. Архітектура Cell створена групою дослідників IBM Research спільно з колегами з IBM Systems Technology Group, Sony і Toshiba, а її першим додатком повинні стати мультимедійні пристрої, що вимагають великих обсягів обчислень.

Основа Synergistic Processor Unit - набір команд Instruction Set Architecture (ISA). Команди мають довжину 32 біт і адресуються трьом операндам, розміщених в регістровому пулі, який складається з 128 регістрів по 128 біт в кожному.

У перспективі застосування Cell не буде обмежений ігровими системами. На черзі - телебачення високої чіткості, Домашні сервери і навіть суперкомп'ютери.

література
  1. Леонід Черняк. Ревізія першооснов - кінець застою? // Відкриті системи. - 2003 №5.
  2. Михайло Кузьмінський. Багатонитковою архітектура мікропроцесорів // Відкриті системи. - 2002 №1.
  3. Rajat A Dua, Bhushan Lokhande. A Comparative study of SMT and CMP multiprocessors. -

Розібравшись з теорією багатопоточності, розглянемо практичний приклад - Pentium 4. Уже на етапі розробки цього процесора інженери Intel продовжували роботу над підвищенням його швидкодії без внесення змін до програмний інтерфейс. Розглядалося п'ять найпростіших способів:
1. Підвищення тактової частоти.
2. Розміщення на одній мікросхемі двох процесорів.
3. Введення нових функціональних блоків.
1. Подовження конвеєра.
2. Використання багатопоточності.
Найбільш очевидний спосіб підвищення швидкодії полягає в тому, щоб підвищити тактову частоту, не змінюючи інші параметри. Як правило, кожна наступна модель процесора має дещо вищу тактову частоту, ніж попередня. На жаль, при прямолінійній підвищенні тактової частоти розробники стикаються з двома проблемами: збільшенням енергоспоживання (що актуально для портативних комп'ютерів і інших обчислювальних пристроїв, що працюють на акумуляторах) і перегрівом (що вимагає створення більш ефективних теплоотводов).
Другий спосіб - розміщення на мікросхемі двох процесорів - порівняно простий, але він пов'язаний з подвоєнням площі, займаної мікросхемою. Якщо кожен процесор забезпечується власної кеш-пам'яттю, кількість мікросхем на пластині зменшується вдвічі, але це також означає подвоєння витрат на виробництво. Якщо для обох процесорів передбачається загальна кеш-пам'ять, значного збільшення займаної площі вдається уникнути, проте в цьому випадку виникає інша проблема - об'єм кеш-пам'яті в перерахунку на кожен процесор зменшується вдвічі, а це неминуче позначається на продуктивності. Крім того, якщо професійні серверні додатки здатні повністю задіяти ресурси декількох процесорів, то в звичайних настільних програмах внутрішній паралелізм розвинений в значно меншому ступені.
Введення нових функціональних блоків також не представляє складності, але тут важливо дотримати баланс. Який сенс в десятці блоків АЛУ, якщо мікросхема не може видавати команди на конвеєр з такою швидкістю, яка дозволяє завантажити всі ці блоки?
Конвеєр зі збільшеним числом ступенів, здатний розділяти завдання на більш дрібні сегменти і обробляти їх за короткі періоди часу, з одного боку, підвищує продуктивність, з іншого, посилює негативні наслідки невірного прогнозування переходів, кеш-промахів, переривань і інших подій, що порушують нормальний хід обробки команд в процесорі. Крім того, щоб повністю реалізувати можливості розширеного конвеєра, необхідно підвищити тактову частоту, а це, як ми знаємо, призводить до підвищених енергоспоживанню і тепловіддачі.
Нарешті, можна реалізувати багатопоточність. Перевага цієї технології полягає у введенні додаткового програмного потоку, що дозволяє ввести в дію ті апаратні ресурси, які в іншому випадку простоювали б. За результатами експериментальних досліджень розробники Intel з'ясували, що збільшення площі мікросхеми на 5% при реалізації багатопоточності для багатьох додатків дає приріст продуктивності на 25%. Першим процесором Intel з підтримкою багатопоточності став Xeon 2002 року. Згодом, починаючи з частоти 3,06 ГГц, багатопоточність була впроваджена в лінійку Pentium 4. Intel називає реалізацію багатопоточності в Pentium 4 гіперпоточностью (hyperthreading).
Основний принцип гіперпоточності - одночасне виконання двох програмних потоків (або процесів - процесор не відрізняє процеси від програмних потоків). Операційна система розглядає гіперпоточний процесор Pentium 4 як двохпроцесорний комплекс із загальними кешами і основною пам'яттю. Планування операційна система виконує для кожного програмного потоку окремо. Таким чином, в один і той же час можуть виконуватися два додатки. Наприклад, поштова програма може відправляти або приймати повідомлення в фоновому режимі, Поки користувач взаємодіє з інтерактивним додатком - тобто демон і призначена для користувача програма виконуються одночасно, як ніби системі є два процесори.
Прикладні програми, що передбачають можливість виконання у вигляді декількох програмних потоків, можуть задіяти обидва «віртуальних процесора». Наприклад, програми редагування відеоданих зазвичай дозволяють користувачам застосовувати фільтри до всіх кадрів. Такі фільтри коректують яскравість, контраст, колірний баланс і інші властивості кадрів. У такій ситуації програма може призначити один віртуальний процесор для обробки парних кадрів, а інший - для обробки непарних. При цьому два процесори будуть працювати абсолютно незалежно один від одного.
Оскільки програмні потоки звертаються до одних і тих же апаратних ресурсів, необхідна координація цих потоків. В контексті гіперпоточності розробники Intel виділили чотири корисних стратегії управління спільним споживанням ресурсів: дублювання ресурсів, а також жорстке, граничне і повне розділення ресурсів. Розглянемо ці стратегії.
Почнемо з дублювання ресурсів (resource duplication). Як відомо, деякі ресурси з метою організації програмних потоків дублюються. Наприклад, так як кожному програмному потоку потрібно з індивідуальним регулюванням, потрібен другий лічильник команд. Крім того, необхідно ввести другу таблицю відображення архітектурних регістрів (Еах, ЕВХ і т. Д.) На фізичні регістри; аналогічним чином, дублюється контролер переривань, оскільки обробка переривань для кожного потоку проводиться індивідуально.
Далі слід методика жорсткого поділу ресурсів (partitioned resource sharing) між програмними потоками. Наприклад, якщо в процесорі передбачена чергу між двома функціональними ступенями конвеєра, то половину слотів можна віддавати потоку 1, іншу половину - потоку 2. Поділ ресурсів легко реалізується, не веде до дисбалансу і забезпечує повну незалежність програмних потоків один від одного. При повному поділі всіх ресурсів один процесор фактично перетворюється в два. З іншого боку, може скластися така ситуація, при якій один програмний потік не використовує ресурси, які могли б стати в нагоді другого потоку, але щодо яких у нього немає повноважень доступу. В результаті ресурси, які в іншій ситуації могли б бути задіяні, простоюють.
Протилежність жорсткого поділу - повне розділення ресурсів (full resource sharing). У цій схемі до потрібних ресурсів може отримати доступ будь-який програмний потік, а обслуговуються вони в порядку надходження запитів на доступ. Розглянемо ситуацію, в якій швидкий потік, що складається переважно з операцій додавання і віднімання, співіснує з повільним потоком, які реалізують операції множення і ділення. Якщо команди викликаються з пам'яті швидше, ніж виконуються операції множення і ділення, число команд, викликаних в рамках повільного потоку і поставлених в чергу на конвеєр, буде поступово зростати. В кінцевому підсумку ці команди заповнять чергу, в результаті швидкий потік через брак місця в ній зупиниться. Повне розділення ресурсів вирішує проблему неоптимального витрачання загальних ресурсів, але створює дисбаланс їх споживання - один потік може уповільнити або зупинити інший.
Проміжна схема реалізується в рамках порогового поділу ресурсів (threshold resource sharing). Відповідно до цієї схеми будь-який програмний потік може динамічно отримувати певний (обмежений) обсяг ресурсів. Стосовно до реплицироваться ресурсів цей підхід забезпечує гнучкість без загрози простою одного з програмних потоків через неможливість отримання ресурсів. Якщо, наприклад, заборонити кожному з потоків займати більше 3/4 черзі команд, підвищене споживання ресурсів повільним потоком не завадить виконанню швидкого.
Модель гіперпоточності Pentium 4 об'єднує різні стратегії поділу ресурсів. Таким чином, робиться спроба вирішити всі проблеми, пов'язані з кожною стратегією. Дублювання реалізується відносно ресурсів, доступ до яких постійно потрібно обом програмним потокам (зокрема, щодо лічильника команд, таблиці відображення регістрів і контролера переривань). Дублювання цих ресурсів збільшує площу мікросхеми всього лише на 5% - погодьтеся, цілком розумна плата за многопоточность. Ресурси, доступні в такому обсязі, що практично виключається ймовірність їх захоплення одним потоком (наприклад, рядки кеша), розподіляються динамічно. Доступ до ресурсів, контролюють роботу конвеєра (зокрема, його численні черги), розділяється - кожному програмному потоку віддається половина слотів. Головний конвеєр архітектури Netburst, реалізованої в Pentium 4, зображений на рис. 8.7; білі і сірі областіна цій ілюстрації позначають механізм розподілу ресурсів між білим і сірим програмними потоками.
Як бачимо, все черзі на цій ілюстрації розділені - кожному програмному потоку виділяється по половині слотів. Жоден з програмних потоків не може обмежити роботу іншого. Блок розподілу і підміни також поділяється. Ресурси планувальника поділяються динамічно, але на основі якогось порогового значення - таким чином, жоден з потоків не може зайняти всі слоти черзі. Для всіх інших ступенів конвеєра має місце повне розділення.
Втім, з багатопоточність не все так просто. Навіть у такій прогресивній методики є недоліки. Жорстке поділ ресурсів не пов'язане з серйозними витратами, а ось динамічне поділ, особливо з урахуванням граничних величин, вимагає відстежувати споживання ресурсів на етапі виконання. Крім того, в деяких випадках програми значно краще працюють без багатопоточності, ніж з нею. Припустимо, наприклад, що при наявності двох програмних потоків для нормального функціонування кожного з них потрібно 3/4 кеша. Якби вони виконувалися по черзі, кожен показав би достатню ефективність при невеликій кількості кеш-промахів (як відомо, пов'язаних з додатковими витратами). У разі паралельного виконання кеш-промахів у кожного було б значно більше, і кінцевий результат виявився б гірше, ніж без багатопоточності.
Додаткові відомості про механізм многопоточности Реппе 4 можна почерпнути в.

THE BELL

Є ті, хто прочитали цю новину раніше вас.
Підпишіться, щоб отримувати статті свіжими.
Email
ім'я
Прізвище
Як ви хочете читати The Bell
без спаму