Профілювання (програмування)
| Ця стаття містить перекладений текст, що потребує уваги від когось, хто вільно володіє мовою оригіналу та українською. (листопад 2008) |
|
|
Цю статтю потрібно вікіфікувати, щоб привести її вигляд до стандартів Вікіпедії. (листопад 2008) |
У розробці програмного забезпечення, аналіз продуктивності, або профілювання, - дослідження поведінки програми, використовуючи інформацію, зібрану в результаті дії програми (тобто це - форма динамічного аналізу програми, в протилежність статичному аналізу коду). Звичайна мета аналізу продуктивності - визначити які частини програми оптимізувати, для покращення використання пам'яті або швидкості.
1. Використання профайлерів Профайлер - інструмент аналізу продуктивності, який вимірює поведінку програми коли вона працює, особливо частоту і тривалість звернень до функцій. Вихідний результат - потік записаних подій (a trace) або статистичний короткий звіт спостережуваних подій (a profile). Профайлери використовують широку різноманітність методів, аби зібрати дані, у тому числі апаратні переривання, кодове оснащення апаратурою, пастки операційної системи, і вимірювання продуктивності. Використання профайлерів потрібне в процесі планування продуктивності.
Оскільки підсумовування в профайлі часто робиться пов'язано з позицією вихідного коду, де вказані події, розмір вимірюваних даних лінійний до розміру коду програми. Як контраст, розмір потоку лінійний до тривалості виконання програми, роблячи це частково непрактичним. Для послідовних програм, профайлу зазвичай досить, але проблеми продуктивності в паралельних програмах (очікуючи повідомлень або проблем синхронізації) часто залежать від взаємозв'язку часу подій, тому вимагають повного запису щоб зрозуміти проблему.
Інструменти програмного аналізу критично важливі для розуміння поведінки програми. Комп'ютерним архітекторам потрібні такі інструменти, аби оцінити, як хороші програми виконуватимуться на новій архітектурі. Авторам програмного забезпечення потрібні інструменти, аби проаналізувати їх програми і ідентифікувати критичні частини коду. Автори компіляторів часто використовують такі інструменти, аби з'ясувати, як добре виконується їх планування інструкцій або алгоритм передбачення, що відгалужується... (АТОМ, PLDI, '94)
2. Історія Інструменти аналізу продуктивності існували на платформах IBM/360 і IBM/370 від початку 1970-х, зазвичай засновані на перериваннях таймера, які записали PSW (СЛОВО СТАНУ ПРОЦЕСОРА) в визначені проміжки часу, аби виявити "гарячі місця" у виконуваному коді. Це було раннім прикладом здійснення вибірки (дивіться нижче). У ранньому 1974, Імітатори Системи Команд надали повний запис і інші можливості контролю продуктивності.
Виконуваний профайлером аналіз програми на Unix датується як мінімум 1979, коли системи Unix включали основний інструмент "prof", який виводив список кожної функції і те, скільки з тривалості виконання програми вона використовувала. У 1982, gprof розширив поняття до повного аналізу графа виклику (Gprof: a Call Graph Execution Profiler).
У 1994, Амітаб Срівастава і Алан Юстас з Digital Equipment Corporation видав папір, що описує АТОМ. АТОМ - платформа для перетворення програми на її власний профайлер. Тобто, під час компіляції, вона вставляє код в програму для аналізу. Вставлений код виводить дані аналізу. Ця техніка, змінюючи програму для аналізу себе, відома як "instrumentation".
У 2004, як Gprof, так і АТОМН з'явилися в списку "50 most influential PLDI papers of all time".
3. Типи профайлерів, основані на виводі 3.1 Flat профайлер Flat-профайлери обчислюють середній час виклику і не переривають виклики, засновані на callee або контексті. 3.2 Call-Graph профайлер Call Graph профайлери показують часи виклику, і частоти функцій, а також ланцюги застосованих викликів, заснованих на callee. Проте контекст не збережений.
4. Методи збору даних 4.1 Профайлери, засновані на подіях Мови програмування, перелічені тут, мають профайлери, засновані на подіях: .NET: Може прикріпити профілюючого агента як сервер COM до CLR. Подібно до Java, час виконання потім забезпечує різні повторні виклики в агентові, для перехоплення подій подібно до методу JIT/ введення / вихід, створення об'єктів і т.п. Особливо потужний в цьому агент профілювання може переписати код цільової програми довільним способом.
Java: JVM-Tools Interface (колись JVM Profiling Interface) JVM API забезпечує пастки до профайлеру, для заманювання в пастку подій, таких як викликів, завантаження класу, вивантаження, вхід-вихід потоку.
Python: профілювання Python включає модуль профілювання, хотшот (який є заснованим на call-graph), і використовуючи 'Sys.setprofile()' модуль до подій-пасток подібно до c_{call,return,exception}, python_{call,return,exception}.
Ruby: Ruby також використовує подібний до Python інтерфейс для профілювання. Є flat-профайлер в profile.rb, модуль, і ruby-prof C-розширення.
4.2 Статистичні профайлери Деякі профайлери оперують здійсненням вибірки. Профайлер, що здійснює вибірку, досліджує лічильник команд цільової програми з регулярними проміжками, використовуючи переривання операційної системи. Профайлери, що здійснюють вибірку, зазвичай менш точні і специфічні, але дозволяють цільовій програмі працювати майже на повну швидкість.
Деякі профайлери надають цільовій програмі додаткові команди збирати необхідну інформацію. Це може призводити до змін у виконанні програми, викликаючи неакуратні результати і помилки. Це може бути дуже специфічним, але уповільнює цільову програму, оскільки більше специфічної інформації збирається.
Результуючі дані не остатотня істина, а статистична апроксимація. Фактична кількість помилок зазвичай більша, ніж один вибраний період вибірки. Фактично, якщо значення - n разів періоду вибірки, очікувана помилка в ньому - корінь квадратний з вибраних періодів.
Деякі з найбільш використовуваних статистичних профайлерів це GNU's gprof, Oprofile, AMD's CodeAnalyst та SGI's Pixie.
4.3 Інструменти Інструкція: Робиться програмістом, наприклад додаючи команди, аби явно обчислити часи виконання. Допоміжний компілятор: Приклад: "gcc -pg ..." для gprof, "quantify g++ ..." для Quantify Бінарна трансляція: інструмент додає інструментацію в скомпільований бінарник. Приклад: АТОМ Інструментація виконання: Безпосередньо перед виконанням код інструментується. Програмна дія повністю контролюється і управляється інструментом. Приклади: PIN, Valgrind Ін'єкція виконання: Легше, ніж інструментація виконання. Код змінюється в часі виконання, аби мати переходи до допоміжних функцій. Приклад: DynInst Гіпервайзер: Дані збираються виконанням (зазвичай) незміненої програми під управлінням гіпервайзера. Приклад: SIMMON Симулятор: Дані збираються виконанням під управлінням Симулятора Системи Команд. Приклади: SIMMON, SIMON і OLIVER.
5. Техніка простої інструкції Коли послідовна програма має нескінченну петлю, найпростіший шлях знайти проблему - запустити її відладчиком, зупинити кнопкою "pause" (не breakpoint) , і розглянути стек виклику}. Кожне ствердження (або інструкція) на стеку виклику - звернення до функції, за винятком того, що внизу стека. Один з тих стверджень знаходиться в нескінченній петлі, яку можна знайти покроковим просуванням і дослідження контексту кожного ствердження.
Метод працює, навіть якщо час роботи обмежений. Спершу, програма зміненюється, якщо необхідно, щоб зробити її більше декількох секунд, можливо додаючи тимчасовий зовнішній цикл. Потім, поки програма робить те, що здається дуже довгим, це випадково зупиняється, і робиться запис стека виклику. Процес повторюється, щоб отримати додаткові зразки стека виклику. В той же час, стеки виклику порівнюються, щоб знайти будь-які ствердження, які з'являються на більш ніж один раз. Будь-яке таке ствердження, якщо можна знайти шлях, що викликає його не так часто або виключає його, скорочує тривалість виконання фракцією часу, збереженою на стеку виклику. Як тільки це зроблено, весь процес можна повторити декілька разів, зазвичай це приводить до істотних кумулятивних прискорень. Цей метод називається "випадкова зупинка" або "глибока проба".
У створенні цих покращуючих швидкодію модифікацій, видно, що виправляються дефекти, що роблять програму повільною, а не неправильною. Ім'я для цього виду дефекту - "слизняк" (дефект повільності). Програми, як вперше написано, загалом містять як дефекти, так і слизняків. Дефекти зазвичай виправляються протягом програмного випробування, а слизняки зазвичай ні, доки не проводиться аналіз продуктивності протягом розвитку проекту.
Є різні види слизняків. Загалом, речі, які могли бути зроблені навмисно, щоб зробити програмну дію довшою, можуть також траплятися ненавмисно. Один загально прийнятий вид слизняка - "гаряча пляма", що є щільним внутрішнім циклом, де лічильник команд витрачає багато свого часу. Наприклад, якщо часто внизу стеку виклику знаходиться алгоритм послідовного перебору замість двійкового пошуку, то це дійсно слизняк "гаряча пляма". Проте, якщо в пошуковому циклі є звертання до іншої функції, як наприклад порівняння рядка, та функція знаходилася б внизу стека, і виклик до неї в циклі знаходився б на наступному рівні. В даному випадку, петля не була б "гарячою плямою", але вона все ще була б "слизняком". У всіх програмах, крім маленьких, "гарячі плями" рідкі, але "слизняки" доволі розповсюджені.
Структури даних, які дуже загальні для даної проблеми, також можуть уповільнювати програмне забезпечення. Наприклад, якщо група об'єктів залишається невеликою, простий масив з послідовним перебором міг би бути набагато швидше, ніж що-небудь подібно до класу "словника", повного кодуванням хешу. З цим видом "слизняка", лічильник команд частіше всього знаходиться системній пам'яті і звільняє шаблони, поки групи конструюються і руйнуються.
Інший загальний лейтмотив - коли потужна функція написана, щоб зібрати набір корисної інформації (з бази даних, наприклад). Потім, та функція викликається багаторазово, замість необхідності зберігати результати попереднього виклику. Можливе пояснення цьому може бути те, що це поза розумінням програміста, що звернення до функції, можливо займе в мільйон разів більше щоб виконатися як оператор сусіднього привласнення. Важливий чинник міг бути "приховуванням інформації", в якому зовнішні користувачі модуля можуть не знати, що йде усередині цього.
В цей час є певні непорозуміння в аналізі продуктивності. Перше - це те, що час важливий. Знання того, скільки часу витрачається у функціях, добре для повідомлення удосконалень, але це забезпечує тільки невизначену допомогу у пошуку проблем. Інформація, що важлива - фракція часу, який індивідуальні ствердження займають у стеку виклику.
Інше непорозуміння є те, що статистична точність має значення. Типові слизняки трапляються на стеку виклику між 5 і 95 відсотками часу. Чим більшими вони є, тим менші зразки потрібні, щоб знайти їх. Як в спортивній ловлі риби, ціль - зловити їх спочатку, і виміряти їх пізніше, якщо взагалі не ніколи.
Як приклад, повторення видалення "слизняка" потребує зробити щось подібно до цього: "Слизняк" X1 міг брати 50% з часу, і X2 міг брати 25% з часу. Якщо X1 убраний, тривалість виконання вирізується навпіл, і X2 бере 50% з часу. Якщо на першому проході убирається X2, час тільки зменшений до 1/4, однак, з іншого боку X1 бере 67% з часу, так що це навіть більш очевидно, і може бути прибрано. У будь-якому випадку, видалення як X1, так і X2 скорочує тривалість виконання до 75%, тобто залишені "слизняки" у чотири рази більші. Цей "ефект збільшення" дозволяє процесу продовжуватися через X3, X4, і так далі, поки всі "слизняки", що легко прибираються, не були виправлені.
Джерела [ред.]
- Використано матеріали зі статті в англійській Вікіпедії.
