Software & TechnicalFree
Load Test Report Template Against SLOs
River checks whether the run could measure the claim, then converts what survives into error budget spent at the traffic you are actually planning for.
River does two things before it writes a number down. It asks whether the run could have measured the thing you want to know, which most runs cannot. Then it converts everything surviving that check into error budget spent at the traffic volume you are planning for. A 99th percentile of two seconds is not a result and never was. Two seconds across the on-sale you have already scheduled, priced against the budget your objective gives you for the month, is a decision somebody can sign.
Alderhay sells tickets. Its new checkout service was tested three weeks before a stadium on-sale and came back with a 99th percentile of 2,180 milliseconds, which nobody in the launch meeting could act on. Converted, the 90 minutes of that on-sale spends 29.5 percent of the month's availability budget and 26.6 percent of its latency budget. There are four on-sales inside the same window. That is 118 percent and 106 percent, both gone before a single unplanned incident.
Built for the engineer who ran the test and the person who has to sign the launch off. Run it before a peak event, before a migration, or against the regression run your pipeline produces and nobody opens. The targets it reports against come from the SLO and error budget pack. Whether production would even tell you the budget was burning is the monitoring coverage review, and the capacity a fix needs gets priced in the cloud cost analysis.
Three reasons the numbers are not evidence yet
Most generators hold virtual users rather than a request rate, and that decides what the run measured. The k6 documentation is explicit that in a closed model a new iteration starts only once the last one finishes, so a six-second response from one user yields ten requests a minute and no more. Offered load falls exactly when the system slows. Alderhay sized 600 users off a smoke test averaging 667 milliseconds and expected 900 requests a second. Under load the mean reached 1.34 seconds, so the run delivered 448.
The requests a stall prevents are never sent, so they are never timed. Gil Tene's wrk2 states the mechanism plainly: because each connection only sends again once a response arrives, high latency responses have the load generator coordinating with the server to avoid measuring the slow period. Alderhay stalled for 14 seconds at minute 11. At the planned rate that is 12,600 arrivals nobody made, 6,300 of them waiting over seven seconds. The run recorded 537,600 requests, so its whole top percentile is 5,376.
Then the headline number itself. Prometheus documents why quantiles cannot be aggregated, since a total 90th percentile for a service spread over replicated workers is not recoverable from each worker's own. Alderhay's 2,180 milliseconds was the mean of twenty per-minute figures across twelve pods. Merged properly it is 3,410, and even that is a floor. The SRE Workbook puts the budget it gets spent against at one hundred percent minus the objective, which is what turns a millisecond into a decision.
How it works
Bring the run
Raw output from k6, Gatling, JMeter or Locust, plus how the load itself was shaped.
State the targets
The objectives, the window they are measured over, and the request volume that window carries.
Forecast the event
The traffic you are actually planning for, segment by segment, with the rate in each.
Read the verdict
What each segment spends, where the ceiling is, and what changes before anyone launches.
What you get
- Every surviving number converted into error budget spent at the traffic you are planning for
- A validity verdict per scenario, so a run that could not measure the claim says so first
- Achieved request rate recomputed from virtual users and iteration time, not read off the label
- Requests the stalls omitted, counted and set beside the size of the run's top percentile
- Percentiles rebuilt from merged histograms rather than averaged across workers and minutes
- The bottleneck traced to a named resource limit, with the number that would clear it
- Headroom stated as the traffic multiple at which your first objective breaks
Common questions
The test passed. Why is the answer no?
Because it passed against nothing. Alderhay's run cleared every threshold in its own report and still spends 118 percent of the month's availability budget across four scheduled on-sales. A threshold somebody typed into a test script is not a commitment. The budget is, and it is the only number the launch decision actually turns on.
We do not have objectives to report against.
Then the first output is a proposed set, derived from what the service already does on an ordinary week and what its traffic profile can support, flagged as proposed rather than agreed. Getting them agreed and owned is a separate exercise, which the SLO and error budget pack runs. The report is honest about depending on that.
How can you say the test only reached 448 requests a second?
Arithmetic on the run's own output. Fixed virtual users divided by mean iteration duration is the rate the generator can produce, and 600 over 1.34 seconds is 448. Alderhay sized those 600 users from a smoke test where the mean was 667 milliseconds, which is where the 900 came from. The system slowed and the load followed it down.
Our generator already reports the 99th percentile.
It reports one per worker per interval, and the dashboard above it usually averages them. That is not a percentile of anything. Alderhay's 2,180 milliseconds became 3,410 once the raw histograms were merged across all twelve pods and the full window, and 1,230 milliseconds is the difference between clearing a target and missing it.
We tested in staging, which is smaller than production.
Then the report says so and scales what can be scaled, which is throughput against a stated resource ratio, not tail latency. Alderhay's finding survives the difference because it is a pool arithmetic result: 240 connections held for 0.52 seconds each is a ceiling of 462 requests a second, and the plan needs 900 on the same code. That ceiling is what a capacity plan triggers on.
What do we actually get back?
A sheet with every scenario, its validity verdict and the budget it spends, then a document with the go or no-go, the bottleneck and the headroom. Alderhay's said 468 connections against 240 configured, so 24 pods rather than 12. Where a peak arrives anyway, the response belongs in a runbook.
Can this replace watching production?
No, and it will say which of its findings are only checkable there. A load test measures a shape you chose against a system you configured. Whether the real thing is burning budget right now is a monitoring question, and whether anything would page you is the coverage review. Where the system under test is a vendor's, the ceiling sits in their published limits, which a vendor review reads.
Load Test Report Template Against SLOs
Fill in the form and your workspace opens with the work already underway.