Loading...
Loading...
Use when a Unity 6.3 game is slow or stutters: low fps, frame spikes, hitches when entering areas or on first effects, GC spikes, too many draw calls or SetPass calls, CPU vs GPU bound questions, Profiler, Profile Analyzer, Memory Profiler, Frame Debugger or Project Auditor work, GPU Resident Drawer or SRP Batcher setup, LOD and Mesh LOD, shader warm-up and variants, memory or VRAM budgets, IL2CPP and build size, or proving a fix with numbers from a player.
npx skill4agent add scenario-labs/skills scenario-unity-performanceAgentProfilePerfProbePerfCapturemetal_tracePerfBuildnpx skills add scenario-labs/skills --skill <name>ut_*GC.CollectStartShader.CreateGPUProgramMono.JITdeviceut_perf.profileab_profilePerfRendering.Auditlint_scriptsproject_auditortriage_auditorPerfAudit.AudioImportbundle_duplicatesbuild_player(development=True)run_player(..., shot=png, markers=[...])draw_callsbudget_checkcapture_playeranalyze_capturemetal_tracemetal_gpu_framesattribute_spikesphysics_catchupmemory_budgetdensity_checkAllocScopeIs.Not.AllocatingGCMemory()PerfFrameDebug.CaptureEnableGpuResidentDrawercompare_lineBuildPlayerOptions| Value | Relative to | Source |
|---|---|---|
| 16.67 / 33.33 ms; x 0.65 mobile | frame budget at 60 / 30 fps; thermal headroom | profiling e-book p. 9, 36 |
| 0 B | managed allocation per gameplay frame | 6.3 Manual; e-book p. 66 |
| up to about 1 ms | per-frame cost of incremental GC write barriers | e-book p. 69 |
| 4.4x / 2.07x / 1.45x | GRD gain: 2M-instance stress / game in Editor / same game standalone | Oc6T4hh5gaI [frame 00:12:41] |
| 217 / 199 / 176 / 161 fps | DX12 Split / Legacy / plain DX12 / Native graphics jobs | Oc6T4hh5gaI [frame 00:03:52] |
| 256 vertices | below it GPU instancing is inefficient: combine instead | 6.3 Manual |
| about 250 ms | one PSO creation stall | Oc6T4hh5gaI [frame 00:04:48] |
| 4 pixel invocations | per one-pixel triangle (2x2 quads); gate 1 triangle per rendered pixel [added] | CmD8MVGkDxQ [00:27:26] |
| 48.55 of 80 ms | per-frame Debug.Log in a development frame | xjsqv8nj0cw [00:10:23] |
| < 200 / > 400 KB | audio: Decompress On Load / Streaming | console e-book p. 104-105 |
| up to 1 ms | CPU per extra active camera on mobile | console e-book p. 89 |
| up to 10 s | startup added by Autoconnect Profiler | e-book p. 47 |
| 50% / 70% / 80% of RAM | memory budget: 2 GB phones / general / dedicated devices | Hall; Unity tutorial; e-book |
| 5,946 to 33 SetPass; 58-60 to 5.2-6.2 ms | 3,000 spheres, MPB tint to 8 Material Variants, dev player | observed |
| 18 to 0 | first-use | observed |
| 177.9 / 110.5 / 116.3 MB | macOS app: IL2CPP Minimal + speed / IL2CPP High + size / Mono | observed |
| 14.75 M to 0.26 M triangles (7.1 to 0.12 per pixel) | 400 dense meshes after Mesh LOD, draw calls unchanged | observed |
57.1 ms frame = | burst of 3,000 Instantiate read through its own marker | observed |
| 48-80 ms vs 0 ms | MeshCollider cooking at spawn vs | observed |
| 33 us vs 2.6-3.9 us | per | observed |
| 2.5 vs 5.8 ms; 1.2x at 4x pixels | GPU busy vs CPU main (Metal System Trace); 4K vs 1080p: not pixel bound | observed |
| 1,944 to 1,002 KB | two bundles sharing a texture: implicit copies vs a shared bundle | observed |
budget_checkgc_checkattribute_spikesphysics_stepsmemory_budgetdensity_checkPerfRendering.AuditShader.CreateGPUProgram-perfShotut_review.compare| Mistake | What it looks like | Fix |
|---|---|---|
| Optimizing the side that is not bound | fewer allocations, same frame time | classify first (wait markers, GPU busy, SetPass) |
| Trusting Editor numbers or one run | "3x faster" gone in the player | player CSV; |
| Benchmarking a batch-mode player that renders nothing | 0.3 ms frames, 0 draw calls | PerfProbe submit + |
| GRD on, nothing changes | draw calls unchanged | Keep All, Forward+/Deferred+, static batching off, fallouts fixed |
| MaterialPropertyBlock for per-object color | SetPass = draw calls; | Material Variants; |
| Reading GC.Alloc ms as the cost | "allocations cost 0.5 ms" | count and bytes, |
| A monitor that formats strings each frame | GC column never 0 | preallocated buffers, write once (PerfProbe) |
| Closure in a rarely taken branch | allocations with the feature off | move captured locals into the branch |
| Deep Profile to find a spike | inflated small functions | markers and counters kept in code, |
| GPU tuned from the Frame Debugger | guessed timings | |
| Fixed render scale on a laptop | fine cold, hitches when hot or loaded | dynamic resolution; STP at a fixed scale only for a fixed pixel bound |
| Warm-up assumed to fix a first-frame hitch | still 250 ms | capture: JIT means IL2CPP, loading means async |
| Frame-spreading as the fix | lower peak, same total | measure unamortized first, fix structure |
| MeshCollider added at runtime | spawn spike, | |
Development flag set through | every platform profile changed | |
Sizing from BuildReport | 1.9 GB for a 178 MB app | shipped folder on disk |
| 17 to 83 ms frame later | pool and prewarm behind a transition |
| Benchmarking the first launch of a new build | 212 vs 22 ms | discard the first launch |
asyncUploadBufferSizeGraphicsStateCollectionFrameDebuggerUtilityProfilerCounterValuePhysics.BakeMesh(int, bool)mesh.GetEntityId()references/procedures.mdreferences/expert-notes.mdreferences/critique.mdreferences/gui-paths.mdreferences/sources.mdscripts/ut_perf.pyscripts/AgentKit/Performance/*.csscripts/Runtime/Performance/*.cs