A workload is a pinned answer to "what exactly was run". One JSON file per
workload, schema in schemas/workload.schema.json,
shape summarised in SPEC §4.
A result is only comparable to another result when both name the same
workload_id. That is the whole reason this directory exists: the model, the
quantization, the engine and the flags are recorded in the result, and the
question that was asked of them is recorded here.
Immutability
A published workload is never edited. Not the concurrency, not the number of requests, not the dataset it points at, not a typo in a number. Every existing result that references it was produced under the old definition, and silently changing it turns those numbers into a lie.
immutable: true and the mandatory -vN suffix say so in the data. The only
edits ever allowed on a published file are the ones that cannot change what runs:
name, description, notes.
Proposing a v2
- Copy the file to
<same-name>-v2.jsonand changeidto match the filename. - Set
"supersedes": "<the v1 id>". - Change what you meant to change, set
createdto today. - Leave the v1 file exactly as it is. It keeps its results; the site can show them side by side and mark the v1 cells stale rather than wrong.
- If the change is really "the dataset changed", the dataset needs a
-v2too (seedatasets/README.md) — a workload pointing at different bytes is a different workload.
Naming: <kind>-<shape>-v<N>, lower-case kebab, with the shape readable at a
glance (c8 = concurrency 8, i1k = ~1k input tokens, o256 = 256 output
tokens).
Kinds
| kind | what it measures | runner | required shape |
|---|---|---|---|
serving |
steady-state throughput and latency at a fixed concurrency | serving |
sweep and eval are null |
sweep |
one axis walked, a metric block per point | sweep |
sweep has exactly one axis |
prefill |
time to first token on a long input, almost no decode | prefill |
tiny output_tokens |
longctx |
behaviour as the prompt grows, with a retrieval check | longctx |
may carry a sweep and/or an eval block |
eval |
capability, scored per item | eval |
eval and dataset_id required |
metrics_required lists the metric paths a result must carry non-null. Dotted
paths address into a distribution (ttft_ms.p50). For kind: eval the three
required names — accuracy, success_rate, avg_latency_ms — live in the
result's scores block rather than in metrics; success_rate there means "the
share of requests that completed at all", independently of whether the answers
were right.
All workloads
| id | kind | dataset | shape |
|---|---|---|---|
serve-single-i256-o256-v1 |
serving | prompts-mixed-v1 |
c1, n=50, in≈256, out=256 |
serve-short-c16-i128-o128-v1 |
serving | prompts-mixed-v1 |
c16, n=320, in≈128, out=128 |
serve-chat-c8-i1k-o256-v1 |
serving | prompts-mixed-v1 |
c8, n=200, in≈1k, out=256 |
serve-chat-c32-i1k-o256-v1 |
serving | prompts-mixed-v1 |
c32, n=400, in≈1k, out=256 |
serve-chat-c64-i1k-o256-v1 |
serving | prompts-mixed-v1 |
c64, n=640, in≈1k, out=256 |
serve-long-c4-i8k-o512-v1 |
serving | prompts-mixed-v1 |
c4, n=40, in≈8k, out=512 |
serve-code-c8-i2k-o1k-v1 |
serving | prompts-code-v1 |
c8, n=160, in≈2k, out=1k |
serve-prefix-c16-v1 |
serving | prompts-shared-prefix-v1 |
c16, n=200, grouped by prefix |
sweep-parallel-1-32-i512-o256-v1 |
sweep | prompts-mixed-v1 |
concurrency 1,2,4,8,16,32 |
sweep-parallel-1-64-i1k-o256-v1 |
sweep | prompts-mixed-v1 |
concurrency 1,2,4,8,16,32,64 |
prefill-8k-v1 |
prefill | haystack-v1 |
c1, n=10, in=8k, out=16 |
prefill-32k-v1 |
prefill | haystack-v1 |
c1, n=10, in=32k, out=16 |
prefill-128k-v1 |
prefill | haystack-v1 |
c1, n=10, in=128k, out=16 |
longctx-depth-sweep-v1 |
longctx | haystack-v1 |
input_tokens 1k…256k, out=256, needle checked |
longctx-needle-32k-v1 |
longctx | eval-longctx-v1 |
c1, n=6, in=32k, needle scored |
longctx-needle-128k-v1 |
longctx | eval-longctx-v1 |
c1, n=6, in=128k, needle scored |
eval-math-v1 |
eval | eval-math-v1 |
numeric, max_out 4096 |
eval-reasoning-v1 |
eval | eval-reasoning-v1 |
exact (rows may be mc), max_out 2048 |
eval-code-v1 |
eval | eval-code-v1 |
code-exec, max_out 4096 |
eval-knowledge-v1 |
eval | eval-knowledge-v1 |
mc, max_out 2048 |
eval-instruction-v1 |
eval | eval-instruction-v1 |
instruction, max_out 2048 |
eval-json-v1 |
eval | eval-json-v1 |
json, max_out 2048 |
eval-tools-v1 |
eval | eval-tools-v1 |
json on tool_calls[0], max_out 2048 |
eval-vision-v1 |
eval | eval-vision-v1 |
vision, max_out 2048 |
eval-multilingual-v1 |
eval | eval-multilingual-v1 |
contains, max_out 2048 |
eval-longctx-v1 |
eval | eval-longctx-v1 |
needle, max_out 1024, c1 |
eval-format-v1 |
eval | eval-format-v1 |
exact, max_out 256 |
eval-math-v2 |
eval | eval-math-v2 |
numeric, max_out 4096, supersedes v1 |
eval-reasoning-v2 |
eval | eval-reasoning-v2 |
mixed scorers, max_out 4096, supersedes v1 |
eval-knowledge-v2 |
eval | eval-knowledge-v2 |
mc, max_out 1024, supersedes v1 |
eval-science-v2 |
eval | eval-science-v2 |
numeric, max_out 4096, new suite |
eval-commonsense-v2 |
eval | eval-commonsense-v2 |
mixed scorers, max_out 2048, new suite |
eval-security-v2 |
eval | eval-security-v2 |
mixed scorers, max_out 4096, new suite |
eval-longgen-integrity-v1 |
eval | eval-longgen-integrity-v1 |
integrity, max_out 3000, c1, n=36 |
Conventions a runner must honour
paramsis the contract,descriptionis prose. Anything a runner needs is a key inparams, never only in the text.input_tokensis nominal. It says which prompts to pick, not what the tokenizer will produce. Record the real count inmetrics.input_tokens_total.dataset_buckets(serving/sweep) filtersprompts-*rows by length bucket;dataset_categoriesanddataset_target_tokensfilter eval rows.- Sweep points. For the two parallelism sweeps, requests per point are
max(params.num_requests, concurrency * params.requests_per_concurrency), so a low-concurrency point is not dominated by warmup.params.concurrencyis the first point of the axis and is otherwise ignored. serve-prefix-c16-v1must send all rows of oneprefix_idback to back (params.group_by), must not shuffle, and excludeswarmup_per_grouprequests per group from the aggregate. Run it twice on the same engine, with and without the prefix-cache flag, and comparettft_ms.longctx-depth-sweep-v1checks the needle at every point. A wrong needle answer is a failed request — it lowerssuccess_rateand adds afailures[]entry with categorymalformed-output. A point that exceeds the servedmax-model-lenis recorded as a failure with categorycontext-overflow, never omitted, because "did not fit" is a result.- Eval concurrency does not change the score, only the wall clock. It is 4
everywhere except
eval-longctx-v1, which runs at 1 to keep KV cache pressure honest, andeval-longgen-integrity-v1, where concurrency 1 is part of the configuration under test: batching changes the scheduler, the KV-cache layout and the attention path, so a run at another concurrency measures something else. eval-longgen-integrity-v1scores token integrity, not correctness.accuracyis the share of 150-to-290-line generations that came back with no spliced token. A clean run of 36 is not proof of absence: at a one-in-five per-generation rate a clean pass is a plausible outcome for an affected build, so report the run rather than the absence.params.reasoning: "default"means "leave the engine's own default alone". Whatever it was, record it in the result'sargs— reasoning settings move eval scores and latency more than most flags.- Scorer names.
eval.scoreruses the kebab-case vocabulary ofworkload.schema.json(code-exec); dataset rows use the snake_case scorer module name from SPEC §8 (code_exec). They mean the same thing. Always prefer the row's ownscorerwhen a dataset mixes them.
Adding a workload
A new workload is a PR that adds one file. Before writing it, check the table
above: a workload that differs from an existing one only in num_requests splits
the coverage map for no gain. Good reasons to add one: a new axis (a concurrency
the sweeps do not reach), a new dataset, or a shape that models a real deployment
nobody has captured yet.
Checklist:
- id ends in
-v1, filename equalsid + ".json"; dataset_idexists underdatasets/;metrics_requiredonly names metrics the runner can actually fill for that kind;immutable: true,createdtoday,supersedesnull;pnpm validatepasses.