This document tracks runtime and SDK benchmark coverage for Sovereign-Mohawk and explains how to reproduce and compare benchmark outputs.
- Python SDK regression gate (
pytest-benchmark) in.github/workflows/performance-gate.yml - Go runtime FedAvg aggregation matrix (
BenchmarkAggregateParallel) intest/accelerator_test.go - Base-vs-current FedAvg benchmark comparison report generated by
scripts/benchmark_fedavg_compare.sh - Bridge JSON-vs-zero-copy compression benchmark comparison generated by
scripts/benchmark_bridge_compression_compare.sh
| Surface | Default Parameters | Notes |
|---|---|---|
| FedAvg base-vs-current compare | BASE_REF=origin/main, BENCH_TIME=300ms, BENCH_COUNT=10, BENCH_CPU=2, USE_BENCHSTAT=always, BENCHSTAT_ALPHA=0.01 |
Fails if expected benchmark symbol BenchmarkAggregateParallel/ is missing in base or current output. |
| Bridge format compare | BENCH_TIME=200ms, BENCH_COUNT=5, BENCH_CPU=2, BENCHSTAT_ALPHA=0.01 |
JSON vs zero-copy on same commit; PR regression compares against cached main baseline. |
| Python SDK gate | pytest-benchmark JSON artifact plus absolute and optional trend checks |
Trend checks compare against cached main baseline when available. |
| Gate | Threshold | Fail Behavior |
|---|---|---|
| FedAvg PR regression | +5.0% geomean time regression |
Fails on threshold breach, missing baseline cache, or unparsable geomean delta. |
| Bridge PR regression | +5.0% geomean time regression |
Fails on threshold breach, missing baseline cache, or unparsable geomean delta. |
| Python SDK absolute | Per-benchmark mean/p99 limits in .github/workflows/performance-gate.yml |
Fails on any threshold breach or missing expected benchmarks. |
| Python SDK trend | PY_PERF_MEAN_DELTA_MAX_PCT=10.0, PY_PERF_P99_DELTA_MAX_PCT=15.0 |
Fails on regression breach when baseline exists; logs skip when baseline is not available. |
The FedAvg microbenchmark matrix currently includes:
- Workloads:
clients32_dim2048clients128_dim4096clients256_dim8192clients512_dim8192
- Worker configurations:
workers1workers2workers4workers8workersAuto
workersAuto resolves through ResolveAggregateWorkers(...) in internal/accelerator/aggregate.go, which uses single-worker fallback on small reductions and parallel worker selection for larger workloads.
Representative result trends from the current benchmark run:
- Small workload (
32x2048): single worker orworkersAutois typically fastest due to parallel overhead. - Medium/large workloads (
128x4096and above): multi-worker andworkersAutomaterially improve throughput. - High workload (
512x8192): parallel paths substantially outperformworkers1in typical runs.
This is expected behavior for reduction-heavy workloads where synchronization overhead dominates at small tensor sizes but amortizes at higher element counts.
A live stress capture was executed on a running full stack with temporary stress
node agents (node-agent-stress-4 through node-agent-stress-10) over a
10-minute scope using 3 windows of 200 seconds each.
Artifacts:
results/metrics/stress_metrics_capture_10m.jsonresults/metrics/stress_metrics_capture_10m.md
Highlights from the 10-minute capture:
bridge_totaldelta:+60(mean rate0.100/s)proof_totaldelta:+120(mean rate0.200/s)hybrid_proof_totaldelta:+60(mean rate0.100/s)accel_ops_totaldelta:+240(mean rate0.400/s)accel_gradient_submit_success_totaldelta:+60accel_gradient_submit_failure_totaldelta:0
Resource snapshot during stress run showed low utilization headroom remained
available (for example, orchestrator ~1.45% CPU and ~51.46 MiB memory in
the sampled interval).
cd sdk/python
python -m pytest tests/test_benchmarks.py --benchmark-only -qTOOLROOT=/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.25.9.linux-amd64 \
GOROOT=$TOOLROOT PATH=$TOOLROOT/bin:$PATH GOTOOLCHAIN=local \
go test ./test -run '^$' -bench BenchmarkAggregateParallel -benchmem -benchtime=300ms -count=10 -cpu=2TOOLROOT=/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.25.9.linux-amd64 \
BASE_REF=origin/main BENCH_TIME=300ms BENCH_COUNT=10 \
BENCH_CPU=2 \
USE_BENCHSTAT=always BENCHSTAT_ALPHA=0.01 \
REPORT_PATH=results/metrics/fedavg_benchmark_compare.md \
./scripts/benchmark_fedavg_compare.shThis enforces benchstat output and uses a stricter significance threshold (alpha=0.01).
# Full stack should already be running.
for i in 4 5 6 7 8 9 10; do
docker rm -f node-agent-stress-$i >/dev/null 2>&1 || true
docker compose run -d --no-deps --name node-agent-stress-$i \
-e NODE_ID=node-stress-$i \
-e MOHAWK_LIBP2P_PORT=$((4100+i)) \
node-agent-1 >/dev/null
done
# Capture script path used in this run:
python3 - <<'PY'
print('See results/metrics/stress_metrics_capture_10m.json and .md artifacts from captured run')
PY
# Cleanup temporary stress agents.
for i in 4 5 6 7 8 9 10; do
docker rm -f node-agent-stress-$i >/dev/null 2>&1 || true
doneBENCH_TIME=200ms REPORT_PATH=results/metrics/bridge_compression_benchmark_compare.md \
BENCH_COUNT=5 BENCH_CPU=2 BENCHSTAT_ALPHA=0.01 \
./scripts/benchmark_bridge_compression_compare.shThis benchmark report compares JSON vs zero-copy serialization formats on the same commit. It is not a base-ref regression report.
- Python performance artifact:
benchmark-results.json(uploaded by.github/workflows/performance-gate.yml)
- FedAvg comparison artifact:
results/metrics/fedavg_benchmark_compare.md(uploaded by.github/workflows/fedavg-benchmark-compare.yml)- Baseline source in CI: cached
mainbenchmark output (fedavg-main-*cache key prefix) and artifactfedavg-baseline-main
- Bridge compression comparison artifacts:
results/metrics/bridge_compression_benchmark_compare.mdresults/metrics/bridge_compression_benchmark_raw.txt- PR regression artifact:
results/metrics/bridge_compression_regression_compare.md - Baseline source in CI: cached
mainraw benchmark output (bridge-main-*cache key prefix) and artifactbridge-baseline-main
- Extended live stress capture artifacts:
results/metrics/stress_metrics_capture_10m.jsonresults/metrics/stress_metrics_capture_10m.md
- If benchmark symbols are missing from either base or current FedAvg runs,
scripts/benchmark_fedavg_compare.shfails fast with an explicit error. - For stable trend analysis, run with
BENCH_COUNT>=3and compare medians across runs.