Skip to content

benchmarking: add SLO-knee throughput post-processor - #883

Open
Alex Bulankou (AlexBulankou) wants to merge 1 commit into
agent-substrate:mainfrom
AlexBulankou:a4s1/benchmarking-slo-knee-postproc
Open

benchmarking: add SLO-knee throughput post-processor#883
Alex Bulankou (AlexBulankou) wants to merge 1 commit into
agent-substrate:mainfrom
AlexBulankou:a4s1/benchmarking-slo-knee-postproc

Conversation

@AlexBulankou

@AlexBulankou Alex Bulankou (AlexBulankou) commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Pure-stdlib post-processor over runner.py's stats.jsonl. For each gRPC op in a build tag's concurrency sweep it computes the SLO-knee throughput: the max sustained RPS among sweep points whose chosen latency percentile stays under a ceiling AND whose failure ratio is within tolerance. Past the knee, offered load keeps climbing but latency has blown past the SLO, so that extra throughput isn't usable capacity.

Gives the sweep a single honest "throughput @ pXX<SLO" number per op (e.g. --ceiling-ms 1000 / 5000) instead of eyeballing stats_history.csv.

Offline-only: benchmarking/analysis/ ships tests + 3 synthetic stats.jsonl fixtures — python3 -m pytest analysis/ -q runs 18/18 with no cluster.

Note: the fixtures are the repo's first .jsonl files, so this also adds .jsonl to the data-extension exemption in hack/util/verify-boilerplate.py (alongside .json) — verify-all.sh runs clean with it.

Compute throughput-at-SLO-knee from a concurrency sweep of locust runs.
For each op (Type_Name) in a build tag's sweep, the knee is the maximum
sustained RPS among sweep points whose chosen latency percentile stays
under a ceiling AND whose failure ratio is within tolerance. This maps
directly onto the spec-doc substrate-row throughput axes (@<1s / @<5s ==
--ceiling-ms 1000 / 5000) with p50/p95 read straight off each point.

- Pure stdlib over runner.py's stats.jsonl schema (no locust/pandas/numpy),
  so it runs offline over saved run artifacts.
- Offered concurrency (-u user count) is absent from stats.jsonl; the knee
  is computed from (rps, latency) pairs and does not need it. Supplying a
  name->users map via --users-by-name / --tests-yaml labels each point's
  concurrency so the knee's location is interpretable.
- Failure-ratio guard (default <=1%) prevents a fast-failing high-RPS run
  from being selected as usable capacity.
- 18 unit tests + synthetic stats.jsonl fixtures (clean ceiling-crossing
  sweep, fast-failing exclusion, SLO-never-met, percentile normalization,
  multi-metric grouping, CLI e2e). Runnable via pytest or a built-in stdlib
  runner (no pytest dependency required).

Signed-off-by: Alex Bulankou <alexbu@google.com>
@a4-a4s1
a4-a4s1 Bot force-pushed the a4s1/benchmarking-slo-knee-postproc branch from 281e4ee to e41255f Compare August 12, 2026 09:15
@AlexBulankou

Copy link
Copy Markdown
Collaborator Author

Design question from exercising this against live sweep output: slo_knee.py requires an external name→users map (--users-by-name / --tests-yaml) because stats.jsonl doesn't carry offered concurrency. An alternative: an in-band per-entry users field stamped by runner.py at write time, with record_to_point preferring it and falling back to the external map — drops the analysis-time tests.yaml dependency and makes each stats line self-describing. If you'd prefer in-band, I can send that as a small follow-up (runner.py stamp + the fallback here); if the external-map design is deliberate to keep the stats.jsonl schema stable, this stands as-is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant