Профілювання CPU та GPU ресурсів ігор
Коли гра «тупить», перший інстинкт — відкрити Stats в Game View та дивитись на fps. Це бесполезно. Stats показує усереднене значення, не видить спайків, не розділяє CPU від GPU, не показує, який саме код з'їдає час. Для реальної діагностики потрібен Profiler в режимі Standalone на цільовому залізі.
Різниця між «42 fps в середньому» та «42 fps з просадками до 18 на кожному третьому кадрі» — це різниця між комфортною грою та відчуттям, що гра сломана. І це видно тільки через frame time graph, не через fps-лічильник.
CPU bottleneck vs GPU bottleneck — як розрізнити
Перше питання при будь-якій оптимізації: де вузьке місце. Якщо CPU гальмує → GPU чекає. Якщо GPU гальмує → CPU чекає. Змішування методів оптимізації без розуміння цього — трата часу.
Діагностика в Unity Profiler: відкриваємо CPU Usage модуль, дивимось на Gfx.WaitForPresent або Graphics.PresentAndSync. Якщо ці маркери займають 8+ мс з 16.6 мс бюджету кадру — ви GPU-bound. CPU уже віддав все GPU та просто чекає.
Якщо ж PlayerLoop, Physics.Processing або ваші скрипти займають велику частину frame time, а Gfx.WaitForPresent мінімальна — ви CPU-bound.
Це принципово різні шляхи оптимізації. GPU-bound: зменшуємо складність шейдерів, overdraw, fill rate. CPU-bound: оптимізуємо скрипти, використовуємо Job System, скорочуємо кількість Update()-викликів.
Глибоке профілювання CPU
Deep Profile в Unity — потужний інструмент, але з overhead'ом: він інструментирує кожен виклик методу, і сам по собі сповільнює гру. Використовуємо тільки для точкової діагностики конкретної підсистеми, не як постійний режим.
Що шукаємо в CPU профілі:
Managed heap allocations в Update(). Coloured Marker в Profiler — GC.Alloc. Будь-яка аллокація в гарячому шляху (Update, FixedUpdate, OnCollisionEnter) потенційно вилучає GC.Collect в майбутньому. GC.Collect на мобільних пристроях — це 2–20 мс spike. Виправляється через кешування посилань, object pools, string interning, заміну LINQ на ручні цикли.
Physics.Processing займає > 4 мс. Занадто складні Collider'и (Mesh Collider замість Capsule), занадто малий Fixed Timestep, занадто багато Rigidbody з ContinuousCollisionDetection. Першим делом — Physics Debugger: visualize sleep state всіх Rigidbody, шукати ті, що не спять без причини.
NavMesh.CalculatePath кожен кадр для 40 агентів. NavMeshAgent оновлюється за замовчуванням в кожному FixedUpdate. Для великої кількості агентів — розбиваємо на групи з оновленням через кадр або через N кадрів залежно від дистанції до гравця.
Профілювання GPU
RenderDoc — обов'язковий інструмент для будь-якого серйозного GPU-профілювання. Підключається до Android/PC, робить capture одного кадру, показує кожен draw call з часом на GPU, Input/Output текстури, pipeline state. Саме тут видно, який шейдер з'їдає 60% GPU time.
Unity Frame Debugger — легше в використанні, але менш детальний. Показує порядок отрисовки, чому об'єкти не батчуються, стан render targets. Для первинної діагностики цілком достатньо.
На мобільних пристроях — ARM Streamline (Mali) або Snapdragon Profiler (Adreno). Показують метрики, недоступні в Unity: memory bandwidth, ALU utilization, texture cache miss rate. Саме texture cache miss (багато маленьких текстур замість атласу) або високий bandwidth (текстури без mipmaps) часто є справжньою причиною гальмування, коли Draw Calls здавались в нормі.
Реальний case: мобільний аркадний раннер, 45 fps на Snapdragon 730. CPU профіль — чисто, скрипти займають < 3 мс. GPU — підозрівно багато fill rate за даними Snapdragon Profiler. RenderDoc показав: кастомний distortion-шейдер на воді семпліював GrabPass (Screen Space Texture) на кожному кадрі, плюс стояв в Transparent queue поверх трьох інших шарів з blending. Заміна GrabPass на предзапечену кубмап-текстуру для фонових відображень + перенесення water mesh нижче по Z-order убрали 11 мс з GPU time. Підсумок: 58–60 fps стабільні.
Процес профілювання
Спочатку визначаємо цільові метрики: fps бюджет (30/60/120), допустимий frame time (16.6/8.3 мс), платформа. Без цільових метрик незрозуміло, що вважати «достатньо хорошим».
Профілюємо в кількох сценаріях: idle (персонаж стоїть), пикова навантаження (бій з максимальною кількістю ефектів), переход між сценами. Кожен сценарій — окремий Profiler capture.
Створюємо звіт з конкретними bottleneck'ами, їхнім весом в ms та пропозиціями з усунення. Пріоритизуємо по співвідношенню усилій до приросту продуктивності.
| Масштаб задачі | Орієнтовні терміни |
|---|---|
| CPU/GPU профілювання + звіт (1–2 сцени) | 2–4 дні |
| Глибокий аудит + виправлення топ-3 bottleneck'ів | 1–2 тижні |
| Комплексна оптимізація під конкретну платформу | 3–8 тижнів |
Вартість визначається після вивчення проекту та цільових платформ.





