Skip to content

Commit 6d186ff

Browse files
committed
refactor: update HTTP benchmark result structure and improve documentation clarity
1 parent 42d62a8 commit 6d186ff

7 files changed

Lines changed: 39 additions & 27 deletions

File tree

app/Actions/Results/HttpBenchmarkResults.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ public static function selfGenerator(): array
282282
}
283283

284284
/**
285-
* @return array{mode: string|null, target: string|null, duration_seconds: int|null, connections: int|null, io_ms: int|null, routes: array<string, array<string, mixed>>}|null
285+
* @return array{mode: string|null, target: string|null, io_ms: int|null, workers: int|null, levels: array<string, array<int, int>>, routes: array<string, array<string, mixed>>}|null
286286
*/
287287
public function execute(): ?array
288288
{

app/Support/Http/LoadCurve.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* numbers untrustworthy.
99
*
1010
* Nothing here drives the load. The levels are chosen before the run starts
11-
* (LoadProfile::levels) and run as a plain list, so this only has to describe
11+
* (LoadProfile::levelsFor) and run as a plain list, so this only has to describe
1212
* what came back — which is why the same class can read a self-test and an
1313
* external run without either of them knowing it exists.
1414
*/

app/Support/Http/LoadStep.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* rather than per route. The external generator posts its result back to that
1010
* index, and the server refuses anything that is not the step it is currently
1111
* waiting for — which is what makes a retried upload cost one round trip
12-
* instead of corrupting the ramp.
12+
* instead of corrupting the sweep.
1313
*/
1414
class LoadStep
1515
{
@@ -37,7 +37,7 @@ public function __construct(
3737
* OPcache warm; its numbers describe a cold server and are never parsed.
3838
* Saying so here keeps the drivers from having to know which phases mean
3939
* something — the generator sends `{}` for an uncaptured step, and the
40-
* state machine advances on the acknowledgement alone.
40+
* driver advances on the acknowledgement alone.
4141
*/
4242
public function isMeasured(): bool
4343
{
@@ -47,9 +47,8 @@ public function isMeasured(): bool
4747
/**
4848
* Whether the raw oha JSON for this step is kept on disk.
4949
*
50-
* Ramp rungs are reduced to a curve point and discarded: thirty-odd files
51-
* of three-second throwaway data are not worth keeping, and nothing may
52-
* cite a rung as a measurement. The two published passes are kept whole.
50+
* Every measured window is kept: a sweep level backs one point on the
51+
* published curve, and the response-time pass backs the percentiles.
5352
*/
5453
public function isPublished(): bool
5554
{

app/Support/Http/StepResult.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace App\Support\Http;
44

55
/**
6-
* One oha result, reduced to the facts the state machine and the curve need.
6+
* One oha result, reduced to the facts the sweep and the curve need.
77
*
88
* Reducing here rather than passing the raw document around is what lets the
99
* two drivers stay identical: the generator uploads oha's JSON and the local
@@ -89,7 +89,7 @@ public static function failed(string $reason): self
8989
* every request reports a perfect success rate, and at a *higher* rate
9090
* than a working one, because an error is cheap to produce. Checking the
9191
* status distribution is what turns that from a flattering number into a
92-
* stopped ramp.
92+
* stopped sweep.
9393
*/
9494
public function isClean(): bool
9595
{

docs/app/pages/results/[id].vue

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -138,18 +138,12 @@
138138
HTTP benchmark — reading it off `http` here silently
139139
labelled every worker-mode run "classic mode". -->
140140
<ResultsChip>{{ run.environment.php.octane ? 'worker mode' : 'classic mode' }}</ResultsChip>
141-
<ResultsChip v-if="http.duration_seconds">
142-
{{ http.duration_seconds }}s
143-
</ResultsChip>
144-
<ResultsChip v-if="http.connections">
145-
{{ http.connections }} connections
141+
<ResultsChip v-if="http.workers">
142+
{{ http.workers }} workers
146143
</ResultsChip>
147144
<ResultsChip v-if="http.io_ms != null">
148145
I/O {{ http.io_ms }}ms
149146
</ResultsChip>
150-
<ResultsChip v-if="http.mode">
151-
{{ http.mode }}
152-
</ResultsChip>
153147
<ResultsChip v-if="loadModeLabel">
154148
{{ loadModeLabel }}
155149
</ResultsChip>
@@ -162,8 +156,9 @@
162156
</template>
163157

164158
<p class="mt-2 text-xs text-neutral-500">
165-
Saturation test — connections held open to find max throughput, so response times
166-
include time spent queued.
159+
Concurrency was raised until throughput stopped improving. Response times were
160+
measured separately, at about 70% of that rate, so they include no queue a real
161+
visitor would not also hit.
167162
<NuxtLink
168163
to="/docs/benchmarks"
169164
class="text-neutral-400 underline underline-offset-4 decoration-white/20 transition-colors hover:text-neutral-300 hover:decoration-white/40"
@@ -187,10 +182,13 @@
187182
</p>
188183
<div class="mt-2">
189184
<p class="text-5xl text-white font-mono font-medium leading-none tabular-nums">
190-
{{ round(benchRoute.data.throughput?.requests_per_second) }}
185+
<!-- A run whose sweep never flattened measured the most BenchKit
186+
could ask for, not the most the machine can serve. A gallery
187+
that prints that flat ranks a floor against maximums. -->
188+
<span v-if="benchRoute.isFloor" class="text-amber-400">≥</span>{{ round(benchRoute.data.throughput?.requests_per_second) }}
191189
</p>
192190
<p class="mt-1.5 text-sm text-neutral-400 font-mono">
193-
req/s
191+
req/s <span v-if="benchRoute.concurrency" class="text-neutral-500">at {{ benchRoute.concurrency }} concurrent</span>
194192
</p>
195193
</div>
196194
<div class="mt-4 flex flex-col gap-2.5">
@@ -230,10 +228,10 @@
230228
</p>
231229
<div class="mt-auto pt-4">
232230
<p class="text-4xl text-white font-mono font-medium leading-none tabular-nums">
233-
{{ round(benchRoute.data.throughput?.requests_per_second) }}
231+
<span v-if="benchRoute.isFloor" class="text-amber-400">≥</span>{{ round(benchRoute.data.throughput?.requests_per_second) }}
234232
</p>
235233
<p class="mt-1.5 text-sm text-neutral-400 font-mono">
236-
req/s
234+
req/s <span v-if="benchRoute.concurrency" class="text-neutral-500">at {{ benchRoute.concurrency }} concurrent</span>
237235
</p>
238236
</div>
239237
</div>
@@ -691,6 +689,9 @@ const routes = computed(() => {
691689
})
692690
return {
693691
key,
692+
// Where the peak happened, and whether it was a peak at all.
693+
concurrency: data.throughput?.concurrency ?? null,
694+
isFloor: data.throughput?.saturated === false,
694695
label: ROUTES[key]!.label,
695696
description: key === 'io' ? `Simulated ~${http.value.io_ms ?? 100}ms outbound call` : ROUTES[key]!.description,
696697
data,

resources/js/Components/Share/templates/TemplateFullSuite.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,11 @@ const chips = computed(() => {
186186
environment.phpVersion ? { text: `PHP ${environment.phpVersion}` } : null,
187187
environment.laravelVersion ? { text: `Laravel ${environment.laravelVersion}` } : null,
188188
environment.database ? { text: environment.database } : null,
189-
http?.connections && http?.duration_seconds ? { text: `${http.connections} connections · ${http.duration_seconds}s` } : null,
189+
// Only when it is not the standard delay: a chip that always says the
190+
// same thing is furniture. The connections/duration chip that used to
191+
// sit here read fields that no longer exist, so it silently never
192+
// rendered.
193+
http?.io_ms != null && http.io_ms !== 100 ? { text: `I/O ${http.io_ms}ms` } : null,
190194
http?.mode && http.mode !== 'loopback' ? { text: httpTargetLabel(http.mode) } : null,
191195
http?.generator?.mode === 'external' ? { text: 'external load' } : null,
192196
].filter(Boolean);

resources/js/Pages/Runs/Compare.vue

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
</div>
5656

5757
<p v-if="httpLoadMismatch && headline.path.startsWith('routes.')" class="mt-7 text-sm text-center text-[#F79009]">
58-
These runs used different load settings &mdash; Run A: <span class="font-mono">{{ httpLoadMismatch.a }}</span> &middot; Run B: <span class="font-mono">{{ httpLoadMismatch.b }}</span> &mdash; so throughput isn't directly comparable.
58+
These runs simulated a different outbound call &mdash; Run A: <span class="font-mono">{{ httpLoadMismatch.a }}</span> &middot; Run B: <span class="font-mono">{{ httpLoadMismatch.b }}</span> &mdash; so the I/O route measured different work on each side.
5959
</p>
6060
</section>
6161

@@ -164,11 +164,19 @@ const httpLoadMismatch = computed(() => {
164164
return null;
165165
}
166166
167-
if( a.connections === b.connections && a.duration_seconds === b.duration_seconds ) {
167+
// The load sizes itself from each machine now, so two runs differing in
168+
// concurrency is expected and says nothing. What still makes throughput
169+
// apples-to-oranges is the one load parameter left — the simulated delay
170+
// changes what /bench/io measures rather than how hard the load pushes.
171+
//
172+
// This used to compare connections and duration, and after those stopped
173+
// existing it compared undefined against undefined: always equal, so the
174+
// banner could never fire at all.
175+
if( (a.io_ms ?? null) === (b.io_ms ?? null) ) {
168176
return null;
169177
}
170178
171-
const label = (http) => `${http.connections ?? '?'} connections × ${http.duration_seconds ?? '?'}s`;
179+
const label = (http) => `${http.io_ms ?? '?'}ms simulated I/O`;
172180
173181
return { a: label(a), b: label(b) };
174182
});

0 commit comments

Comments
 (0)