Adding a language
Job of this page: implementer checklist to grow a language harness without changing the analysis core.
Background (layout, timing model, contract summary): Benchmark architecture.
Fixtures: Test Data.
Stats after you have CSVs: Analysis methodology.
1. Register the language
Edit config/benchmark_config.yaml (used by scripts/read-config.py, scripts/run-all-benchmarks.sh, and analyze-benchmarks):
languages:
go: # example
display_name: Go
enabled: true
runner_dir: go
runner_script: scripts/run-benchmarks.sh
log_dir: logs/go
time_unit: nanoseconds
docs_dir: docs/go
serializers: [...]
Add paths.language_log_dirs.go: logs/go if your config uses that map.
2. Implement the harness contract
Meet the harness contract summary and measurement model. In particular:
| Requirement | Detail |
|---|---|
| Output CSV | logs/<lang>/YYYY-MM-DD-HHMMSS.csv with csv_schema |
Language column |
Must match the language id (e.g. go) |
| Time unit | Nanoseconds for all runners (including C#) |
| Modes | bytes and stream (or string/stream if matching legacy C#) |
| Warmup | Repetition index 0 excluded by analysis |
| Prepare outside loop | Schema compile, type registration, buffer pools — not timed |
| Timed section | Serialize + deserialize only |
| Fidelity | Round-trip semantic check; write logs/<lang>/<ts>.errors.csv only when errors occur |
| Optional sidecars | *.configs.json (environment + optional dataset/serializer metadata) |
| Seed | Master config reproducibility.random_seed / BENCHMARK_SEED |
3. Test data types
Implement make_one / run-config cells for suite type ids: message, document, telemetry, strings, event — see Test Data.
- Expand cells with
./scripts/resolve_run_config.py - Emit CSV columns
DataTypeInstanceCountandTypeConfigHashwhen measuring batch cells - Generators live under language trees (e.g.
python/.../data_v2,go/model/v2,rust/src/data_v2.rs,javascript/src/data_v2.js) - Wire schemas:
schemas/v2/+scripts/schemas/generate-all.sh - Catalog defaults:
schemas/data_catalog_v2.yaml
4. Runner script
runner_dir/scripts/run-benchmarks.sh must accept modes:
smoke | all-single | full | research
Source scripts/lib/config.sh and use bench_mode_reps "$MODE" (reads modes.<name>.repetitions). Set BENCHMARK_SEED from bench_random_seed. Do not hard-code repetition counts.
5. Documentation
docs/<lang>/index.md— ecosystem overview, registered inventory, caveats- After benchmarks:
analyze-benchmarkssodocs/<lang>/results.mdcan be produced when logs exist - Register under Benchmarks in
mkdocs.yml(Overview + Results)
6. Wire orchestration
Update scripts/run-all-benchmarks.sh to invoke the new runner (usually automatic via languages.*.enabled in master config).
Auto-discovers timestamped CSVs under logs/<lang>/; or pass:
analyze-benchmarks --logs go=logs/go
- Update
_KNOWN_LANGSfallbacks / aliases inanalysis/if config is unreadable. - Extend
generate_language_results_pages/_LANG_*maps inreports.py(and_LANG_DOCS_DIR) if the docs folder id differs from the language id (e.g.csharp→docs/c-sharp/). - Host scripts:
scripts/check-host-requirements.sh,scripts/install-host-requirements.sh. - Prepare-PR path detect:
.grok/skills/prepare-pr/scripts/detect-changed-langs.sh.
7. GitHub Actions (required)
Update .github/workflows/benchmark-ci.yml:
changesjob outputs +dorny/paths-filterentry forrunner_dir/**(andschemas/**if shared fixtures apply).- New
*-benchmarkjob: install toolchain,check-host-requirements.sh <id>, run./scripts/run-benchmarks.sh(smoke default). - Analysis smoke step: assert the new id appears in
--enabled-langs/--lang-runners.
Without this, PRs that only touch the new harness never run it in CI.
8. Tests
At least: smoke run produces non-empty CSV; times positive; required columns present.