Симулятори комп'ютерних систем: всім знайомий повноплатформний симулятор і невідомі нікому потактовий і траси

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

Симулятори комп'ютерних систем: всім знайомий повноплатформний симулятор і невідомі нікому потактовий і траси

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

Повноплатформний симулятор (full platform simulator), або "Один у полі - не воїн"

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

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

Нижче наведено блок-діаграму чіпсету x58 від компанії Intel. У повноплатформному симуляторі комп'ютера на цьому чіпсеті необхідна реалізація більшості перелічених пристроїв, у тому числі й тих, що знаходяться всередині IOH (Input/Output Hub) та ICH (Input/Output Controller Hub), які не намальовані детально на блок-діаграмі. Хоча, як показує практика, не так вже й мало пристроїв, які не використовуються тим ПЗ, яке ми збираємося запускати. Моделі таких пристроїв не можна створювати.

Симулятори комп'ютерних систем: всім знайомий повноплатформний симулятор і невідомі нікому потактовий і траси

Найчастіше повноплатформні симулятори реалізуються лише на рівні інструкцій процесора (ISA, див. попередня стаття). Це дозволяє відносно швидко та недорого створити сам симулятор. Рівень ISA також хороший тим, що залишається більш менш постійним, на відміну від, наприклад, рівня API/ABI, який змінюється частіше. До того ж, реалізація на рівні інструкцій дозволяє запускати так зване немодифіковане бінарне програмне забезпечення, тобто запускати вже скомпільований код без будь-яких змін, рівно тому, як він використовується на реальному залозі. Іншими словами, можна зробити копію («дамп») жорсткого диска, вказати його як образ для моделі в повноплатформному симуляторі і – вуаля! - ОС та інші програми завантажуються в симулятор без будь-яких додаткових дій.

Продуктивність симуляторів

Симулятори комп'ютерних систем: всім знайомий повноплатформний симулятор і невідомі нікому потактовий і траси

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

Тут якраз доречно торкнутися теми продуктивності симуляторів. Зазвичай її вимірюють IPS (instructions per second), точніше в MIPS (millions IPS), тобто кількості інструкцій процесора, виконуваних симулятором за секунду. У той самий час швидкість симуляції залежить і зажадав від продуктивності системи, де працює сама симуляція. Тому, можливо, правильніше говорити про уповільнення (slowdown) симулятора в порівнянні з оригінальною системою.

Найбільш поширені на ринку повноплатформні симулятори, ті ж QEMU, VirtualBox або VmWare Workstation мають непогану продуктивність. Для користувача може бути навіть не помітно, що робота йде у симуляторі. Так відбувається завдяки реалізованій у процесорах спеціальної можливості віртуалізації, алгоритмам бінарної трансляції та іншим цікавим речам. Це все тема для окремої статті, але якщо зовсім коротко, то віртуалізація – це апаратна можливість сучасних процесорів, що дозволяє симуляторам не симулювати інструкції, а віддавати на виконання безпосередньо в реальний процесор, якщо, звичайно, архітектури симулятора та процесора схожі. Бінарна трансляція – це переведення гостьового машинного коду в хостовий та подальше виконання на реальному процесорі. В результаті симуляція лише ненабагато повільніше, раз на 5-10, а часто взагалі працює з тією ж швидкістю, що і реальна система. Хоча на це впливає дуже багато факторів. Наприклад, якщо ми хочемо симулювати систему з кількома десятками процесорів, то швидкість відразу впаде в ці кілька десятків разів. З іншого боку, симулятори типу Simics в останніх версіях підтримують багатопроцесорне хостове «залізо» і ефективно розпаралелюють ядра, що симулюються, на ядра реального процесора.

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

Графік нижче показує зразкову залежність швидкості симуляції від деталізації моделі.

Симулятори комп'ютерних систем: всім знайомий повноплатформний симулятор і невідомі нікому потактовий і траси

Потактова симуляція

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

Найпростіший приклад – інструкція доступу до пам'яті. Якщо запитувана комірка пам'яті доступна в кеші, час виконання буде мінімально. Якщо в кеші даної інформації немає («промах кешу», cache miss), це сильно збільшить час виконання інструкції. Таким чином, для точної симуляції потрібна модель кешу. Однак моделлю кешу справа не обмежується. Процесор не просто чекатиме отримання даних з пам'яті за її відсутності в кеші. Натомість він почне виконувати такі інструкції, вибираючи такі, які не залежать від результату читання з пам'яті. Це так зване виконання «не по порядку» (OOO, out of order execution), необхідне мінімізації часу простою процесора. Врахувати це при розрахунку часу виконання інструкцій допоможе моделювання відповідних блоків процесора. Серед цих інструкцій, які виконуються, поки очікується результат читання з пам'яті, може зустрітися операція умовного переходу. Якщо результат виконання умови невідомий на даний момент, то процесор не зупиняє виконання, а робить «припущення», виконує відповідний перехід і продовжує превентивно виконувати інструкції з місця переходу. Такий блок, званий branch predictor, також має бути реалізований у мікроархітектурному симуляторі.

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

Симулятори комп'ютерних систем: всім знайомий повноплатформний симулятор і невідомі нікому потактовий і траси

Робота всіх цих блоків у реальному процесорі синхронізується спеціальними тактовими сигналами, аналогічно відбувається і моделі. Такий мікроархітектурний симулятор називають потактовим (cycle accurate). Основне його призначення - точно спрогнозувати продуктивність процесора, що розробляється, і/або розрахувати час виконання певної програми, наприклад, будь-якого бенчмарку. Якщо значення будуть нижчими за необхідні, то потрібно доопрацьовувати алгоритми та блоки процесора або оптимізувати програму.

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

При цьому для симуляції часу роботи програми використовується функціональний симулятор. Як таке комбіноване використання відбувається насправді? Спочатку запускається функціональний симулятор, у якому завантажується ОС і все необхідне запуску досліджуваної програми. Адже нас не цікавить ні сама ОС, ні початкові стадії запуску програми, її конфігурування та інше. Однак і пропустити ці частини й одразу перейти до виконання програми із середини ми теж не можемо. Тому всі ці попередні етапи проганяються на функціональному симуляторі. Після того, як програма виповнилася до моменту, що цікавить нас, можливо два варіанти. Можна замінити модель на потактову та продовжити виконання. Режим симуляції, у якому використовується виконуваний код (тобто. звичайні скомпилированные файли програм), називають симуляцією виконання (execution driven simulation). Це найпоширеніший варіант симуляції. Можливий також інший підхід – симуляція на основі трас (trace driven simulation).

Симуляція на основі трас

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

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

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

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

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

Джерело: habr.com

Додати коментар або відгук