Skip to content

Store results one file per framework#1034

Merged
MDA2AV merged 1 commit into
mainfrom
per-framework-results
Jul 24, 2026
Merged

Store results one file per framework#1034
MDA2AV merged 1 commit into
mainfrom
per-framework-results

Conversation

@MDA2AV

@MDA2AV MDA2AV commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Closes #751.

Results lived in 52 shared arrays — site/data/<profile>-<conns>.json, each holding every framework — so a saved run rewrote files every other framework also occupies. They now live one file per framework:

site/data/baseline-512.json    [ {actix…}, {hyper…}, … ]        ->
site/data/results/actix.json   { framework, results: { "baseline-512": {…} } }

108 files, 1941 rows, rows copied verbatim.

The conflict is real, but narrower than "any two saves"

Git merges non-adjacent hunks fine, so I checked rather than assumed. Reproduced all three cases against the real data with actual git merge:

scenario old layout new layout
actix + hyper update existing rows merges cleanly merges cleanly
two adjacent frameworks update rows merges cleanly merges cleanly
two contributors each add a new framework CONFLICT in baseline-512 + baseline-4096 merges cleanly

It bites when rows are inserted — which is exactly the case where a rebase is most annoying, and the one the issue describes.

The correctness guarantee

Rows are copied verbatim rather than reshaped, so the migration is provable: regenerating data.js before and after produces a byte-identical file. The board, the composite and every archived round see exactly what they saw before.

Consumers

rebuild_site_data.py writes each framework's file — verified that benchmarking actix + hyper modified 2 of 108 files
generator loads site/data/results/*.json once and rebuilds the per-profile view, sorted by framework name so data.js doesn't churn
compare.sh one read of the framework's own file instead of scanning every profile file
archive.sh regroups into the existing round shape, so rounds/*.json keeps its current format
benchmark-pr.yml stages only site/data/results/<slug>.json

Filenames are the display_name lowercased with anything outside [A-Za-z0-9._-] replaced by -, because two gateway entries are named aspnet-minimal + nginx and + caddy.

One trap worth flagging

.gitignore's results/ rule was unanchored, so it silently swallowed site/data/results/ — my first commit contained all the code and none of the data. It's now /results/, matching the raw benchmark output it was always meant to cover; the root directory is still ignored (verified both ways).

Sequencing with #1020

#1020 edits rebuild_site_data.py and deletes rows from the flat files, so it will need a rebase. scripts/migrate_results_layout.py is kept in the tree for exactly that: re-run it after merging main and the purge carries over mechanically. Happy to do that rebase — say which order you'd like these to land.

🤖 Generated with Claude Code

Closes #751. Results lived in 52 shared arrays — site/data/<profile>-<conns>.json,
each holding every framework — so a saved run rewrote files that every other
framework also occupies. They now live one file per framework:

  site/data/baseline-512.json    [ {actix…}, {hyper…}, … ]        ->
  site/data/results/actix.json   { framework, results: { "baseline-512": {…} } }

108 files, 1941 rows, same rows verbatim.

The conflict is real but narrower than "any two saves": git merges
non-adjacent hunks fine, so two frameworks updating existing rows usually
merge. It bites when rows are *inserted* — two contributors each adding a
framework, which is exactly when a rebase is most annoying. Reproduced both
ways against the real data:

  old layout, actix + hyper update rows      merges cleanly
  old layout, two new frameworks added       CONFLICT in baseline-512 and -4096
  new layout, the same two new frameworks    merges cleanly, both files present

Rows are copied verbatim rather than reshaped, which makes the migration
provable: regenerating data.js before and after gives a byte-identical file.
That is the main guarantee here — the board, the composite and every archived
round see exactly what they saw before.

Consumers:

  rebuild_site_data.py   writes each framework's file; a run touches only the
                         frameworks it benchmarked (verified: benchmarking
                         actix + hyper modified 2 of 108 files)
  gen_leaderboard_data   loads site/data/results/*.json once and rebuilds the
                         per-profile view, sorted by framework name so the
                         emitted data.js does not churn
  compare.sh             one read of the framework's own file instead of a
                         scan of every profile file
  archive.sh             regroups into the existing round shape, so
                         rounds/*.json keeps its current format
  benchmark-pr.yml       stages only site/data/results/<slug>.json

The filename is the display_name lowercased with anything outside
[A-Za-z0-9._-] replaced by '-', because two gateway entries are named
"aspnet-minimal + nginx" and "+ caddy".

.gitignore's `results/` rule was unanchored and silently swallowed the new
directory — the first attempt committed the code and none of the data. It is
now `/results/`, which is the raw benchmark output it was always meant to
cover; the root directory is still ignored.

scripts/migrate_results_layout.py is kept rather than deleted: it re-derives
the layout from a flat checkout, which is what a branch predating this needs
in order to rebase.

Note for #1020, which edits rebuild_site_data.py and deletes rows from the
flat files: it will need a rebase, and running the migration script after
merging main is the mechanical way to do it.
@MDA2AV
MDA2AV merged commit 5698fa8 into main Jul 24, 2026
MDA2AV added a commit that referenced this pull request Jul 24, 2026
#1034 added `env: FRAMEWORK` to the "Commit saved results" step, which already
declared `env: GH_TOKEN` at its end. Two env keys in one step is invalid, and
GitHub rejects the entire file:

    failed to parse workflow: (Line: 160, Col: 9): 'env' is already defined

So /benchmark is currently dead on main — the workflow cannot be dispatched at
all. Merged into the existing block.

This slipped through because the check I ran was `yaml.safe_load`, and PyYAML
silently accepts duplicate mapping keys (last one wins) while GitHub Actions
does not. All six workflows now validate with a loader that raises on
duplicates instead.
MDA2AV added a commit to Kaliumhexacyanoferrat/HttpArena that referenced this pull request Jul 24, 2026
Six merges landed since the last sync: MDA2AV#1030, MDA2AV#1031, MDA2AV#1032, MDA2AV#1033, MDA2AV#1034 and
MDA2AV#1036. One real conflict, in the composite blurb, where both sides had
changed the same line for different reasons:

  main (MDA2AV#1032)  made the text state which normalization rule is active, so a
                screenshot can't be ambiguous about whether scores were
                rescaled to the current filter
  this branch   pointed the "How it works" link at /docs/scoring/composite
                -score/ instead of the hash route

Both are kept: MDA2AV#1032's wording with this branch's real URL.

Everything else merged on its own, but the two structural ones were checked
rather than assumed:

MDA2AV#1034 moved results from 52 shared per-profile arrays to one file per
framework. Git applied that to the renamed generator correctly — it still
loads site/data/results/*.json and still emits 1941 rows, and compare.sh
kept both its per-framework read and the --compare flag from MDA2AV#1031.

MDA2AV#1030 added three echo-ws-limited doc pages after this branch's SEO pass, so
they were written with seo_title/description already; all 126 pages now carry
both.

Generator output on the merged tree: 1941 rows, 126 static doc pages, a 126
-page search index and a 127-URL sitemap. All six workflows validate against
a loader that rejects duplicate keys, which is what MDA2AV#1036 had to fix.
MDA2AV added a commit to prothegee/HttpArena that referenced this pull request Jul 24, 2026
This branch saved results before MDA2AV#1034, so it carries
site/data/<profile>-<conns>.json files that main has since replaced with one
file per framework. Git reported them as modify/delete conflicts.

The rows this PR added or changed against its merge base were re-applied to
site/data/results/zix.json and the flat files dropped. Only rows the PR
actually touched moved across, so nothing main has changed since is
resurrected:

  baseline-h3-64   9,573,685 -> 9,392,865 rps
  static-h3-64       611,890 ->   686,550 rps
MDA2AV added a commit to prothegee/HttpArena that referenced this pull request Jul 24, 2026
This branch saved results before MDA2AV#1034, so it carries
site/data/<profile>-<conns>.json files that main has since replaced with one
file per framework; git reported them as modify/delete conflicts.

The six gRPC rows this PR added were re-applied to site/data/results/zix.json
and the flat files dropped:

  stream-grpc-64, stream-grpc-tls-64,
  unary-grpc-256, unary-grpc-1024,
  unary-grpc-tls-256, unary-grpc-tls-1024

Only rows the PR actually touched moved across, so nothing main has changed
since is resurrected.

site/data/frameworks.json also conflicted. It is derived from every
frameworks/*/meta.json, so it was regenerated with
rebuild_site_data.py::rebuild_frameworks_json rather than hand-merged - 118
entries, this PR's zix entry included.
MDA2AV added a commit to prothegee/HttpArena that referenced this pull request Jul 24, 2026
This branch saved results before MDA2AV#1034, so it carries 20
site/data/<profile>-<conns>.json files that main has since replaced with one
file per framework; git reported them all as modify/delete conflicts.

Every row this PR added or changed against its merge base was re-applied to
site/data/results/zix.json and the flat files dropped - 8 profiles this entry
did not publish before (api-4, api-16, async-db, crud, json-comp at three
connection counts, json-tls) and 12 it updated (baseline, limited-conn,
pipelined, json, static, upload). Two keys already in main were left alone,
because this PR did not touch them.
MDA2AV added a commit to williamthome/HttpArena that referenced this pull request Jul 24, 2026
This branch saved results before MDA2AV#1034, so it carries 38
site/data/<profile>-<conns>.json files that main has since replaced with one
file per framework; git reported them all as modify/delete conflicts.

Every row this PR re-measured for the v0.8.0 bump was re-applied to
site/data/results/roadrunner.json and the flat files dropped. All 38 keys
already existed, so all 38 are updates rather than additions - for example
baseline-512 833,311 -> 919,625 rps and async-db-1024 84,434 -> 134,059 rps.

Only rows this PR touched moved across, so nothing main has changed since is
resurrected.
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.

New results json strategy

1 participant