The benchmark has no control, and the load generator has never been checked against another one #116
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Both are named in
report.md's own "what is not established", and item 1 of its suggested order is the control — the largest remaining hole in the method rather than in the server.No control request. Nothing in the timed set does provably identical work on both sides. A password hash at login would: same algorithm, same cost parameters, same input, so a large gap there would indict the measurement rather than the server. The login currently happens once at connect, outside the timed set. Until a control exists, the 5.5–7× and the 43.9 ms against 273.1 ms rest on internal consistency, which is good evidence and is not a control.
The generator has not been cross-checked. It is verified against a test server that returns a fixed response after a fixed delay, so what it ought to report is arithmetic — but it has never been run beside an established generator over the same target. The scheduling property it claims (a request's latency measured from when it was due, not when it was sent) is exactly the property that is easy to get subtly wrong and impossible to notice from the inside.
Neither blocks using the numbers internally. Both block publishing them.
Where to start
crates/jellyfin-bench/is the generator (load.rs,gate.rs,constant.rs,stats.rs,report.rs) andcrates/jellyfin-bench/README.mdsays why it canbe believed.
docs/benchmarks.mdis how a comparison is set up;report.mdisthe run these two gaps come out of, and its "what is not established" section is
the specification for this issue.
The control. Something in the timed set that does provably identical work on
both sides. A password hash at login is the candidate named in the report: same
algorithm, same cost parameters, same input, so a large gap there indicts the
measurement rather than the server. It happens once at connect today, outside
the timed set. Getting it into the set is the work — and note the harness's
own rule applies, that a request both servers answer identically for the wrong
reason is a false pass.
The cross-check. Run an established generator (
oha,wrk2,k6— any onethat also schedules by due time rather than send time) against the same target
and compare. The scheduling property is the one that is easy to get subtly wrong
and impossible to see from the inside.
How to know it is done
The control appears in the reported table with a ratio near 1, and a second
generator's numbers for the same target sit inside the spread the report already
records for five repetitions. If either does not, that result is the finding and
it goes in
report.md.House rules
CLAUDE.mdis the short version and these are the parts that bite: tests rununder
cargo nextest; upstream's source is the checkout inupstream/at thepin (
v12.0-rc5,6d501ba4) and not the clone beside the repository;generated files are regenerated rather than edited; a comment says what the code
does, not how it got there; and
Dnreferences stay out of code and comments.ARCHITECTURE.mddecides which crate a thing goes in and which dependency edgesare illegal,
DECISIONS.mdsays why a rule exists.The reference pair is
cargo xtask reference up(andreference provision,which is idempotent); a run is
cargo run -p jellyfin-harness -- replay --upstream URL --ours URL --scenario FILE --out DIR,with
diff-dbfor the two databases.crates/jellyfin-harness/README.mdsayswhat a diff means and what an ignore entry has to carry — every entry needs a
reason and an expiry milestone, and an adds-only history is the smell the risk
table names.
Landed in
94e9276.The control.
loginisPOST /Users/AuthenticateByName— PBKDF2-SHA512 atthe stored hash's iteration count against the same stored hash. Against the
defaultsnapshot at concurrency 1 it reports 68.30 ms upstream against71.95 ms ours: a ratio of 1.05, with p90 at 1.02, p99 at 0.94 and throughput
at 0.95. So the gap on the read paths is the server rather than the instrument.
It has no committed scenario. An anchor carries the accounts a household had,
and a scenario naming
jellyfinwould be refused by both servers and agreeabout the refusal — a control that measures a 401. The run writes it from its
own
--user/--passwordbeside the results, so what was measured is on recordnext to the numbers.
authenticated: trueis on the request not for a token butbecause upstream refuses the route without the client and device that header
carries. It writes a device row per request, so it is a write workload.
One ignore-list entry was needed:
AccessToken, which each server draws foritself. Everything else the route answers is diffed — the account, its policy
and configuration, and the session the login opened.
The cross-check.
oha1.15, overephyra-bench constant --service-ms 20 --body 512 --serialized, offered 100/s for 10s:Closed loop at one connection: 47.2/s and 21.20 ms against 47.4/s and 21.13 ms.
oha has to be asked for the same run:
--latency-correctionfor the due-timeclock,
-wto drain rather than truncate the tail at the deadline, and enoughconnections that the rate is never held back by the generator. Ask for less and
the disagreement is the flag rather than the finding —
-c 200without-wreports a worst case of 5.27 s for the same run, which is the tail it did not
wait for. The flags and the numbers are in
crates/ephyra-bench/README.md.Two small changes made the target reachable by the whole timed path rather than
by
loadalone:constantanswers a JSON string of the length it was askedfor, and
runtakes an empty--userfor a target with no login. The gate alsolists what it dropped before deciding there is nothing to measure — it used to
report a count and nothing to act on.