Відкрити головне меню
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, і так далі, поки всі "слизняки", що легко прибираються, не були виправлені.

Див. такожРедагувати