Профілювання (програмування)

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до: навігація, пошук
CodeAnalyst3.png

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

Використання профайлерів[ред.ред. код]

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

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

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

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

Інструменти аналізу продуктивності існували на платформах IBM/360 і IBM/370 від початку 1970-х років. Ці інструменти зазвичай використовували переривання таймера, які записували PSW (англ. Program Status Word, Слово Стану Процесора) в визначені проміжки часу, аби виявити "гарячі місця" у виконуваному коді. В 1974 році Імітатори Системи Команд надали повний запис і інші можливості контролю продуктивності.

Виконуваний профайлером аналіз програми на Unix датується як мінімум 1979 роком, коли для систем Unix було розроблено основний інструмент prof, який виводив список викликів кожної функції і тривалість її виконання. У 1982 році gprof розширив профілювання до повного аналізу графа виклику.

У 1994 році Амітаб Срівастава і Алан Юстас з Digital Equipment Corporation видали документ, що описує АТОМ. АТОМ — платформа для перетворення програми на її власний профайлер. Тобто, під час компіляції, вона вставляє в програму спеціальний код для збирання інформації про події в програмі. Ця техніка, що змінює програму для аналізу, відома як "instrumentation".

Типи профайлерів, основаних на виводі[ред.ред. код]

Flat профайлер[ред.ред. код]

Flat-профайлери обчислюють середній час виклику функцій і не переривають виклики, засновані на callee або контексті.

Call-Graph профайлер[ред.ред. код]

Call Graph профайлери показують часи виклику і частоти функцій, а також ланцюги викликів, заснованих на callee. Проте не зберігають контекст.

Методи збору даних[ред.ред. код]

Профайлери, засновані на подіях[ред.ред. код]

Мови програмування, перелічені тут, мають профайлери, засновані на подіях:

  • .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-розширення.

Статистичні профайлери[ред.ред. код]

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

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

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

Деякі з найбільш використовуваних статистичних профайлерів це GNU's gprof, Oprofile, AMD's CodeAnalyst та SGI's Pixie.

Інструменти[ред.ред. код]

Інструкція: Робиться програмістом, наприклад додаючи команди, аби явно обчислити часи виконання.

Допоміжний компілятор: Приклад: "gcc -pg ..." для gprof, "quantify g++ ..." для Quantify Бінарна трансляція: інструмент додає інструментацію в скомпільований бінарник. Приклад: АТОМ.

Інструментація виконання: Безпосередньо перед виконанням код інструментується. Програмна дія повністю контролюється і управляється інструментом. Приклади: PIN, Valgrind.

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

Гіпервайзер: Дані збираються виконанням (зазвичай) незміненої програми під управлінням гіпервайзера. Приклад: SIMMON.

Симулятор: Дані збираються виконанням під управлінням Симулятора Системи Команд. Приклади: SIMMON, SIMON і OLIVER.

Техніка простої інструкції[ред.ред. код]

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

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

У створенні цих покращуючих швидкодію модифікацій, видно, що виправляються дефекти, що роблять програму повільною, а не неправильною. Ім'я для цього виду дефекту - "слизняк" (дефект повільності). Програми, як вперше написано, загалом містять як дефекти, так і слизняків. Дефекти зазвичай виправляються протягом програмного випробування, а слизняки зазвичай ні, доки не проводиться аналіз продуктивності протягом розвитку проекту.

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

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

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

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

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

Як приклад, повторення видалення "слизняка" потребує зробити щось подібно до цього: "Слизняк" X1 міг брати 50% з часу, і X2 міг брати 25% з часу. Якщо X1 убраний, тривалість виконання вирізується навпіл, і X2 бере 50% з часу. Якщо на першому проході убирається X2, час тільки зменшений до 1/4, однак, з іншого боку X1 бере 67% з часу, так що це навіть більш очевидно, і може бути прибрано. У будь-якому випадку, видалення як X1, так і X2 скорочує тривалість виконання до 75%, тобто залишені "слизняки" у чотири рази більші. Цей "ефект збільшення" дозволяє процесу продовжуватися через X3, X4, і так далі, поки всі "слизняки", що легко прибираються, не були виправлені.

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

Джерела[ред.ред. код]