Benchmark suites and release certificates#
This directory holds the benchmark-suite records of the papers whose code dynG ports (PLAN
Section 8.5) and, per release, the committed results: the performance gates against the pinned
originals (PLAN Section 8.6) and the parity certificate (PLAN Section 8.3). The scripts that use
them live in parity/: parity/bench_suite.py runs a suite through the A/B harness and
parity/certify.py writes the certificate.
benchmarks/
paper/<suite>.yaml one machine-readable suite per paper and algorithm
results/<version>/ what a release commits: the suite summaries, the compacted harness
records, the golden replays, the checks, parity.json, README.md
The suites#
Suite |
Algorithm |
Paper |
Readings |
|---|---|---|---|
|
|
DynaMOSP (IPDPS 2025, TPDS 2025): the per-objective SOSP update |
roadNet-PA, roadNet-CA, rgg_n_2_20_s0, road_usa; K = 3, U[1, 100] seed 12345, source 0; 50K safe / 50K unsafe / 10K local batches (seed 777); OpenMP (28 threads pinned) and CUDA (boost clock lock) gated; CUDA at default clocks recorded; device memory |
|
|
TruCy / DynTruCy (IEEE TC) |
DD, GitHub, Twitch, COLLAB; static k = 3..7, updates 25K+25K (DD also 50K and 100K), seed 1; OpenMP (56 threads) and CUDA (boost lock; the COLLAB update at the base lock, ADR 0021) gated; CUDA at default clocks recorded; device memory |
|
|
DynaMOSP (IPDPS 2025): the MOSP update, the K per-objective updates plus the combined graph and its SOSP |
the same four graphs, inputs and batches as the sssp suite (K = 3, default preferences); “(a) compute” (<= 1.05x) and “(b) end to end” (<= 1.10x, every output file written by both sides, as the originals’ |
The mosp suite reads the gates M7 took (parity/results/M7.md sections 6 and 8) and is required
in every certificate from 0.2.0 on; the per-objective update alone stays in the sssp suite. The K
sweep of the TPDS 2025 extension (roadNet-CA widened to four objectives, tpds25_dynamosp) is
reported, not gated (M7.md section 5), and listed under deferred in the mosp suite; the temporal
datasets of DynTruCy (CollegeMsg, email-Eu-core, time-window mode) come with the temporal modes in
0.4 (listed under deferred in the suite). The ESCHER, DynLP and H-SOSP suites follow their
ports.
rgg’s unsafe50k batch equals its safe50k batch. The original’s --safe filter
(filterUnsafeDeletions of MOSP-CUDA@e220ee2) drops only the deletions that make a vertex
unreachable from the source, and none of the 25,000 seed-777 deletions of rgg_n_2_20_s0
(average degree about 13) does, so both directories hold byte-identical files (the same digests
in both suite files). The rgg unsafe50k readings of the sssp and mosp suites repeat the safe50k
ones and are not independent coverage of disconnecting deletions; on roadNet-PA, roadNet-CA and
road_usa the safe batch keeps 23,201, 23,319 and 21,884 of the 25,000 deletions. A disconnecting
rgg batch would be a new reading of a later suite.
The suite format#
A suite is YAML (schema 1). parity/bench_suite.py validate checks every key below, and checks
the file against the harness it drives, so the suite cannot silently describe something else than
what is measured.
Key |
Content |
|---|---|
|
the name (equal to the file name), what is measured, the paper and its scope |
|
the harness entry ( |
|
sssp, mosp: K ( |
|
name, |
|
name, generator, sizes, |
|
cycle_count: task, dataset, k, batch; the harness names a case |
|
threads, GPU, scopes, environment, and the baseline each backend is compared with; mosp: the CUDA engine ( |
|
sssp, mosp: alternating rounds per dataset ( |
|
each gated region of |
|
the pinned originals (commit equal to |
|
PLAN 8.6: |
|
one harness invocation per dataset (sssp, mosp) or per case list (cycle_count): |
|
informational: the paper’s published numbers |
validate requires, among others: every gated region of the region map is a metric with the same
gate and the same profiler stages; the baselines are the pinned unpatched commits; the
tolerances are the ones the harness applies; every case of a reading is a case of the harness and
of the suite; a default-clock reading is not gated.
Running a suite#
The protocol is the one of PLAN 8.6 and parity/README.md: parity presets; the originals built
from the unpatched git archive copies; every timing under the exclusive lock
$DYNG_SCRATCH/perf.lock (the harness takes it itself); medians of alternating rounds; the
contamination monitor repeats disturbed rounds; outputs compared in every round; CUDA on GPU 0
with the clocks locked for the whole A/B (ADRs 0018 and 0021), the default-clock reading
recorded next to it.
source scripts/dev_env.sh
parity/build_reference.sh # the pinned originals (unpatched + patched)
for g in roadNet-PA roadNet-CA rgg road_usa_g; do parity/perf_ab.py prepare --graph $g; done
cmake --preset parity && cmake --build --preset parity
cmake --preset parity-cuda && cmake --build --preset parity-cuda
parity/bench_suite.py validate benchmarks/paper/*.yaml
parity/bench_suite.py plan benchmarks/paper/ieee_tc_dyntrucy.yaml # the commands, not run
parity/bench_suite.py run benchmarks/paper/ipdps25_dynamosp_sosp.yaml --version 0.1.0rc1
parity/bench_suite.py run benchmarks/paper/ieee_tc_dyntrucy.yaml --version 0.1.0rc1
parity/bench_suite.py run benchmarks/paper/ipdps25_dynamosp_mosp.yaml --version 0.2.0rc1
run first checks the SHA-256 of every input against the suite (--no-verify-inputs skips it),
then runs each planned command; --skip-existing resumes an interrupted execution, and
--build-root points at another checkout’s build trees (for example a clean clone of the release
commit). The full records go to $DYNG_SCRATCH/runs/bench/<version>/, with the log of every
command (<suite>.log); run never replaces a record that exists (--skip-existing keeps it,
--force replaces it; to take a reading again, move its record to superseded/ first).
--readings, --datasets and (sssp, mosp) --batches select a part, --runs overrides the
rounds (at least 5), and --keep-contaminated (sssp, mosp) makes a diagnostic execution for a
machine too busy for a gate run (the harness keeps and flags the rounds its contamination monitor
would repeat; the summary lists them under contaminated, and refuses such a record in any other
execution): such a narrowed execution is summarized as <suite>.partial.json and only into an --out outside
benchmarks/results/ (a release’s summary is the whole suite’s; after taking readings again, run
summarize for the whole suite). The harness records name the NVIDIA driver and the CUDA driver
API version, and the inputs as measured: the sssp harness hashes every input file when a run
starts, the cycle_count harness hashes the datasets in the measuring process. summarize (run at
the end of run, or on its own) writes to benchmarks/results/<version>/:
<suite>-<reading>[-<dataset>].json: each harness record, compacted (the per-round machine-monitor windows are dropped; the samples, verdicts, rejected rounds and clock checks are kept; the record names its full copy);<suite>.json: every reading with its regions (original and port medians, ratio, gate, verdict), the commits that were measured, the driver each record names, when the execution started, the inputs check and the verdict.
The summary re-derives every gate from the suite’s tolerances and fails if a record’s gate,
reference commit or variant, input digests, clock lock or build preset differ from the suite, if
a record is of another algorithm or other batches than the suite’s (a mosp record must say
mosp: an sssp record of perf_ab.py run or memory without --mosp has the same shape), if a
mosp record has another K, other preferences or another CUDA engine, did not write the output
files, or has invalidated counts that differ between the two sides in a round, if
a gated reading is missing or incomplete, if a gated region exceeds its gate or is provisional
(a region under 10 ms read with fewer than 20 rounds), or if the inputs of a record are not
verified. A record’s inputs are verified by the digests the harness took while measuring; a
record without such digests (the sssp records of 0.1.0rc1, whose digests are the ones
perf_ab.py prepare wrote; the memory records of 0.1.0rc1) is verified only if every input file
hashes to the suite’s digest now and has not been written or replaced (modification and
status-change times) since the execution started, the first command of <suite>.log. It lists, without failing (PLAN 8.6:
flagged, not failed), the runs the OpenMP cycle_count harness flagged for foreign CPU load above
its threshold (the other harnesses repeat such rounds); a reading with flagged runs is read again
on a quiet machine before a release.
The release certificate#
PLAN 10.3 steps 1-3 (docs/developer/release.md) end in benchmarks/results/<version>/:
The golden replays (
parity/compare.py ... --json benchmarks/results/<version>/parity-<set>-<backend>.json): every golden set ofparity/goldens.tomlon every backend it covers (sssp: sequential, OpenMP and CUDA; the cycle_count CPU corpus--full: sequential and OpenMP; the cycle_count CUDA corpus: cuda, cuda:resident, cuda:int64).The performance gates:
parity/bench_suite.py runfor every suite of the release’s algorithms.certify.pyrequires the suites ofREQUIRED_SUITESby release series:ipdps25_dynamosp_sosp(sssp) andieee_tc_dyntrucy(cycle_count) from 0.1,ipdps25_dynamosp_mosp(mosp) from 0.2 (a 0.2.0rc1 or 0.2.0 certificate without the mosp gates fails); each summary must hold a gated reading of every gated metric of its suite file on every backend it is gated on (mosp: “(a) compute” and “(b) end to end” on OpenMP and CUDA, the device memory on CUDA).The checks: the
asanandtsanpresets’ test suites,ci/gpu_local.sh(the CUDA tests, the CUDA goldens and compute-sanitizer memcheck, synccheck and racecheck), the mutation CTests (ctest -L mutation) and the golden mutations (parity/mutate.py run --json benchmarks/results/<version>/mutation-goldens.json; 0.1:mutation-sssp.json), oneparity/certify.py checkeach.certify.pyrequires the checks ofREQUIRED_CHECKSby release series, each recorded with at least its scope: from 0.1asan,tsan,mutation-ctests(tests),distributions(packaging),check-parityandgpu_local(repo, with the steps memcheck, synccheck and racecheck passed), and the golden mutationsmutation-sssp(0.1 only, library); from 0.2 alsotsan-openmp(tests),mutation-goldens(library) andapi-check(repo,ci/api_check.sh). Themutation-goldensrecord itself is read: every mutation ofparity/mutate.py listmust be in it and detected, the control passed, its commit must have the release’s library sources and every replay a golden manifest ofgoldens.toml. For exampleparity/certify.py check --version 0.1.0rc1 --name asan --command "ctest --preset asan" \ --ctest-log asan-ctest.log --commit <the commit that was built> parity/certify.py check --version 0.1.0rc1 --name gpu_local --command ci/gpu_local.sh \ --scope repo --gpu-summary build/dev-cuda/gpu_local_summary.md \ --require-steps memcheck,synccheck,racecheck --tests-log gpu_local.log parity/certify.py check --version 0.1.0rc1 --name check-parity --scope repo \ --command "ci/check.sh --parity" --result passed --evidence check-parity.log \ --tests-log check-parity.log
(
--ctest-logreads ctest’s summary line,--gpu-summarythe step table ofci/gpu_local.sh,--json-verdicta record with a top-levelpassedsuch asmutation-sssp.json,--result passed|failed --details ...anything else); they collect inchecks.json.Every check names the commit that was built and its scope, the paths that must be the release’s (below). A ctest log (
--ctest-log, or--tests-logfor another log with ctest output, such asci/gpu_local.sh’s) also gives the per-test results the committed fixtures need. Every log a check names is recorded with its SHA-256 and size, and an excerpt (its step headers and result lines) is committed underbenchmarks/results/<version>/checks/; a check recorded with--resultalone must give its log with--evidence. A--gpu-summarycheck records the steps it required (--require-steps; a skipped step passes only if it was not required).
Then, on the committed release tree, parity/certify.py write --version <version> writes
parity.json and the generated part of README.md (between the certify markers; the text
around it is written by hand). The certificate records:
the release commit and the commits whose builds were measured, each of which must have the release commit’s sources in the paths of its scope (
git diff <measured> <release> -- <paths>is empty):Scope
Paths
For
librarycpp/include cpp/src cpp/CMakeLists.txt tools cmake CMakeLists.txt CMakePresets.json docs/references.bibthe gates, the golden replays,
mutate.py(check --scope library)teststhe library paths,
cpp/tests,cpp/fuzz(the fuzzers’ corpus and regressions, replayed by every test build),examplesandREADME.md(its C++ quickstart is a test)a C++ test suite: the sanitizer presets,
ctest -L mutation(the default ofcheck)packagingthe test paths,
python,pyproject.toml,VERSION,CHANGELOG.md,CITATION.cff, the licence files (THIRD_PARTY_LICENSES_CUDA.txttoo), every other top-level file the sdist ships (certify.sdist_members(), checked byparity/tests),ci/wheels.sh,ci/wheel_check.py,ci/wheel-toolchain.yml,release.yml,wheels.yml, and the CUDA plugins’ build inputs (ci/plugin_wheels.sh,ci/plugin_pyproject.py,ci/plugin_smoke.py,ci/without_cuda_driver.sh,ci/cuda_toolkit.py,ci/cuda_toolkits.toml,ci/cibw_plugin*.sh,ci/cibuildwheel-plugin.toml)the distributions (
select,ci/wheels.sh,ci/plugin_wheels.sh,twine check,wheel_check, the fresh venvs)repoevery tracked file but
benchmarks/results/a check of the whole tree:
ci/check.sh,ci/gpu_local.shVERSIONis not a library path: it only names the build, so a release candidate’s gates certify the final release (step 9 ofdocs/developer/release.md).The one exception: generated metadata. A measured commit whose library differs from the release’s only in
METADATA_PATHSofcertify.py(the manifestscpp/src/algorithms/<name>/manifest.tomlof every algorithm, which no build reads, andcpp/src/core/registry_table.inc, the registry tablescripts/regen.pygenerates from them, read only bydyng::algorithms()) still certifies the gates, the golden replays and the golden mutations, in the library scope only and never a test-suite check (whose tests read the registry), ifequivalence.jsonholds a passed pair for it whose release side has the release’s library. The pair is written byparity/certify.py equivalence --version <version> --measured <sha> --clone <a clean clone>
which refuses a difference outside
METADATA_PATHS, then builds, in that one clone and with the measured commit’sVERSIONand build system, the presetsparityandparity-cuda(targetsdyng-compat-mosp,dyng-compat-cycle-enum) twice: at the measured commit, and with the release’s library paths checked out over it. It compareslibdyng.soand both compat tools: each must be byte-identical, or equivalent, meaning every section and symbol at the same address and every differing byte inside the listed functions’ code (dyng::algorithms()) or in the build id, unwind and symbol tables. The 0.1.0rc1 certificate uses it (measured atd13d393, before the maturity change);the hardware, the CUDA and compiler versions, and the NVIDIA driver of the measurements: the one the records name (all equal, and equal to the driver seen when the certificate is written), or, for CUDA records that predate the per-record field (0.1.0rc1), the driver seen when the certificate is written, accepted only if it is shown unchanged since before the first measurement (the loaded kernel module, the boot time, the module file and
libcuda.so.1installed before it);the pinned originals (commit, the local
baseline-2026-09SHA, upstream);every golden set of
parity/goldens.tomlwith its manifest SHA-256, the SHA-256 of every case and every replay’s case x configuration matrix and tolerance;every committed fixture set of
cpp/tests/data(parity/fixtures/fixtures.toml: the generator script, the original and its commit, the CTests that compare the set) with the SHA-256 of its files and the result of each of its tests in the release checks;the suites the version requires (
required_suites, fromREQUIRED_SUITES), the performance-gate table of every suite (gated, and recorded-only readings separately) and how each reading’s inputs were verified. The table is recomputed, not copied: every gated row’s medians must be those of the compacted record next to the summary, its ratio port / original, its gate the suite file’s tolerance for the region (the short-region compute gate belowshort_region_ms) andwithin_gateratio <= gate, and the summary’s verdict and counts must agree with the rows; the README counts the recomputed rows;the checks, with their scopes and evidence.
It exits 1, and says why in verdict.problems, if any part failed or is missing (a required
suite, or a gated metric of a suite without a gated reading), if a replayed
manifest is not the one of goldens.toml, if a measured tree was dirty, if a suite summary is
not of the committed suite file (SHA-256), is partial, or misses, repeats or has an incomplete
reading of the suite’s plan, if a summary’s inputs are not verified, if a gated row does not
recompute, if a required check is missing or recorded with too narrow a scope, if the records’
drivers disagree, if a directory of cpp/tests/data is not in fixtures.toml, or if a fixture test
pattern was not passed by any release check (or failed in one).