dub.sdlsdl · 90 linesall
name "wired-runtime-bench"
description "Runtime JSON benchmark: std.json baseline vs D engines, on sparkles:test-runner"
authors "Petar Kirov"
copyright "Copyright © 2026, Petar Kirov"
license "BSL-1.0"

targetType "library"
targetPath "build"

dflags "-preview=in" "-preview=dip1000"

dependency "sparkles:wired" path="../../../.."
// Build wired with cross-module inlining scoped to that package (its scan→
// reader seams inline into the hot loop) — this reproduces the pre-rebase
// executable baseline's codegen exactly (retired ins/byte parity). Scoped
// here, not via the `bench` build type, so mir-ion never sees CMI (which would
// cull its template-nested function). The codegen-parity matrix lives in
// `libs/wired/dub.sdl`; override for A/B measurement with e.g.
// `--override-config sparkles:wired/library` (stock) or `.../library-singleobj`.
subConfiguration "sparkles:wired" "library-inline"
// Top-level, not just under `configuration "unittest"`: runner.d imports
// sparkles.test_runner.* at module scope (and the non-template `bytes()` returns
// its `Metric`), so it's an unconditional dependency of the package — declaring
// it here keeps the manifest honest instead of relying on `dub` defaulting a
// dep-less config to the unittest one.
dependency "sparkles:test-runner" path="../../../.."

// D engines (pure-D dub packages; pinned in dub.selections.json). Each adapter
// sits behind its `versions` gate so a frontend incompatibility is one line
// away from off. Foreign engines (yyjson/C++/Rust) need nix-built shims and are
// off by default — re-add their `versions` + path deps to run them under nix.
dependency "mir-ion" version="~>2.3"
versions "BenchMirIon"
dependency "asdf" version="~>0.8.0"
versions "BenchAsdf"
dependency "jsoniopipe" version="~>0.2.7"
versions "BenchJsoniopipe"

configuration "unittest" {
    // The benchmark is a set of `@benchmark unittest`s run through
    // sparkles:test-runner (`dub test -- --bench`, with `--perf` for hardware
    // counters). Corpora load from `$WIRED_BENCH_DATA` at run time. This
    // default config is the D-engine field only (std.json, wired-native,
    // mir-ion, asdf, jsoniopipe) — pure-D deps that build anywhere, for fast
    // off-nix iteration.
    dflags "-checkaction=context" "-allinst"
    dflags "-defaultlib=libphobos2.so" "-L-fuse-ld=gold" platform="linux-dmd"
    dflags "--link-defaultlib-shared" "--linker=gold" platform="linux-ldc"
    lflags "--export-dynamic" platform="linux-ldc"
}

// The full competitive field: the D engines plus the foreign engines
// (yyjson, simdjson DOM/On-Demand, rapidjson, serde_json, simd-json,
// sonic-rs) reached through their ImportC/`extern(C)` shims. Those shims
// resolve via pkg-config (`yyjson.pc`, `wired-bench-cpp-shim.pc`,
// `wired-bench-rs.pc`) on the devshell's `PKG_CONFIG_PATH`, so this config
// is nix-only. Run the full field with:
//   dub test -b bench -c unittest-foreign -- --bench --perf
configuration "unittest-foreign" {
    // yyjson: ImportC binding; the ISA-preset build's yyjson.pc provides both
    // cflags and -lyyjson.
    dependency "yyjson" path="bindings/yyjson"
    versions "BenchYyjson"

    // simdjson (DOM + On-Demand) and rapidjson via the extern "C" shim, and
    // serde_json + simd-json + sonic-rs via the Rust staticlib.
    dependency "wired-bench-shim" path="bindings/shim"
    versions "BenchCpp" "BenchRust"

    dflags "-checkaction=context" "-allinst"
    dflags "-defaultlib=libphobos2.so" "-L-fuse-ld=gold" platform="linux-dmd"
    dflags "--link-defaultlib-shared" "--linker=gold" platform="linux-ldc"
    lflags "--export-dynamic" platform="linux-ldc"
}

// Real numbers need release codegen: dub's stock `unittest` build type is a
// debug build (the runner prints an assert-build warning under --bench), so
// benchmarks run via `dub test -b bench -- --bench …`. `unittests` is the
// load-bearing option — without it `dub test` registers zero tests.
buildType "bench" {
    buildOptions "unittests" "releaseMode" "optimize" "inline"
    // NB vs the old executable harness's flags: `-enable-cross-module-inlining`
    // is OFF — build types propagate to dependencies, and mir-ion's -unittest +
    // releaseMode build culls a template-nested function its inlined code still
    // references (undefined `printElement…quote`; `-linkonce-templates` ICEs).
    // Costs ~15% on wired's number-heavy hot loops vs the old `-b bench`
    // executable baselines — compare new numbers only against baselines
    // regenerated under this build type.
    dflags "-mcpu=native" "-O3" "-allinst" platform="ldc"
}