Профілювання CPU мобільної програми (Instruments/Android Profiler)
Розробник каже «програма тормозит при переході між екранами». Це — не дані для роботи. Дані — це «перехід з HomeViewController на DetailViewController займає 380 мс, з яких 240 мс уходить на viewDidLoad в DetailViewController, та в нім 200 мс — це синхронний NSJSONSerialization.jsonObject на main thread». Саме за такою точністю — до CPU-профілювщика.
Xcode Instruments: як отримати реальні дані
Instruments запускається через Xcode → Product → Profile або ⌘I. Для CPU — використовуємо Time Profiler (sampling-профілювщик, 1ms інтервал за замовчуванням) або CPU Profiler (instrumentation-based, точніше але з overhead).
Time Profiler — перший вибір для більшості задач. Показує call tree з часом виконання кожного методу. Критичні налаштування:
- Call Tree Options → Hide System Libraries — убираємо шум від системних фреймворків, бачимо лише свій код
- Separate by Thread — розуміємо, на якому потоці тормозит
- Invert Call Tree — показує «листя» дерева вызовів, то есть методи, де реально тратиться час
Типовий сценарій: записуємо 10 секунд роботи програми, відкриваємо call tree. [MyImageProcessor processImage:] займає 67% CPU. Розширюємо — там vImageScale_ARGB8888 викликається на main thread з didSelectRowAt. Виносимо в DispatchQueue.global(qos: .userInitiated), результат застосовуємо через DispatchQueue.main.async — проблема розв'язана.
Signposts та os_log для точного вимірю
Системний профілювщик має overhead та шум. Для точного замеру конкретної операції — os_signpost:
import os.signpost
let log = OSLog(subsystem: "com.app", category: "Performance")
let id = OSSignpostID(log: log)
os_signpost(.begin, log: log, name: "Image Processing", signpostID: id)
processImage(data)
os_signpost(.end, log: log, name: "Image Processing", signpostID: id)
У Instruments → Logging track бачимо точні часові мітки. Це дозволяє вимірювати не «де тормозит в цілому», а «скільки конкретно займає ця операція при різних вхідних даних».
Flame graph та де його читати
У Xcode 14+ Time Profiler показує flame graph. Широкі горизонтальні прямокутники — методи, потребуючі багато часу. Вкладеність показує стек вызовів. Головне правило: дивиться на «плато» — широкі блоки без дочірніх методів. Це «дно» стека, де реально витрачається час.
Android Studio Profiler: CPU
Android Studio CPU Profiler підтримує три режими:
| Режим | Коли використовувати | Overhead |
|---|---|---|
| Sample Java/Kotlin Methods | Первинна діагностика | Низький |
| Trace Java/Kotlin Methods | Точний аналіз, потрібен повний стек | Високий |
| Sample C/C++ Functions | Native код, NDK | Низький |
| System Trace | Системні події, janky frames | Мінімальний |
System Trace — найбільш інформативний для аналізу jank. Показує Choreographer#doFrame, RenderThread, hwuiTask, binder-визови. Видно конкретний кадр, який затримався, та чому.
Запис через UI або програмно:
Debug.startMethodTracing("myapp_trace")
// операція
Debug.stopMethodTracing()
Файл .trace відкривається в Android Studio Profiler для аналізу.
Типова знахідка на Android
Профілювання показало: при відкриванні екрану чату 180 мс уходить на SharedPreferences.getAll() — розробник завантажував всі налаштування при кожному відкриванні для перевірки флагу. SharedPreferences на головному потоці з великим файлом (2 MB через кешовані дані) — реальний блокувальник UI. Перехід на DataStore з фоновим читанням через Flow убрав цю затримку повністю.
Що робимо в рамках послуги
- Записуємо Instruments / Android Profiler сесії для ключових користувацьких сценаріїв
- Аналізуємо call tree та flame graph, виявляємо top-3 вузькі місця за часом CPU
- Додаємо
os_signpost/Traceмаркери для точного вимірю критичних операцій - Усуваємо найдені проблеми: виносимо на фонові потоки, оптимізуємо алгоритми, додаємо кеш
- Повторне профілювання для підтвердження поліпшення
Строки
Профілювання та аналіз — 1–2 дні. Усунення найдених проблем — залежить від кількості та складності: від 2 днів до 2 тижнів. Оцінюємо після аналізу.







