Using the Performance service¶
The Performance service continuously measures runtime performance metrics from the Kanzi Engine and stores them as profiler samples. These metrics are exported to the trace file by the Trace service, where they appear as counter tracks in the Perfetto trace viewer. The service provides built-in metrics for frame timing, rendering statistics, resource usage, and scheduling, and you can register custom metrics through the API.
Platform support¶
The Performance service builds from sources on all known Kanzi target platforms. All built-in metrics are platform-independent.
How the Performance service works¶
The Performance service attaches measurement tasks to the Kanzi main loop scheduler. These tasks run at specific stages of the main loop (user stage, render stage) and sample the current values from the Kanzi Engine. Each measurement is stored in a typed profiler (float or integer) with a nanosecond-precision timestamp.
The Performance service defines its own profiling category (PROFILING_CATEGORY_PERFORMANCEINFO) which is always enabled at compile time, independent of the build configuration of the Kanzi Engine.
This means performance metrics are included in the trace in all build configurations (Debug, Release, and Profiling).
Built-in metrics¶
The following metrics are measured automatically when the Performance service is enabled:
Frame timing
Frames per second (FPS)
App frames per second (requires Application registration)
Frametime Total (ms) – Last frame duration
Frametime Animation (ms) – Timeline clock duration
Rendering statistics
Draw Count – Draw calls per frame (draw + drawIndirect)
Drawn Elements – Elements (triangles/vertices) rendered per frame
Images – Live GPU image object count
Framebuffers – Live GPU framebuffer object count
Render Pipelines – Live GPU render pipeline object count
Constant Data – Constant data (uniform) updates per frame
Render Pass Count – Render pass begin commands per frame
Render Pipeline Binds – Render pipeline bind commands per frame
Compute Dispatches – Compute dispatch commands per frame
GPU object statistics
Live object counts for all 16 GPU object types tracked by the gfx backend: buffers, images, framebuffers, vertex input states, depth/stencil states, blend states, raster states, samplers, render resource sets, compute resource sets, shaders, compute pipelines, render pipelines, render passes, command buffers, and GPU fences. Each reports current, maximum, lifetime created, and increase/decrease counts.
Note
Rendering statistics and GPU object statistics require the Kanzi graphics statistics layer to be enabled.
In Debug builds, the statistics layer is enabled by default.
In Release and Profiling builds, you must enable it explicitly by setting
GraphicsStatisticEnabled = true in application.cfg, or
configuration.graphicsStatisticsEnabled = true in onConfigure().
Without this setting, these metrics remain zero. FPS, frame time, resource counts, and memory usage are not affected and work in all build configurations.
See GraphicsStatisticEnabled in the Kanzi application configuration reference.
Staging buffers
Per-staging-buffer memory usage (used bytes and total size) from the command recorder.
Resource management
Resource Count – Total loaded resources
Resource CPU Mem – CPU-side memory usage
Resource GPU Mem – GPU-side memory usage
Resource AcquireQueue Size – Pending resource acquisitions
Resource DeployQueue Size – Resources waiting for deployment
Resource LoadQueue Size – Resources in loading queue
Animation and scheduling
Animations Active Count – Currently active timeline playbacks
Animations Total Count – Total timeline playback instances
Timers Count – Active timer subscriptions
Tasks Total Count – Total recurring task count
Viewing performance metrics in the trace¶
The performance metrics are primarily consumed through the trace output:
Enable the Performance service (
ServicePerformanceEnabled, enabled by default).Run the application and trigger a trace write. See Using the Profiling Trace service.
Open the trace file in the Perfetto trace viewer. The performance metrics appear as counter tracks.
The perfinfo2 command provides a quick FPS reading from the console.
Trace integration¶
The Performance service registers a collection task (registry_performanceinfo_profiling) with the Trace service.
When a trace is written, all performance profiler samples are exported as counter events on the main thread.
In the Perfetto trace viewer, each metric appears as a separate counter track showing the value over time.
Adding custom metrics¶
You can register custom performance profilers through the Performance service API.
Custom profilers support both float and size_t (integer) data types and appear alongside the built-in metrics in the trace output.
To register a custom profiler and sample it periodically:
KanziMonitorModule* module = getKanziMonitorModule(domain);
PerformanceService* perfService = module->getPerformanceService();
// Create a custom float profiler.
auto myProfiler = profilinghelper::createPerformanceInfoProfiler<float>(
"My Custom Metric",
kzProfilingGetCategoryRuntimeReference(PROFILING_CATEGORY_PERFORMANCEINFO),
PROFILING_PERFORMANCEINFO_DEFAULT_BUFFER_SIZE);
// Register it in the Performance service profiler registry.
perfService->getPerformanceInfoProfilerRegistry().registerProfiler(myProfiler);
// Store an initial measurement.
updateMeasureAndStore(myProfilerWithValue, false, initialValue);
// Set up periodic sampling using a main loop timer.
domain->getMainLoopScheduler()->appendTimer(
kanzi::UserStage,
kzMakeFixedString("MyPlugin.MeasureMyMetric"),
kanzi::MainLoopScheduler::TimerRecurrence::Recurring,
chrono::milliseconds(500),
bind(myMeasureFunction, placeholders::_1, placeholders::_2,
&myProfilerWithValue));
The updateMeasureAndStore helper records a new sample with the current timestamp.
The main loop timer calls the measurement function at the specified interval, which calls updateMeasureAndStore with the latest value.
The profiler samples are automatically included in the trace output through the Performance service collection task.
Reading profiler data¶
You can query the profiler registry to find profilers by name and read their current values:
KanziMonitorModule* module = getKanziMonitorModule(domain);
PerformanceService* perfService = module->getPerformanceService();
auto& registry = perfService->getPerformanceInfoProfilerRegistry();
// Find a profiler by name.
auto it = std::find_if(
registry.beginProfilers(), registry.endProfilers(),
[](AbstractProfilerSharedPtr p) {
return p->getName() == "My Custom Metric";
});
if (it != registry.endProfilers())
{
AbstractProfilerSharedPtr profiler = *it;
// Read aggregate data (for example, average value at field index 5).
string fieldName = profiler->getAggregateDataFieldName(5);
AbstractProfiler::Value value = profiler->getAggregateDataFieldValue(5);
if (AbstractProfiler::getDataType(value) == AbstractProfiler::DataTypeFloat)
{
float floatValue = get<float>(value);
}
}
This is useful for displaying custom metrics on-screen, logging them, or using them to drive application behavior.
Using performance watchers¶
Performance watchers let you attach threshold-based triggers to metrics. When a metric crosses the threshold, the watcher automatically executes a command and then deactivates (one-shot behavior). This prevents repeated triggers while the metric stays beyond the threshold.
The primary use case is automated trace capture: when FPS drops below 30, write a trace file.
Adding a watcher¶
Use the watch add command to create a watcher:
watch add <metric> <below|above> <threshold> <command> [args]
For example:
watch add fps below 30 trace
watch add batches above 500 trace
watch add frametime above 33.3 trace
The watcher evaluates the metric every frame. When the condition is met, it executes the command and deactivates. A deactivated watcher shows as [triggered] in the list.
Viewing available metrics¶
Use watch metrics to see all available metric names and their current values:
watch metrics
Alias |
Description |
|---|---|
|
Frames per second |
|
Application frames per second |
|
Frame time total (ms) |
|
Frame time animation (ms) |
|
Draw count (draw + drawIndirect) |
|
Drawn elements count |
|
Live GPU image object count |
|
Live GPU framebuffer object count |
|
Live GPU render pipeline object count |
|
Constant data updates per frame |
|
Render pass begin commands per frame |
|
Render pipeline bind commands per frame |
|
Compute dispatch commands per frame |
|
Live GPU object count for a specific type (for example, |
|
Alias for |
|
Alias for |
|
Alias for |
|
Alias for |
|
Total resource count |
|
CPU memory usage (bytes) |
|
GPU memory usage (bytes) |
|
Active animation count |
Managing watchers¶
List all watchers and their status:
watch list
Example output:
#1 fps below 30 -> trace [active]
#2 batches above 500 -> trace [triggered]
Remove a specific watcher by its ID:
watch remove 1
Remove all watchers:
watch clear
Re-arm a triggered watcher so it can fire again:
watch reset 2
Example workflow¶
A typical workflow for capturing a trace when FPS drops:
watch add fps below 30 trace Add the watcher
fpslimit 15 Simulate low FPS (for testing)
watch list Verify watcher triggered
fpslimit 0 Remove the FPS limit
watch reset 1 Re-arm the watcher for next time
When a watcher triggers, it logs the event and the command output at Info level.
Available commands¶
Command |
Description |
|---|---|
|
Shows Kanzi Monitor Performance Service information. |
|
Manages performance watchers. Usage: |
The perfinfo2 command displays the current FPS as measured by the Performance service.
Note
The built-in perfinfo command (from the Command Processor service) shows the last frame duration in milliseconds. Both commands warn if SuspendWhenIdle is enabled, as it affects timing accuracy.