← Back to Home
Intermediate ~12 min read

Blueprint API

Use PerfGuard entirely from Blueprint — run performance captures, display live frame times, automate scenarios, and manage baselines without writing any C++ or Python.

1

Accessing the Subsystem

PerfGuard exposes its capture workflow through a GameInstance Subsystem. To access it from any Blueprint, use the standard UE5 subsystem pattern:

Blueprint Pseudocode
Get Game InstanceGet Subsystem (class: PerfGuardSubsystem)
    → Store as variable "PerfGuard"
Blueprint graph showing PerfGuard subsystem access

Store the result in a variable for reuse throughout your Blueprint. The subsystem is available in any game mode — PIE, standalone, packaged builds, and Gauntlet runs.

*
Always check return values Functions like StartSequencePlayback return false if the sequence fails to load, and EndCSVCapture returns an empty string if capture was not active. Guard against these in your graphs.
2

One-Button Capture

The simplest Blueprint workflow: press a key to start a timed CSV capture, then print the output path. Add a Key Press event (F9) to your Level Blueprint or Player Controller.

Blueprint Pseudocode — One-Button Capture
Event F9
  |
  +-- Get Game InstanceGet Subsystem (PerfGuardSubsystem) → Store as "PerfGuard"
  |
  +-- PerfGuard → Begin CSV Capture (ScenarioName: "MyTest")
  |
  +-- Set Timer by Event (10.0 seconds) → Custom Event "StopCapture"
  |
  +-- [StopCapture fires]
       |
       +-- PerfGuard → End CSV Capture → Store return as "CSVPath"
       |
       +-- Print String (CSVPath)

What this does:

1. Pressing F9 starts the UE CSV profiler.
2. After 10 seconds, the timer fires and stops the profiler.
3. The CSV file path is printed on screen — pass it to perfguard baseline record to create a baseline.

!
Don't capture in-editor Captures should run in standalone mode for accurate numbers. If you test your Blueprint logic in PIE, the CSV data will include editor overhead. That is fine for verifying your graph works, but never use PIE data for baselines.
3

Capture with Warmup and Events

This example uses all four PerfGuard delegates to build a full capture lifecycle with warmup countdown, live status, and completion handling. Create an Actor Blueprint with a Text Render component for the display.

Blueprint Pseudocode — Capture Lifecycle
Event BeginPlay
  |
  +-- Get Game InstanceGet Subsystem (PerfGuardSubsystem) → Store as "PerfGuard"
  |
  +-- Bind Event to OnWarmupProgress (PerfGuard)
  |     +-- Custom Event "WarmupTick" (FramesRemaining: int, TotalWarmupFrames: int)
  |           +-- Set Text: "Warmup: {FramesRemaining}/{TotalWarmupFrames}"
  |
  +-- Bind Event to OnCaptureStarted (PerfGuard)
  |     +-- Custom Event "CaptureStarted" (ScenarioName: String)
  |           +-- Set Text: "Capturing: {ScenarioName}..."
  |
  +-- Bind Event to OnCaptureComplete (PerfGuard)
  |     +-- Custom Event "CaptureDone" (ScenarioName: String, CSVPath: String, bSuccess: bool)
  |           +-- Branch on bSuccess
  |           +-- True  → Set Text: "Done! Saved to {CSVPath}"
  |           +-- False → Set Text: "Capture failed"
  |
  +-- Bind Event to OnFrameCaptured (PerfGuard)
        +-- Custom Event "FrameTick" (FrameTimeMs: float, SequencePosition: float, FrameIndex: int)
              +-- Set Text: "Frame {FrameIndex}: {FrameTimeMs} ms"

Key points:

OnWarmupProgress fires each frame during warmup — use it for countdown UI.
OnCaptureStarted fires once when measurement begins (after warmup ends).
OnFrameCaptured fires every frame during capture — use for live performance displays.
OnCaptureComplete fires once when capture ends, with the CSV path and success flag.

*
Warmup matters The first 60+ frames include shader compilation and texture streaming. The Gauntlet controller handles warmup automatically, but if you are building a custom workflow, skip those frames before trusting the data.
4

Live Frame Time Display

Build a real-time frame time overlay using OnFrameCaptured. Create a UMG Widget Blueprint with a progress bar and text block.

Blueprint Pseudocode — Live Frame Time Widget
Event Construct
  |
  +-- Get Game InstanceGet Subsystem (PerfGuardSubsystem) → Store as "PerfGuard"
  |
  +-- Bind Event to OnFrameCaptured (PerfGuard)
        +-- Custom Event "OnFrame" (FrameTimeMs: float, SequencePosition: float, FrameIndex: int)
              |
              +-- Add FrameTimeMs to Array "FrameHistory" // keep last 120 entries
              |
              +-- Calculate average of FrameHistory → Store as "AvgMs"
              |
              +-- Set Progress Bar percent: Clamp(FrameTimeMs / 33.33, 0, 1)
              |     // green at 0%, red at 100% = over 33ms budget
              |
              +-- Set Text: "{AvgMs} ms avg ({1000/AvgMs} FPS)"

The progress bar fills toward red as frame time approaches the 33ms budget (30 FPS). For a 60 FPS target, divide by 16.67 instead. The rolling 120-frame average smooths out momentary spikes so the display remains readable.

5

Automated Scenario Runner

Run a scenario entirely from Blueprint: find it by name, play the Level Sequence, capture CSV during playback, and stop when the sequence ends.

Blueprint Pseudocode — Scenario Runner
Custom Event "RunScenario" (ScenarioName: String)
  |
  +-- PerfGuard → Find Scenario By Name (ScenarioName) → Store as "Scenario"
  |
  +-- Branch: Is Scenario Valid?
  |     +-- False → Print String: "Scenario not found: {ScenarioName}" → Return
  |
  +-- PerfGuard → Begin CSV Capture (ScenarioName)
  |
  +-- PerfGuard → Start Sequence Playback (Scenario, Get World) → Store as "bStarted"
  |
  +-- Branch: bStarted?
  |     +-- False → PerfGuard → End CSV CapturePrint "Sequence failed" → Return
  |
  +-- Set Timer by Event (0.5s, Looping) → Custom Event "PollSequence"
       |
       +-- PerfGuard → Is Sequence Playing? → Branch
       |
       +-- False (sequence finished):
            |
            +-- Clear Timer
            |
            +-- PerfGuard → End CSV Capture → Store as "CSVPath"
            |
            +-- Print String: "Capture complete: {CSVPath}"
*
Sequence vs Replay vs Duration Choose the right capture source for your scenario. LevelSequence gives deterministic camera paths for reproducible benchmarks. Replay captures real gameplay recordings via the UE demo system. DurationOnly is for static scenes where you just need a timed capture without any playback driver.
6

Baseline Round-Trip

Save and load baselines from Blueprint for custom comparison workflows. This lets you build in-game UI for recording golden baselines and comparing future runs.

Blueprint Pseudocode — Save Baseline
Custom Event "SaveBaseline" (Baseline: PerfBaseline)
  |
  +-- PerfGuard → Get Default Baselines Dir → Store as "Dir"
  |
  +-- PerfGuard → Save Baseline To Json (Baseline, Dir) → Branch on return
       +-- True  → Print "Baseline saved"
       +-- False → Print "Save failed"
Blueprint Pseudocode — Load Baseline
Custom Event "LoadBaseline" (FilePath: String)
  |
  +-- Make local variable: OutBaseline (type: PerfBaseline)
  |
  +-- PerfGuard → Load Baseline From Json (FilePath, OutBaseline) → Branch
       +-- True  → Use OutBaseline for comparison
       +-- False → Print "Load failed"

Baselines are stored as JSON in Saved/PerfGuard/Baselines/ by default. The GetDefaultBaselinesDir and GetDefaultResultsDir functions return the configured paths, so your Blueprint stays portable across projects.

7

Function Reference

Complete reference for all BlueprintCallable functions on UPerfGuardSubsystem.

Scenario Execution

FunctionReturnsDescription
FindScenarioByNameUPerfScenario*Look up a scenario asset by its ScenarioName property
StartSequencePlaybackboolBegin playing the scenario's Level Sequence. Returns false if sequence fails to load
StopSequencePlaybackvoidStop the active sequence
IsSequencePlayingboolTrue if a Level Sequence is currently playing
GetSequenceDurationfloatTotal sequence length in seconds. 0 if nothing playing
GetSequencePositionfloatCurrent playback position in seconds. -1 if not playing
StartReplayPlaybackboolBegin playing a demo replay file. Map must already be loaded
StopReplayPlaybackvoidStop the active replay
IsReplayPlayingboolTrue if a replay is currently playing
GetReplayDurationfloatRead replay duration from file header. Returns 0 on failure
GetDefaultReplayDirFStringAbsolute path to the configured replay directory

CSV Capture

FunctionReturnsDescription
BeginCSVCapturevoidStart the CSV profiler. Fires OnCaptureStarted
EndCSVCaptureFStringStop the profiler and return the CSV file path. Fires OnCaptureComplete
IsCapturingboolTrue if a CSV capture is active

Insights Trace

FunctionReturnsDescription
BeginTraceCapturevoidStart an Insights trace recording with specified channels
EndTraceCaptureFStringStop the trace and return the .utrace file path
IsTracingboolTrue if a trace is being recorded

Capture Health

FunctionReturnsDescription
RecordCaptureFramevoidRecord one frame during capture. Call each tick. Fires OnFrameCaptured
RecordWarmupFramevoidRecord one warmup frame for stability analysis
GetCaptureHealthReportFCaptureHealthReportGet capture quality metrics after a run

Baseline I/O

FunctionReturnsDescription
SaveBaselineToJsonboolWrite a baseline to disk as JSON
LoadBaselineFromJsonboolRead a baseline from disk into an output struct
GetDefaultBaselinesDirFStringPath to Saved/PerfGuard/Baselines/
GetDefaultResultsDirFStringPath to Saved/PerfGuard/Results/
8

Events Reference

PerfGuard exposes four multicast delegates. Bind these in your Event Graph to react to capture lifecycle events.

EventParametersWhen It Fires
OnCaptureStarted ScenarioName (String) CSV capture begins (after warmup completes)
OnCaptureComplete ScenarioName (String), CSVPath (String), bSuccess (bool) CSV capture ends. CSVPath is empty when bSuccess is false
OnFrameCaptured FrameTimeMs (float), SequencePosition (float), FrameIndex (int) Every frame during active capture
OnWarmupProgress FramesRemaining (int), TotalWarmupFrames (int) Each warmup frame before capture starts

All four delegates are multicast, so multiple Blueprints can bind to them simultaneously. For example, one Actor handles the capture logic while a separate UMG widget displays live frame times.