Phase 29: add project benchmarks, endurance stress and callback safety checks

This commit is contained in:
Johannes Findeisen 2026-10-27 17:07:37 +01:00
commit afc049e2c8
14 changed files with 1032 additions and 43 deletions

View file

@ -257,3 +257,9 @@ configuration explicitly, use a fresh BUILD_DIR with
Link static consumers with `-lm -ldl` plus the backend dependencies when used.
See LICENSES.md for header/plugin licensing and decision 0009 for rationale.
Recording stress/recovery is available with `make test-recording`.
Phase 29 developer qualification: `make check-development` runs the core build,
regressions, scale/virtual endurance, benchmark-gate checks, Clang analysis and
ASan/UBSan. Run `make benchmark benchmark-project` separately without contention
or sanitizers for timing reports. Optional `make test-stress-plugins` requires
installed LADSPA headers; `make test-stress` supports minimal builds too.

View file

@ -1,6 +1,6 @@
# Performance and realtime qualification
`make test-performance` runs a hardware-independent 48 kHz, 128-frame stereo
The original Phase 9 `test-performance` ran a hardware-independent 48 kHz, 128-frame stereo
workload: 64 graph nodes, 4096 MIDI notes (32 simultaneous), 16 tracks and gain
automation. Preparation and block timing use CLOCK_MONOTONIC outside the engine;
callback code itself does not clock or log. The test checks finite output and
@ -89,3 +89,130 @@ and bounded per-sample lane searches and may be costly; they are excluded from
the gain-chain baseline. Large WAV memory limits remain those in AUDIO_FILES.md.
Physical-device endurance, CPU-overload sound quality and a full GUI latency
benchmark remain unqualified.
## Phase 29 qualification workloads
The current `test-performance` emits one JSON record (the old prose output is
retired). Default: 2,000 stereo blocks at 48 kHz/128, 64 graph nodes, 16 tracks,
1,024 stored notes and 256 automation points, at most 32 active voices. This
changes the Phase 9 workload; its historical numbers above are not a baseline
for this revision. `benchmark-project` runs nine cases: 1/16/64 tracks,
64/1,024/4,096 stored notes, 16/256/1,024 points and 31/128/1,024-frame buffers.
Two long notes per first 16 tracks remain audible. Other notes are scheduled
later to remain within the 32-voice plan limit. The position wraps every 96,000
samples to keep long runs active. Future notes exercise storage/preparation and
bounded scans rather than additional simultaneous synthesis. Each track has
16 gain points; graph processing uses the same 64-node chain in every case.
The graph matrix separately scales nodes and chain connections from 2 to 256.
These synthetic cases do not qualify every possible dense graph or plugin chain.
```sh
make benchmark benchmark-project
make benchmark-compare
make benchmark-project-compare
# Baselines must match the current CPU/compiler/flags and workload.
make benchmark-project-compare PROJECT_BENCHMARK_BASELINE=/path/to/report.json
./build/test_performance 10000 64 128
make test-benchmark-tools
```
Both matrices report wall-clock mean/p99/max processing duration and the count
of measured calls exceeding frames/sample-rate. These are offline deadline
exceedances, not actual JACK xruns: there is no server scheduling in the timing
loop. Graph compilation or project construction/preparation is timed separately.
`process_cpu_ms` measures CLOCK_PROCESS_CPUTIME_ID over the complete measured
loop, including timing and finite-output checks; it excludes preparation and
sorting. Project `cpu_audio_ratio` divides that CPU time by simulated audio time.
`peak_rss_kib` is Linux getrusage process high-water RSS, including model, plans,
measurement storage and executable/runtime overhead; it is not current heap size
or a leak test. Graph buffer bytes remain a separate exact buffer-size estimate.
Timing probes, memory queries, sorting and output occur outside engine calls.
Checked-in `project-performance-baseline.json` provides initial project cases;
the original graph baseline is retained. `graph-performance-phase29.json` adds
a current graph report with CPU/RSS/deadline fields. Gates use the existing
1.5x mean-time budget and 1 us noise allowance, with p99/max/misses and memory
reported for investigation. There is no universal hardware-independent deadline
or RSS pass threshold. `test-benchmark-tools` verifies same-context success,
regression rejection, missing cases and host/workload mismatch without relying
on machine timing. Do not replace a failing baseline without investigating.
## Endurance, faults and callback audit
```sh
make test-soak test-stress test-stress-plugins
make test-stress STRESS_ROUNDS=10
./build/test_soak 10000000
make check-development
```
`test-soak` renders exactly 1,000,000 alternating 31/128/1,024-frame stereo
blocks: 2.282 hours of virtual 48 kHz audio. It checks every output sample,
processed block counts and final publication acknowledgement, with 9,999
quiescent position/rebuild cycles. It runs faster than wall time and models
position wrap/seek and restart publication; it is not a real device start/stop
or hardware endurance test. The project benchmark separately wraps active MIDI.
`test-stress` defaults to three rounds under two ordinary CPU workers. Each round
runs concurrent publication, allocation/lifetime guards, maximum model capacity,
project relocation/reload and missing-media retention, save-fault diagnostics,
and the soak test. With JACK headers present it also repeats the deterministic
backend fake's start/stop/seek, rate/buffer/server-loss and failure/retry cases.
Optional GUI tests run after those rounds under the same CPU load.
`test-stress-plugins` adds the original LADSPA fixture's identity/layout/range,
instantiation-error and invalid-metadata cases each round; it needs LADSPA headers.
No command changes a physical device, kills the shared server or loads unknown
plugins. Subprocess deadlines bound each test and workers are cleaned up on exit.
The reliability executable now interposes fopen/fread/fwrite/read/write,
pthread_mutex_lock and pthread_cond_wait in addition to malloc/calloc/realloc/free.
Guarded host graph/realtime render calls fail immediately on these operations.
This complements the existing native lifetime and plugin callback guards and
control/callback ownership review in RELIABILITY.md. It does not intercept every
libc entry point, raw syscalls, hidden dynamic-module calls, or GUI code by magic;
third-party DSP remains trusted. No known host callback safety violation was found.
`check-development` combines the ordinary build/tests, capacity/soak checks,
benchmark gate tests, static analysis and ASan/UBSan. The sanitizer target now
includes maximum capacity and virtual endurance. These are opt-in developer
checks requiring installed Clang/Python; no runtime dependency was added.
Sanitized/contended/profiled runs must not become timing baselines.
## Profiling evidence and remaining costs
Before considering DSP changes, Phase 29 sampled a 10,000-block, 64-track/128-frame
project with GCC `-O2 -g -pg` and GNU gprof on the documented baseline host.
Flat samples attributed about 30% to mixer automation `value`, 29% to MIDI
`segment`, and 11% to finite-value handling. Instrumentation and inlining affect
attribution; this identifies investigation candidates, not exact production
cost or evidence that checks should be removed. MIDI scans bounded stored-note
arrays and evaluates per-voice, per-sample gain/pan lanes. No DSP optimization
was introduced without a separate correctness/performance justification.
Reproduce in an isolated build (GNU gprof must already be installed):
```sh
make BUILD_DIR=build/profile CFLAGS='-O2 -g -pg -std=c99 -Iinclude' LDFLAGS=-pg build/profile/test_performance
GMON_OUT_PREFIX="$PWD/build/profile/gmon" ./build/profile/test_performance 10000 64 128
gprof build/profile/test_performance build/profile/gmon.* > build/profile/profile.txt
```
Remaining limits include per-sample LADSPA automation run(1), stored-note/clip
scans, preloaded WAV memory and immutable-plan/history overlap. This phase does
not qualify physical-device changes, arbitrary plugin hangs/crashes, multi-hour
wall-clock sessions or GUI redraw latency. Virtual endurance and deterministic
faults provide repeatable software evidence, not a hard realtime guarantee.
Phase 29 observed results (same Threadripper/GCC host, 300 blocks per case):
64-track/128-frame project mean 380.417 us, p99 720.271 us, prepare 11.841 ms,
CPU/audio .142 and peak process RSS 19,296 KiB. The 256-node stereo/128 graph
mean was 286.398 us, p99 484.712 us, compile .300 ms. These case runs observed
zero deadline exceedances. See JSON for all cases and host metadata.
The project comparison passed. Repeated graph comparisons flagged variable
small cases despite unchanged graph processing code; a 3,000-block run against
the retained Phase 19 baseline still flagged 16-node mono/31-frame mean 5.089 us
above its 1.5x budget. The new graph report is evidence, not a replacement chosen
to make that comparison pass. This shared-host timing alert remains an
investigation item; no CPU/latency guarantee is inferred from the correctness
suite. Longer comparisons can use `BENCHMARK_BLOCKS=3000`.

View file

@ -125,3 +125,13 @@ Collection acquires completion and deactivates the backend before resetting
voices/flags. A completed callback continues silence/holds position until that
deactivation. No callback waits or calls JACK control functions. Immediate
stop/close handles faults or missing callbacks. See AUDIO_QUALITY.md.
## Phase 29 repeatable development checks
`make check-development` combines normal tests, capacity/endurance, deterministic
benchmark-gate tests, static analysis and ASan/UBSan (including scale and soak).
`make test-stress` repeats project/backend/publication faults under CPU contention;
`make test-stress-plugins` adds the original LADSPA failure fixture. The reliability
callback guard now also rejects common host file I/O and blocking mutex/condition
calls. It audits directly linked host code, not arbitrary dynamic-plugin internals.
See PERFORMANCE.md for exact workloads, metrics, profiles and qualification limits.

View file

@ -808,6 +808,21 @@ Establish measurable performance expectations and verify that larger projects re
- No known real-time safety violation remains in the engine's own callback path.
- Performance regressions can be detected by repeatable tests or benchmark reports.
### Implementation status
Implemented with the existing graph/capacity/fault infrastructure plus Phase 29
project scaling matrices, CPU/RSS/deadline metrics, checked-in reports, virtual
endurance, repeated reload/device/plugin fault suites, wider host callback guards
and a combined development/sanitizer/static-analysis target. See PERFORMANCE.md
for exact workloads, profiling evidence and qualification limits.
Validation: normal core/GUI/JACK/plugin/recovery/recording suites, three-round
CPU-contention stress, 2.282-hour virtual playback, minimal build, ASan/UBSan,
static analysis and benchmark-gate regression tests passed. Project timing
comparison passed. Graph comparisons detect shared-host variation (including a
16-node mono/31-frame alert in a longer run); the prior baseline is retained and
this limitation is recorded rather than suppressing the gate. Hardware and
wall-clock endurance remain unqualified.
## Phase 30 — Release Engineering, Packaging, and Maintenance
### Goal

View file

@ -0,0 +1,422 @@
{
"schema": 1,
"context": {
"cpu": "AMD Ryzen Threadripper 1920X 12-Core Processor",
"architecture": "x86_64",
"compiler": "cc (GCC) 16.2.1 20260810",
"flags": "-O2 -g -std=c99 -Wall -Wextra -Wpedantic -Wconversion -Wshadow -Iinclude",
"kernel": "7.2.11-artix1-1",
"scheduler": "ordinary process; no realtime scheduling",
"workload": "graph"
},
"cases": [
{
"nodes": 2,
"channels": 1,
"rate": 44100,
"frames": 31,
"blocks": 300,
"compile_ms": 0.003657,
"mean_us": 0.357413,
"p99_us": 0.421001,
"max_us": 0.721004,
"deadline_us": 702.947846,
"load": 0.000508,
"graph_buffer_bytes": 496,
"deadline_misses": 0,
"process_cpu_ms": 0.12127,
"peak_rss_kib": 19308
},
{
"nodes": 2,
"channels": 1,
"rate": 48000,
"frames": 128,
"blocks": 300,
"compile_ms": 0.005571,
"mean_us": 1.303103,
"p99_us": 1.363005,
"max_us": 1.512992,
"deadline_us": 2666.666667,
"load": 0.000489,
"graph_buffer_bytes": 2048,
"deadline_misses": 0,
"process_cpu_ms": 0.424738,
"peak_rss_kib": 19308
},
{
"nodes": 2,
"channels": 1,
"rate": 96000,
"frames": 1024,
"blocks": 300,
"compile_ms": 0.033223,
"mean_us": 23.244337,
"p99_us": 34.926998,
"max_us": 36.950005,
"deadline_us": 10666.666667,
"load": 0.002179,
"graph_buffer_bytes": 16384,
"deadline_misses": 0,
"process_cpu_ms": 7.388398,
"peak_rss_kib": 19308
},
{
"nodes": 2,
"channels": 2,
"rate": 44100,
"frames": 31,
"blocks": 300,
"compile_ms": 0.005841,
"mean_us": 1.71521,
"p99_us": 2.685993,
"max_us": 11.882992,
"deadline_us": 702.947846,
"load": 0.00244,
"graph_buffer_bytes": 496,
"deadline_misses": 0,
"process_cpu_ms": 0.54705,
"peak_rss_kib": 19308
},
{
"nodes": 2,
"channels": 2,
"rate": 48000,
"frames": 128,
"blocks": 300,
"compile_ms": 0.008015,
"mean_us": 4.814904,
"p99_us": 9.418,
"max_us": 14.648002,
"deadline_us": 2666.666667,
"load": 0.001806,
"graph_buffer_bytes": 2048,
"deadline_misses": 0,
"process_cpu_ms": 1.505184,
"peak_rss_kib": 19308
},
{
"nodes": 2,
"channels": 2,
"rate": 96000,
"frames": 1024,
"blocks": 300,
"compile_ms": 0.011121,
"mean_us": 22.629783,
"p99_us": 31.78,
"max_us": 39.103994,
"deadline_us": 10666.666667,
"load": 0.002122,
"graph_buffer_bytes": 16384,
"deadline_misses": 0,
"process_cpu_ms": 7.04282,
"peak_rss_kib": 19308
},
{
"nodes": 16,
"channels": 1,
"rate": 44100,
"frames": 31,
"blocks": 300,
"compile_ms": 0.024256,
"mean_us": 5.00722,
"p99_us": 9.327996,
"max_us": 16.952996,
"deadline_us": 702.947846,
"load": 0.007123,
"graph_buffer_bytes": 3968,
"deadline_misses": 0,
"process_cpu_ms": 1.512578,
"peak_rss_kib": 19308
},
{
"nodes": 16,
"channels": 1,
"rate": 48000,
"frames": 128,
"blocks": 300,
"compile_ms": 0.040657,
"mean_us": 8.499017,
"p99_us": 15.569996,
"max_us": 19.628002,
"deadline_us": 2666.666667,
"load": 0.003187,
"graph_buffer_bytes": 16384,
"deadline_misses": 0,
"process_cpu_ms": 2.57139,
"peak_rss_kib": 19308
},
{
"nodes": 16,
"channels": 1,
"rate": 96000,
"frames": 1024,
"blocks": 300,
"compile_ms": 0.017684,
"mean_us": 73.465867,
"p99_us": 110.88101,
"max_us": 123.875987,
"deadline_us": 10666.666667,
"load": 0.006887,
"graph_buffer_bytes": 131072,
"deadline_misses": 0,
"process_cpu_ms": 22.071262,
"peak_rss_kib": 19308
},
{
"nodes": 16,
"channels": 2,
"rate": 44100,
"frames": 31,
"blocks": 300,
"compile_ms": 0.024356,
"mean_us": 7.90933,
"p99_us": 16.942999,
"max_us": 19.336992,
"deadline_us": 702.947846,
"load": 0.011252,
"graph_buffer_bytes": 3968,
"deadline_misses": 0,
"process_cpu_ms": 2.387202,
"peak_rss_kib": 19308
},
{
"nodes": 16,
"channels": 2,
"rate": 48000,
"frames": 128,
"blocks": 300,
"compile_ms": 0.02095,
"mean_us": 18.307943,
"p99_us": 38.874001,
"max_us": 49.833994,
"deadline_us": 2666.666667,
"load": 0.006865,
"graph_buffer_bytes": 16384,
"deadline_misses": 0,
"process_cpu_ms": 5.482221,
"peak_rss_kib": 19308
},
{
"nodes": 16,
"channels": 2,
"rate": 96000,
"frames": 1024,
"blocks": 300,
"compile_ms": 0.018595,
"mean_us": 142.5079,
"p99_us": 200.170995,
"max_us": 206.372002,
"deadline_us": 10666.666667,
"load": 0.01336,
"graph_buffer_bytes": 131072,
"deadline_misses": 0,
"process_cpu_ms": 42.820019,
"peak_rss_kib": 19308
},
{
"nodes": 64,
"channels": 1,
"rate": 44100,
"frames": 31,
"blocks": 300,
"compile_ms": 0.077537,
"mean_us": 8.674007,
"p99_us": 13.575991,
"max_us": 25.628004,
"deadline_us": 702.947846,
"load": 0.012339,
"graph_buffer_bytes": 15872,
"deadline_misses": 0,
"process_cpu_ms": 2.598515,
"peak_rss_kib": 19308
},
{
"nodes": 64,
"channels": 1,
"rate": 48000,
"frames": 128,
"blocks": 300,
"compile_ms": 0.123505,
"mean_us": 67.732122,
"p99_us": 102.083999,
"max_us": 104.92999,
"deadline_us": 2666.666667,
"load": 0.0254,
"graph_buffer_bytes": 65536,
"deadline_misses": 0,
"process_cpu_ms": 20.251813,
"peak_rss_kib": 19308
},
{
"nodes": 64,
"channels": 1,
"rate": 96000,
"frames": 1024,
"blocks": 300,
"compile_ms": 0.120299,
"mean_us": 348.007127,
"p99_us": 606.123009,
"max_us": 754.726003,
"deadline_us": 10666.666667,
"load": 0.032626,
"graph_buffer_bytes": 524288,
"deadline_misses": 0,
"process_cpu_ms": 103.942768,
"peak_rss_kib": 19308
},
{
"nodes": 64,
"channels": 2,
"rate": 44100,
"frames": 31,
"blocks": 300,
"compile_ms": 0.06793,
"mean_us": 18.297367,
"p99_us": 27.101996,
"max_us": 35.546997,
"deadline_us": 702.947846,
"load": 0.026029,
"graph_buffer_bytes": 15872,
"deadline_misses": 0,
"process_cpu_ms": 5.478211,
"peak_rss_kib": 19308
},
{
"nodes": 64,
"channels": 2,
"rate": 48000,
"frames": 128,
"blocks": 300,
"compile_ms": 0.124016,
"mean_us": 90.302024,
"p99_us": 158.481998,
"max_us": 163.279998,
"deadline_us": 2666.666667,
"load": 0.033863,
"graph_buffer_bytes": 65536,
"deadline_misses": 0,
"process_cpu_ms": 27.01664,
"peak_rss_kib": 19308
},
{
"nodes": 64,
"channels": 2,
"rate": 96000,
"frames": 1024,
"blocks": 300,
"compile_ms": 0.103767,
"mean_us": 651.941917,
"p99_us": 939.527992,
"max_us": 1111.795005,
"deadline_us": 10666.666667,
"load": 0.06112,
"graph_buffer_bytes": 524288,
"deadline_misses": 0,
"process_cpu_ms": 194.780424,
"peak_rss_kib": 19308
},
{
"nodes": 256,
"channels": 1,
"rate": 44100,
"frames": 31,
"blocks": 300,
"compile_ms": 0.393599,
"mean_us": 36.277767,
"p99_us": 61.768005,
"max_us": 69.022004,
"deadline_us": 702.947846,
"load": 0.051608,
"graph_buffer_bytes": 63488,
"deadline_misses": 0,
"process_cpu_ms": 10.8528,
"peak_rss_kib": 19308
},
{
"nodes": 256,
"channels": 1,
"rate": 48000,
"frames": 128,
"blocks": 300,
"compile_ms": 0.316512,
"mean_us": 155.434897,
"p99_us": 279.041007,
"max_us": 334.977012,
"deadline_us": 2666.666667,
"load": 0.058288,
"graph_buffer_bytes": 262144,
"deadline_misses": 0,
"process_cpu_ms": 46.467151,
"peak_rss_kib": 19308
},
{
"nodes": 256,
"channels": 1,
"rate": 96000,
"frames": 1024,
"blocks": 300,
"compile_ms": 0.474884,
"mean_us": 1246.40406,
"p99_us": 2426.396997,
"max_us": 2940.154998,
"deadline_us": 10666.666667,
"load": 0.11685,
"graph_buffer_bytes": 2097152,
"deadline_misses": 0,
"process_cpu_ms": 371.849272,
"peak_rss_kib": 19308
},
{
"nodes": 256,
"channels": 2,
"rate": 44100,
"frames": 31,
"blocks": 300,
"compile_ms": 0.573331,
"mean_us": 86.74766,
"p99_us": 192.195992,
"max_us": 197.79701,
"deadline_us": 702.947846,
"load": 0.123406,
"graph_buffer_bytes": 63488,
"deadline_misses": 0,
"process_cpu_ms": 25.90803,
"peak_rss_kib": 19308
},
{
"nodes": 256,
"channels": 2,
"rate": 48000,
"frames": 128,
"blocks": 300,
"compile_ms": 0.29951,
"mean_us": 286.398197,
"p99_us": 484.712,
"max_us": 567.41001,
"deadline_us": 2666.666667,
"load": 0.107399,
"graph_buffer_bytes": 262144,
"deadline_misses": 0,
"process_cpu_ms": 85.605838,
"peak_rss_kib": 19308
},
{
"nodes": 256,
"channels": 2,
"rate": 96000,
"frames": 1024,
"blocks": 300,
"compile_ms": 0.301544,
"mean_us": 2379.64819,
"p99_us": 4935.191013,
"max_us": 5069.556006,
"deadline_us": 10666.666667,
"load": 0.223092,
"graph_buffer_bytes": 2097152,
"deadline_misses": 0,
"process_cpu_ms": 709.538479,
"peak_rss_kib": 19308
}
]
}

View file

@ -0,0 +1,185 @@
{
"schema": 1,
"context": {
"cpu": "AMD Ryzen Threadripper 1920X 12-Core Processor",
"architecture": "x86_64",
"compiler": "cc (GCC) 16.2.1 20260810",
"flags": "-O2 -g -std=c99 -Wall -Wextra -Wpedantic -Wconversion -Wshadow -Iinclude",
"kernel": "7.2.11-artix1-1",
"scheduler": "ordinary process; no realtime scheduling",
"workload": "project"
},
"cases": [
{
"tracks": 1,
"notes": 64,
"points": 16,
"nodes": 64,
"rate": 48000,
"frames": 31,
"blocks": 300,
"wraps": 0,
"prepare_ms": 2.037527,
"mean_us": 22.432314,
"p99_us": 37.752005,
"max_us": 41.168008,
"deadline_us": 645.833333,
"deadline_misses": 0,
"process_cpu_ms": 6.710229,
"cpu_audio_ratio": 0.034633,
"peak_rss_kib": 19296
},
{
"tracks": 1,
"notes": 64,
"points": 16,
"nodes": 64,
"rate": 48000,
"frames": 128,
"blocks": 300,
"wraps": 0,
"prepare_ms": 3.156677,
"mean_us": 136.447411,
"p99_us": 266.878007,
"max_us": 339.576,
"deadline_us": 2666.666667,
"deadline_misses": 0,
"process_cpu_ms": 40.746385,
"cpu_audio_ratio": 0.050933,
"peak_rss_kib": 19296
},
{
"tracks": 1,
"notes": 64,
"points": 16,
"nodes": 64,
"rate": 48000,
"frames": 1024,
"blocks": 300,
"wraps": 3,
"prepare_ms": 3.142049,
"mean_us": 853.354273,
"p99_us": 1651.11199,
"max_us": 1777.513011,
"deadline_us": 21333.333333,
"deadline_misses": 0,
"process_cpu_ms": 254.818128,
"cpu_audio_ratio": 0.039815,
"peak_rss_kib": 19296
},
{
"tracks": 16,
"notes": 1024,
"points": 256,
"nodes": 64,
"rate": 48000,
"frames": 31,
"blocks": 300,
"wraps": 0,
"prepare_ms": 5.05565,
"mean_us": 94.302404,
"p99_us": 186.395002,
"max_us": 235.758998,
"deadline_us": 645.833333,
"deadline_misses": 0,
"process_cpu_ms": 28.104842,
"cpu_audio_ratio": 0.145057,
"peak_rss_kib": 19296
},
{
"tracks": 16,
"notes": 1024,
"points": 256,
"nodes": 64,
"rate": 48000,
"frames": 128,
"blocks": 300,
"wraps": 0,
"prepare_ms": 5.312168,
"mean_us": 386.378117,
"p99_us": 692.126996,
"max_us": 694.069997,
"deadline_us": 2666.666667,
"deadline_misses": 0,
"process_cpu_ms": 115.256236,
"cpu_audio_ratio": 0.14407,
"peak_rss_kib": 19296
},
{
"tracks": 16,
"notes": 1024,
"points": 256,
"nodes": 64,
"rate": 48000,
"frames": 1024,
"blocks": 300,
"wraps": 3,
"prepare_ms": 5.224572,
"mean_us": 2722.953837,
"p99_us": 4571.800004,
"max_us": 4690.454996,
"deadline_us": 21333.333333,
"deadline_misses": 0,
"process_cpu_ms": 812.60835,
"cpu_audio_ratio": 0.12697,
"peak_rss_kib": 19296
},
{
"tracks": 64,
"notes": 4096,
"points": 1024,
"nodes": 64,
"rate": 48000,
"frames": 31,
"blocks": 300,
"wraps": 0,
"prepare_ms": 11.86645,
"mean_us": 144.810444,
"p99_us": 352.410992,
"max_us": 373.500996,
"deadline_us": 645.833333,
"deadline_misses": 0,
"process_cpu_ms": 41.640344,
"cpu_audio_ratio": 0.214918,
"peak_rss_kib": 19296
},
{
"tracks": 64,
"notes": 4096,
"points": 1024,
"nodes": 64,
"rate": 48000,
"frames": 128,
"blocks": 300,
"wraps": 0,
"prepare_ms": 11.841152,
"mean_us": 380.41659,
"p99_us": 720.271011,
"max_us": 826.122006,
"deadline_us": 2666.666667,
"deadline_misses": 0,
"process_cpu_ms": 113.546659,
"cpu_audio_ratio": 0.141933,
"peak_rss_kib": 19296
},
{
"tracks": 64,
"notes": 4096,
"points": 1024,
"nodes": 64,
"rate": 48000,
"frames": 1024,
"blocks": 300,
"wraps": 3,
"prepare_ms": 12.183272,
"mean_us": 2766.193183,
"p99_us": 3645.336998,
"max_us": 4391.266004,
"deadline_us": 21333.333333,
"deadline_misses": 0,
"process_cpu_ms": 825.19931,
"cpu_audio_ratio": 0.128937,
"peak_rss_kib": 19296
}
]
}