Profiling
Every Profiling command in CodeFizz Editor Agent, with parameters and examples.
Every Profiling command in CodeFizz Editor Agent, with parameters and examples.
16 commands. Each shows its parameters and an example, and has a copyable deep link, so you (or an AI agent) can jump straight to one.
performance_start_traceStart recording a live .utrace from the running editor
Requires UE 5.7+ (all profiling commands do, on a 5.6 editor they return an explanatory error). Begins recording a Unreal Insights .utrace from the running editor. --preset names investigation presets (goal-oriented channel groups); --channels names raw channels. A name that is both a preset and a channel (cpu, gpu, animation) means the CHANNEL inside --channels, write preset:gpu to expand the preset there. The response lists expanded_presets, added_channels (frame and bookmark are always added), channel_notes and high_cost_channels, so nothing heavy is enabled silently. A channel or preset name the engine does not have is refused before anything records, naming the close matches and listing the engine's channels. Run performance_list_channels first to see every channel the engine has. While recording, 'PIE Start' / 'PIE End' bookmarks are written as Play In Editor starts and stops (queries then take --window pie), and a guard stops the trace itself at --max-mb (default 8192, 0 = no limit), --max-seconds, or when the drive falls under --min-free-disk-mb (default 2048; a start with less free space is refused). --until-pie-end stops the trace when PIE ends. Check size and rate with performance_trace_status; stop with performance_stop_trace.
| Parameter | Type | Required | Description |
|---|---|---|---|
| file_path | string | No | Output file path for connection=file (empty = auto) |
| preset | string | No | Investigation preset: default,cpu,gpu,render,memory,loading,network,tasks,sampling,animation,uaf |
| channels | string | No | Channel names and/or preset names, comma-separated (combined with preset). Empty + no preset = engine 'default' |
| connection | string | No | file (write .utrace) or network (live stream to Unreal Insights) |
| target | string | No | Host for connection=network (default 127.0.0.1) |
| exclude_tail | bool | No | Start without the engine's in-memory tail of the last seconds (smaller trace, and no events from before the start). A trace with the 'net' channel always starts without it |
| stat_named_events | bool | No | Enable named events (stats.NamedEvents on) so CPU scopes capture stat names |
| max_mb | float | No | Stop the trace itself once this many MB are written (default 8192; 0 = no limit) |
| max_seconds | float | No | Stop the trace itself after this many seconds (default: no limit) |
| min_free_disk_mb | float | No | Refuse to start, and stop while recording, when the trace drive has less free space than this (default 2048; 0 = off) |
| until_pie_end | bool | No | Stop the trace itself when the Play In Editor session ends |
| net_verbosity | int | No | With the 'net' channel: the engine's network trace level this trace turns on, because the channel alone records nothing. 1 (default) = packets, objects, properties; 2 and 3 add serializer detail and file size; 0 = leave the level alone. It goes back to what it was when the trace stops |
cfa performance_start_trace --preset gpu
cfa performance_start_trace --preset memory --exclude-tail
cfa performance_start_trace --channels "cpu,gpu,frame,counters" --until-pie-end
cfa performance_start_trace --channels "preset:gpu,counters" --max-mb 2048
cfa performance_start_trace --connection network --target 127.0.0.1 --preset cpu
cfa performance_start_trace --file-path "C:/Traces/my.utrace" --channels "loading,counters"performance_stop_traceStop recording and optionally auto-load for analysis
Stops the active trace, one started by performance_start_trace, or one started outside CFA (-trace= on the command line, Trace.Start). With auto_load (default) the trace is then analyzed on the engine's background analysis thread: the editor keeps running and PIE keeps playing. The CLI waits for the analysis and returns the loaded trace's summary; pass --wait=false to get the job id at once and poll performance_job_status yourself. A network trace has no file here, so nothing is loaded.
| Parameter | Type | Required | Description |
|---|---|---|---|
| auto_load | bool | No | Analyze the trace after stopping |
| wait | bool | No | Wait for the background analysis to finish (false = return the job id at once) |
| wait_timeout | int | No | Seconds to wait before returning a still-running job (default 100; 50 over MCP) |
cfa performance_stop_trace
cfa performance_stop_trace --auto-load=false
cfa performance_stop_trace --wait=falseperformance_analyze_insightAnalyze a performance trace (diagnose, spikes, flame, hotpath, etc.)
Requires UE 5.7+ ('objects' query needs 5.8). Runs analysis queries against a loaded .utrace file. The recommended workflow is: (1) performance_start_trace to record, (2) performance_stop_trace to stop and auto-load, (3) performance_analyze_insight with query="diagnose" for a full automatic report, then drill down with "spikes", "flame", "hotpath", or "search" as needed. Use query="load" with trace_path to analyze a previously saved trace. The "diagnose" query returns a one-call verdict with severity findings, category breakdown, and top bottlenecks. The "flame" query shows timers by exclusive (self) time to find actual CPU-consuming code. The "search" query finds a specific timer across all frames with min/avg/max/p95/p99 stats.
| Parameter | Type | Required | Description |
|---|---|---|---|
| query | string | Yes | Query type (every one runs on a worker thread; the CLI waits for it): unload (free the loaded trace), diagnose, bound, breakdown, calltree, gpu_sync, gpu_passes, inspect_frame, gc, hitch_cause, memory_growth, critical_path, objectproperties, spikes, flame, bottlenecks, hotpath, compare, compare_traces, search, histogram, load, summary, worst_frames, frame_details, timer_stats, butterfly, threads, counters, counter_series, csv, between, net_summary, net_stats, net_packets, net_objects, loading, logs, memory, memory_series, alloc_query, stack_tree, cook, trace_channels, animation, uaf (5.8+), mass, iostore, chaos_locks, render_trace (5.8+), world_streaming (5.8+), regions, bookmarks, session, modules, file_io, tasks, context_switches, allocations, stack_samples, screenshots, objects (5.8+) |
| trace_path | string | No | Path to .utrace file (for 'load' and 'compare_traces') |
| frame_index | int | No | Frame index (omit = the worst frame in the window) |
| count | int | No | Result count (omit = the query's own default; every list reports total/returned/truncated) |
| threshold_ms | float | No | Time threshold in ms (worst_frames/spikes: min frame ms; compare_traces: min self-time delta in ms per game frame, default 0.05) |
| max_depth | int | No | Max tree/event depth (query default when omitted) |
| min_duration_ms | float | No | Min event duration for frame_details (default 0.1) |
| thread_name | string | No | Thread name filter (frame_details) |
| thread | string | No | Thread filter: a CPU thread name (exact, else prefix), or GPU. stack_samples: every sampled thread whose name contains it |
| filter | string | No | Name filter (substring). For 'uaf': variable names |
| start_time | float | No | Window start in seconds |
| end_time | float | No | Window end in seconds |
| include_values | bool | No | Include counter values |
| max_samples | int | No | Max samples per counter (default 100) |
| timer_name | string | No | Timer name (butterfly / calltree) |
| counter_id | int | No | counter_series: exact counter id from --query counters (names can repeat) |
| mode | string | No | butterfly: callers, callees or both (default both); calltree: callees or callers (default callees) |
| connection_index | int | No | Network connection index, global across game instances (0..N-1). net_summary lists every index with its sent and received bandwidth; net_packets/net_objects default to the first connection with data; net_stats aggregates outgoing traffic only when this is given |
| verbosity | string | No | Log verbosity filter |
| tracker | int | No | Memory tracker id (default: the tracker named Default, else the first; the result names the tracker used) |
| target_fps | float | No | Target FPS for budget checks (default 60) |
| category | string | No | Category filter |
| event_name | string | No | Event name filter |
| min_deviation_pct | float | No | compare: min deviation from the median to report (default 50) |
| bucket_size_ms | float | No | Histogram bucket size (default: auto from target fps) |
| snapshot_index | int | No | Snapshot index for the 'objects' query (default: the last snapshot at or before the window end) |
| skip_frames | int | No | Warmup frames to skip for 'bound'/'diagnose' (omit = auto-detect startup spikes) |
| warmup_seconds | float | No | Skip frames in the first N seconds of the window for 'bound'/'diagnose' |
| skip_waits | bool | No | For 'calltree': skip Wait/Idle children in the hot path to land on the real work leaf |
| object | string | No | For 'objectproperties': traced object name (substring). Omit to list traced objects. For 'uaf': substring of the instance's asset or owner |
| object_id | string | No | For 'objectproperties' and 'animation': trace object id, passed as the string (trace_object_id from performance_trace_object, or an id the query listed). Use it when names repeat, e.g. one object per PIE world |
| property | string | No | For 'objectproperties': a property name; the exact name and its .Member children match first, else a substring. Returns the points where each value changed |
| name | string | No | For 'counter_series': counter name (substring, case-insensitive). Omit to list all counters |
| from | string | No | Window start anchor for any windowed query: a bookmark text (substring) or a seconds value |
| to | string | No | Window end anchor: a bookmark text (first match at or after --from) or a seconds value |
| capture_id | int | No | For 'csv': capture id to read (default: first capture) |
| queue | string | No | For 'gpu_passes': GPU queue filter (e.g. Graphics, Compute) |
| wait_seconds | float | No | For 'alloc_query': max seconds to wait for results (max 60) |
| rule | string | No | For 'alloc_query': allocation rule, aAf (live at A), AaBf (growth A..B), AaBCf (leaks), AafB (short-living), aABf (long-living)... |
| time_a | float | No | For 'alloc_query': time marker A in seconds (default: trace end) |
| time_b | float | No | For 'alloc_query': time marker B in seconds |
| time_c | float | No | For 'alloc_query': time marker C in seconds |
| time_d | float | No | For 'alloc_query': time marker D in seconds |
| direction | string | No | For 'net_packets'/'net_objects': out or in (default out) |
| packet_start | int | No | For 'net_objects': first packet index of the analysis window (default 0); net_packets largest_packets[].packet_index values plug in here |
| packet_count | int | No | For 'net_objects': packets to analyze from packet_start (default 2000) |
| view | string | No | For 'gpu_passes': flat (default) or tree. For 'animation': overview, tickrecords, graph, notifies (notifies, notify states and sync markers), montages (with --object; omit --object to list animated objects) |
| enable_analyzer | bool | No | For 'render_trace': opt in to the RenderTrace analyzer (disabled by default, a UE 5.8 engine bug can crash the editor on mid-session traces) |
| window | string | No | Analyze only part of the trace: pie (first Play In Editor session), pie:N, pie:last, or full. Works on every windowed query; --from/--to and --start-time/--end-time are the other ways to set a window |
| name_mode | string | No | GPU pass names: digits (default: numbers folded to # so per-frame and per-resolution variants add up), full (exact names), timer (static timer name only) |
| allow_partial | bool | No | Query a trace whose background analysis has not finished yet (results cover only what is analyzed so far). mass, chaos_locks and cook always wait for the full analysis, and on 5.8 so do animation and objectproperties |
| wait | bool | No | Wait for the background job (the load, or the query on its worker thread) to finish (false = return the job id at once) |
| wait_timeout | int | No | Seconds to wait before returning a still-running job (default 100; 50 over MCP) |
cfa performance_analyze_insight --query diagnose
cfa performance_analyze_insight --query bound --target-fps 60
cfa performance_analyze_insight --query bound --skip-frames 30
cfa performance_analyze_insight --query breakdown --thread GPU --count 15
cfa performance_analyze_insight --query breakdown --thread GameThread
cfa performance_analyze_insight --query calltree --timer-name "FTickFunctionTask" --max-depth 8
cfa performance_analyze_insight --query calltree --timer-name "FEngineLoop::Tick" --thread GameThread --skip-waits
cfa performance_analyze_insight --query gpu_sync
cfa performance_analyze_insight --query gpu_passes --count 20
cfa performance_analyze_insight --query gpu_passes --filter Shadow
cfa performance_analyze_insight --query inspect_frame --frame-index 137
cfa performance_analyze_insight --query objectproperties
cfa performance_analyze_insight --query objectproperties --object BP_Miner --property StoredAmount
cfa performance_analyze_insight --query counter_series
cfa performance_analyze_insight --query counter_series --name "DrawCall" --count 200
cfa performance_analyze_insight --query between --from MARK_A --to MARK_B
cfa performance_analyze_insight --query between --from 5 --to 10 --count 15
cfa performance_analyze_insight --query gc
cfa performance_analyze_insight --query hitch_cause
cfa performance_analyze_insight --query hitch_cause --frame-index 137
cfa performance_analyze_insight --query csv
cfa performance_analyze_insight --query csv --filter DrawCalls --count 200
cfa performance_analyze_insight --query compare_traces --trace-path "C:/Traces/after.utrace"
cfa performance_analyze_insight --query memory_growth --count 15
cfa performance_analyze_insight --query critical_path
cfa performance_analyze_insight --query critical_path --frame-index 137
cfa performance_analyze_insight --query load --trace-path "C:/Traces/my_trace.utrace"
cfa performance_analyze_insight --query spikes --count 5 --target-fps 60
cfa performance_analyze_insight --query flame --count 10 --thread GameThread
cfa performance_analyze_insight --query hotpath --frame-index 42 --category Animation
cfa performance_analyze_insight --query search --filter "ConveyorProcessor" --count 10
cfa performance_analyze_insight --query butterfly --timer-name "MassProcessor" --mode both
cfa performance_analyze_insight --query frame_details --frame-index 100 --max-depth 5 --min-duration-ms 0.5performance_list_channelsList every trace channel the running engine has (engine + custom) plus presets
Enumerates all trace channels registered in the running editor, engine channels AND any custom channels defined by plugins, each with its enabled state, category, cost, a one-line summary, and when to use it. Also returns the named investigation presets. Run this BEFORE performance_start_trace to decide exactly what to capture for a target. Filter by name/desc substring, by category (CPU, GPU, Memory, Loading, Network, Gameplay..., Custom for channels the catalog does not describe; an unknown category is refused with the valid ones), or show only currently-enabled channels. --max-results caps the list; the response reports total, returned and truncated.
| Parameter | Type | Required | Description |
|---|---|---|---|
| filter | string | No | Substring match on channel name or description |
| category | string | No | Filter by category (CPU, GPU, Memory, Loading, Network, Gameplay, UI, Physics, Core, Custom...); an unknown one is refused |
| enabled_only | bool | No | Only channels currently enabled |
| include_presets | bool | No | Include the investigation presets in the output |
| max_results | int | No | Cap on channels returned; 0 = all |
cfa performance_list_channels
cfa performance_list_channels --category Memory
cfa performance_list_channels --filter mass
cfa performance_list_channels --enabled-onlyperformance_toggle_channelEnable or disable a trace channel at runtime (mid-trace)
Enables or disables a single trace channel on the running engine without restarting the trace. Use it to add a channel mid-session once you've narrowed down a suspect, or to drop an expensive channel. Channel name is matched leniently (case-insensitive, optional 'Channel' suffix).
| Parameter | Type | Required | Description |
|---|---|---|---|
| channel | string | Yes | Channel name (e.g. cpu, mass, memalloc) |
| enabled | bool | No | true to enable, false to disable |
cfa performance_toggle_channel --channel mass
cfa performance_toggle_channel --channel memalloc --enabled=falseperformance_trace_bookmarkInsert a named bookmark into the live trace timeline
Emits a named bookmark into the active trace so you can mark exactly when something happened (e.g. 'spawned 10k belts') and find it later in performance_analyze_insight --query bookmarks. Only recorded while a trace is active with the 'bookmark' channel enabled.
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Bookmark label |
cfa performance_trace_bookmark --name "spawned 10k belts"performance_trace_snapshotWrite a trace snapshot (tail buffer) to a .utrace file
Writes the current in-memory trace tail to a .utrace file without stopping the recording. Useful to capture the moments leading up to a spike you just saw. Leave file_path empty for an auto-generated path under the project's Profiling directory.
| Parameter | Type | Required | Description |
|---|---|---|---|
| file_path | string | No | Output snapshot path (empty = auto) |
cfa performance_trace_snapshot
cfa performance_trace_snapshot --file-path "C:/Traces/spike.utrace"performance_trace_screenshotCapture a screenshot into the live trace
Requests a screenshot to be embedded into the active trace on the next frame, so you can visually correlate the viewport with a timing spike in Unreal Insights. Needs an active trace with the 'screenshot' channel enabled; with the channel off the request is refused (the engine would capture nothing), so turn it on with performance_toggle_channel --channel screenshot first.
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | No | Screenshot label (default CFA_Screenshot) |
| show_ui | bool | No | Include editor UI in the capture |
cfa performance_trace_screenshot --name "before-spike"performance_trace_objectRegister UObject(s) for per-frame property tracing (objectproperties query)
Registers actors (matched by name and/or class in the editor/PIE world) so the trace records their UObject property values every frame, and enables the 'object' + 'objectproperties' channels. Object-property tracing is opt-in per object, nothing is recorded until you register. After registering, record (or keep recording) a trace, then read the values back with performance_analyze_insight --query objectproperties --object <name>. Pass --enabled=false to unregister: the channels stay on while any registered actor remains, and unregistering the last one turns off only the channels registering turned on. A name/class that matches no actor is refused with the closest labels and classes.
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | No | Actor label/name substring to match |
| class | string | No | Class-name substring to match (combine with name to narrow) |
| enabled | bool | No | true to register for tracing, false to unregister |
| count | int | No | Max objects to register |
cfa performance_trace_object --name BP_Miner
cfa performance_trace_object --class StaticMeshActor --count 5
cfa performance_trace_object --name BP_Miner --enabled=falseperformance_live_startStart sampling live per-frame timing (no trace needed)
Begins sampling the engine's per-frame timing counters every frame (frame time plus game/render/rhi/gpu thread ms) via FCoreDelegates::OnEndFrame. No trace and no 'stat unit' are needed, it reads the always-fresh engine counters directly. Let the editor or PIE run for a while, then call performance_live_stop to get the distribution across all sampled frames (min/avg/max/p50/p95/p99 + avg and 1%-low fps), so a single biased frame can't mislead. Sampling self-stops at --max-frames.
| Parameter | Type | Required | Description |
|---|---|---|---|
| max_frames | int | No | Stop sampling automatically after this many frames |
cfa performance_live_start
cfa performance_live_start --max-frames 600performance_live_stopStop live sampling and return the multi-frame timing distribution
Stops the live sampler started by performance_live_start and returns the distribution over all sampled frames: for frame time and each of game/render/rhi/gpu thread ms, the min/avg/max/p50/p95/p99, plus avg fps and 1%-low fps (1000 / p99 frame ms, worst-case smoothness). frame_ms reflects displayed frame time (vsync / t.MaxFPS / editor throttle capped); the thread and gpu ms show the actual per-thread work. The stop ends the session: a second stop is refused until performance_live_start runs again.
cfa performance_live_stopperformance_trace_statusRecording state (MB written, rate, limits) and background analysis progress
Reports whether a trace is recording, CFA's or one started outside CFA, with its destination, active channels, MB written, MB per minute, elapsed time, limits and free disk space, plus why the last recording stopped itself (max_mb, max_seconds, low disk, PIE end). Also reports the loaded trace's background analysis: percent of the file read, trace seconds analyzed so far, and whether it is complete.
cfa performance_trace_statusperformance_job_statusProgress or final result of a background profiling job
Profiling work that needs real frames to pass (trace analysis after stop/load, GPU captures, console-variable A/B runs) runs as a job so the editor never freezes. The CLI waits for jobs by itself; use this to poll one started with --wait=false, to list current jobs (no --job-id), or to cancel one (--cancel restores anything it changed, such as console variables). Finished jobs are kept for 30 minutes.
| Parameter | Type | Required | Description |
|---|---|---|---|
| job_id | int | No | Job id from a command's response (omit to list jobs) |
| cancel | bool | No | Stop the job and restore anything it changed |
cfa performance_job_status
cfa performance_job_status --job-id 3
cfa performance_job_status --job-id 3 --cancelperformance_profile_gpuCapture N frames of GPU timing and return the pass tree (ProfileGPU as JSON)
Requires UE 5.7+. Records its own short trace (gpu, frame and bookmark channels) over --frames frames after --warmup-frames, with r.RDG.Events 3 so every RDG pass has its name (what ProfileGPU forces; --pass-names=false keeps the project's setting), then loads that trace and returns the GPU pass hierarchy per queue averaged per frame: ms = busy time, self_ms = minus children, calls = instances per frame, max_ms = worst single instance. No log parsing and no ProfileGPU pop-up. --root keeps only subtrees whose name contains it (like r.ProfileGPU.Root), --threshold-ms and --max-depth fold small or deep nodes into 'hidden', --view flat lists passes by self time instead. --cvars applies console variables only for the capture. A bad --view, --name-mode or console variable is refused before anything records. Every changed variable and every channel it turned on is put back; the response lists them. The capture trace stays loaded, so gpu_passes, breakdown --thread GPU and calltree --thread GPU can drill further. Refused while another trace is recording. The CLI waits for the result (--wait=false returns the job id).
| Parameter | Type | Required | Description |
|---|---|---|---|
| frames | int | No | Frames to measure (default 60) |
| warmup_frames | int | No | Frames to let pass before measuring (default 30) |
| root | string | No | Keep only subtrees whose pass name contains this text (like r.ProfileGPU.Root) |
| view | string | No | tree (default, the pass hierarchy) or flat (passes by self time) |
| threshold_ms | float | No | Tree: fold nodes under this many ms per frame into 'hidden' (default 0.05) |
| max_depth | int | No | Tree: deepest level shown (default 6) |
| count | int | No | Tree: children shown per node (default 12). Flat: rows (default 25) |
| queue | string | No | Only GPU queues whose name contains this (e.g. Graphics, Compute) |
| name_mode | string | No | digits (default: numbers folded to #), full (exact names), timer (static timer name only) |
| cvars | string | No | Console variables set only for the capture: "r.Foo=1,r.Bar=0" |
| pass_names | bool | No | Set r.RDG.Events 3 during the capture so every RDG pass is named (default true) |
| timeout_seconds | int | No | Give up (and restore everything) after this many seconds (default 300) |
| wait | bool | No | Wait for the result (false = return the job id at once) |
| wait_timeout | int | No | Seconds to wait before returning a still-running job (default 100; 50 over MCP) |
cfa performance_profile_gpu
cfa performance_profile_gpu --frames 120 --root Shadow --threshold-ms 0.1
cfa performance_profile_gpu --view flat --count 30
cfa performance_profile_gpu --cvars "r.Shadow.Virtual.Cache=0"performance_abConsole-variable A/B test: frame, stage, GPU pass and CPU timer deltas
Requires UE 5.7+. Measures phase A, then phase B, in one short trace (cpu, gpu, frame, bookmark): each phase sets its console variables, lets --warmup-frames pass, then bookmarks --frames measured frames. Phase A keeps the current values unless --a is given. After both phases every variable is put back to its old value and priority, the trace is loaded, and the result has per-phase frame median and p95, stage medians (game, render, RHI thread, GPU), GPU queue busy time, and the GPU passes and CPU timers whose self ms per frame moved by at least --threshold-ms, with B minus A deltas. One variable: --cvar NAME --a 1 --b 0. Several: --a "r.Foo=1,r.Bar=2" --b "r.Foo=0,r.Bar=0". The editor keeps running between steps; the CLI waits for the result. Refused while another trace is recording.
| Parameter | Type | Required | Description |
|---|---|---|---|
| cvar | string | No | One console variable to test; --a and --b are then its two values |
| a | string | No | Phase A: the value for --cvar, or "name=value..." (omit to keep the current values) |
| b | string | Yes | Phase B: the value for --cvar, or "name=value..." |
| frames | int | No | Frames measured per phase (default 120) |
| warmup_frames | int | No | Frames to let pass after each change before measuring (default 30) |
| threshold_ms | float | No | Smallest per-frame change listed for GPU passes and CPU timers (default 0.02) |
| count | int | No | Rows per regressed / improved list (default 8) |
| pass_names | bool | No | Set r.RDG.Events 3 during the test so every RDG pass is named (default true) |
| timeout_seconds | int | No | Give up (and restore everything) after this many seconds (default 300) |
| wait | bool | No | Wait for the result (false = return the job id at once) |
| wait_timeout | int | No | Seconds to wait before returning a still-running job (default 100; 50 over MCP) |
cfa performance_ab --cvar r.Shadow.Virtual.Cache --a 1 --b 0
cfa performance_ab --cvar ShowFlag.SkeletalMeshes --b 0 --frames 240
cfa performance_ab --a "r.Lumen.ScreenProbeGather.DownsampleFactor=16" --b "r.Lumen.ScreenProbeGather.DownsampleFactor=32"performance_vsm_reportVirtual shadow map page cache report: cached vs redrawn pages per frame
Requires UE 5.7+. Sets r.Shadow.Virtual.AccumulateStats to --frames, so the renderer writes its own per-frame VSM page stats to Saved/Profiling/VSMStats(<time>).csv, then reads that file: static_pages and dynamic_pages give cached vs redrawn pages per frame and redrawn_pct (a static cache redrawn every frame shows at once), and stats lists every non-zero engine stat column (avg, min, max, last). No trace is recorded, so values are exact per frame. --visualize MODE then renders the level viewport once in that VSM visualization mode (r.Shadow.Virtual.Visualize with the VisualizeVirtualShadowMap show flag forced on: cache shows red = all invalidated, blue = dynamic invalidated, yellow-green = force cached, untinted = cached; also invalid, dirty...; an unknown mode lists the valid ones) and saves a PNG. Everything is put back afterwards, including r.ShaderPrint, which the engine's stats pass switches on. Needs virtual shadow maps in view and the level viewport rendering.
| Parameter | Type | Required | Description |
|---|---|---|---|
| frames | int | No | Frames of stats to collect (default 60) |
| visualize | string | No | VSM visualization mode for one viewport screenshot (cache, invalid, dirty...) |
| screenshot_path | string | No | PNG path for --visualize (default Saved/Profiling/VSM_<mode>_<time>.png) |
| timeout_seconds | int | No | Give up (and restore everything) after this many seconds (default 300) |
| wait | bool | No | Wait for the result (false = return the job id at once) |
| wait_timeout | int | No | Seconds to wait before returning a still-running job (default 100; 50 over MCP) |
cfa performance_vsm_report
cfa performance_vsm_report --frames 120 --visualize cache
cfa performance_vsm_report --visualize invalid --screenshot-path "C:/Temp/vsm_invalid.png"