ENH: Add ASV-over-native-ITK performance benchmark harness#111
Merged
hjmjohnson merged 2 commits intoInsightSoftwareConsortium:masterfrom Apr 21, 2026
Merged
Conversation
Add an airspeed-velocity (asv) harness that drives the existing native
C++ *Benchmark executables in this repository for longitudinal
performance-regression tracking. Designed to be consumed by
InsightSoftwareConsortium/ITK CI via a GitHub Actions workflow that
builds ITK at a PR's merge-base and HEAD, then invokes 'asv run'
against each build and compares the two.
Architecture
- environment_type: 'existing' keeps ASV out of the ITK build loop.
ASV does not recompile ITK or interpret benchmark results
numerically; the build is managed entirely by the consuming CI
workflow.
- Each ASV benchmark is a track_* function returning seconds parsed
from the jsonxx output of HighPriorityRealTimeProbesCollector,
bypassing ASV's wall-clock instrumentation of the Python callable.
- repo: 'itk-repo' — the caller places a symlink named 'itk-repo' at
the harness root pointing to the ITK clone. This lets ASV validate
--set-commit-hash values against git, so result labels track ITK
history rather than this repository's history.
Contents
asv.conf.json
ASV configuration (environment_type=existing, repo=itk-repo,
install_command installs the shim from ./python).
python/itk_perf_shim/
Python shim that invokes benchmark executables via subprocess,
parses the jsonxx timings file, and returns mean probe seconds.
registry.py maps logical benchmark names to executable name and
CLI template. runner.py handles subprocess invocation,
environment-variable resolution, tempfile management, and JSON
parsing.
benchmarks/{core,filtering,segmentation}.py
11 track_* benchmark functions covering Core (2: copy, vector
iteration), Filtering (5: binary_add, unary_add,
gradient_magnitude, median, min_max_curvature_flow), and
Segmentation (4: region_growing, watershed,
morphological_watershed, level_set).
README-asv.md
Design notes, environment-variable contract, local smoke-test
recipe, and the PR comparison pattern invoked by CI.
Scope
Registration and Resample benchmarks are intentionally omitted from
this initial harness. Their C++ sources hit ITK-level build issues
(NrrdIO airFloatQNaN link, ResampleBenchmark -Wmaybe-uninitialized)
that are unrelated to the harness and need to be addressed upstream
before those benchmarks can be included. Adding them later is a
small registry + benchmarks/ edit.
Validation
All 11 benchmarks were smoke-tested end-to-end against a local ITK
build on 2026-04-19 (ITK at v5.4.0-69-g3a8d2fa64b,
Module_PerformanceBenchmarking=ON). 'asv check' passes, 'asv run'
produces sensible timings, and 'asv compare' emits a markdown diff
table suitable for posting as a PR comment.
Supersedes the stalled 'wasm-asv' direction on thewtex's fork (last
touched 2024-05-29, 4c50054), which introduced a
pnpm+emscripten+wasi dependency surface inappropriate for a pure
regression-detection harness.
8b46397 to
b2881fd
Compare
…ression The previous CreateAndInitializeImage used it.Set(static_cast<PixelType>(count)); to seed pixel values. For scalar and FixedArray pixels this performs a value cast, but for VectorImage (where PixelType is itk::VariableLengthVector<T>) it invokes the LENGTH constructor — producing a vector of size 'count', not a N-component pixel with value 'count'. In particular the first iteration produces a length-0 VLV, which ITK commit 1d87efa52 changed to store a null data pointer. Under ITK >= 1d87efa52, the iterator's implicit copy of NumberOfComponentsPerPixel elements from that null source causes a SIGSEGV. Under earlier ITK, the out-of-spec read 'happens to work' by reading uninitialized memory. Either way, the benchmark was never constructing semantically correct pixel values for the VectorImage case. Introduce a PixelFiller trait that specializes for VariableLengthVector so the VectorImage branch constructs a properly sized VLV and Fills it with 'count'. Scalar and FixedArray branches keep the existing static_cast path. With this change the benchmark produces well-defined output across the ITK v5.3 -> main range regardless of the internal representation of VariableLengthVector(0).
4 tasks
Member
|
Sounds great, and looks good on a glance. I can hardly wait to see this fully integrated into our CI! |
hjmjohnson
added a commit
to thewtex/ITK
that referenced
this pull request
Apr 22, 2026
Adds .github/workflows/perf-benchmark.yml — a GitHub Actions workflow that builds ITK twice (merge-base and PR HEAD) with the PerformanceBenchmarking remote module enabled, then drives the ASV harness from InsightSoftwareConsortium/ITKPerformanceBenchmarking#111 against each build to produce an asv compare report. Bumps the PerformanceBenchmarking remote module pin from 7950c1d76095033edbf7601a925cdacc2fe717f9 to 41bf1b9cfbaa1b146e1b3e5d3ad3571b2203ce1e (master HEAD, post-InsightSoftwareConsortium#111). The new pin carries: * asv.conf.json, benchmarks/{core,filtering,segmentation}.py, python/itk_perf_shim/ (the ASV harness). * Hardened examples/Core/itkCopyIterationBenchmark.cxx that no longer crashes on VectorImage under ITK >= 1d87efa (the VLV null-data regression; see InsightSoftwareConsortium#6087 for the parallel ITK-side defensive null-guard). Supersedes the 2019 Azure Pipelines macos-11 approach; macos-11 is retired and the older evaluate-itk-performance.py driver has been replaced by the ASV-native harness. For the very first PR (this one) the merge-base lacks the new pin, so its benchmark run is best-effort and the asv compare step is wrapped with continue-on-error. The workflow becomes fully useful for regression detection after this PR lands.
hjmjohnson
added a commit
to thewtex/ITK
that referenced
this pull request
Apr 22, 2026
Adds .github/workflows/perf-benchmark.yml — a GitHub Actions workflow that builds ITK twice (merge-base and PR HEAD) with the PerformanceBenchmarking remote module enabled, then drives the ASV harness from InsightSoftwareConsortium/ITKPerformanceBenchmarking#111 against each build to produce an asv compare report. Bumps the PerformanceBenchmarking remote module pin from 7950c1d76095033edbf7601a925cdacc2fe717f9 to 41bf1b9cfbaa1b146e1b3e5d3ad3571b2203ce1e (master HEAD, post-InsightSoftwareConsortium#111). The new pin carries: * asv.conf.json, benchmarks/{core,filtering,segmentation}.py, python/itk_perf_shim/ (the ASV harness). * Hardened examples/Core/itkCopyIterationBenchmark.cxx that no longer crashes on VectorImage under ITK >= 1d87efa (the VLV null-data regression; see InsightSoftwareConsortium#6087 for the parallel ITK-side defensive null-guard). Supersedes the 2019 Azure Pipelines macos-11 approach; macos-11 is retired and the older evaluate-itk-performance.py driver has been replaced by the ASV-native harness. For the very first PR (this one) the merge-base lacks the new pin, so its benchmark run is best-effort and the asv compare step is wrapped with continue-on-error. The workflow becomes fully useful for regression detection after this PR lands.
hjmjohnson
added a commit
to thewtex/ITK
that referenced
this pull request
Apr 23, 2026
Adds .github/workflows/perf-benchmark.yml — a GitHub Actions workflow that builds ITK twice (merge-base and PR HEAD) with the PerformanceBenchmarking remote module enabled, then drives the ASV harness from InsightSoftwareConsortium/ITKPerformanceBenchmarking#111 against each build to produce an asv compare report. Bumps the PerformanceBenchmarking remote module pin from 7950c1d76095033edbf7601a925cdacc2fe717f9 to 41bf1b9cfbaa1b146e1b3e5d3ad3571b2203ce1e (master HEAD, post-InsightSoftwareConsortium#111). The new pin carries: * asv.conf.json, benchmarks/{core,filtering,segmentation}.py, python/itk_perf_shim/ (the ASV harness). * Hardened examples/Core/itkCopyIterationBenchmark.cxx that no longer crashes on VectorImage under ITK >= 1d87efa (the VLV null-data regression; see InsightSoftwareConsortium#6087 for the parallel ITK-side defensive null-guard). Supersedes the 2019 Azure Pipelines macos-11 approach; macos-11 is retired and the older evaluate-itk-performance.py driver has been replaced by the ASV-native harness. For the very first PR (this one) the merge-base lacks the new pin, so its benchmark run is best-effort and the asv compare step is wrapped with continue-on-error. The workflow becomes fully useful for regression detection after this PR lands.
hjmjohnson
added a commit
to thewtex/ITK
that referenced
this pull request
Apr 23, 2026
Adds .github/workflows/perf-benchmark.yml — a GitHub Actions workflow that builds ITK twice (merge-base and PR HEAD) with the PerformanceBenchmarking remote module enabled, then drives the ASV harness from InsightSoftwareConsortium/ITKPerformanceBenchmarking#111 against each build to produce an asv compare report. Bumps the PerformanceBenchmarking remote module pin from 7950c1d76095033edbf7601a925cdacc2fe717f9 to 41bf1b9cfbaa1b146e1b3e5d3ad3571b2203ce1e (master HEAD, post-InsightSoftwareConsortium#111). The new pin carries: * asv.conf.json, benchmarks/{core,filtering,segmentation}.py, python/itk_perf_shim/ (the ASV harness). * Hardened examples/Core/itkCopyIterationBenchmark.cxx that no longer crashes on VectorImage under ITK >= 1d87efa (the VLV null-data regression; see InsightSoftwareConsortium#6087 for the parallel ITK-side defensive null-guard). Supersedes the 2019 Azure Pipelines macos-11 approach; macos-11 is retired and the older evaluate-itk-performance.py driver has been replaced by the ASV-native harness. For the very first PR (this one) the merge-base lacks the new pin, so its benchmark run is best-effort and the asv compare step is wrapped with continue-on-error. The workflow becomes fully useful for regression detection after this PR lands.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds an airspeed-velocity (asv) harness that drives the existing native C++
*Benchmarkexecutables for longitudinal performance-regression tracking. Intended for use from ITK CI — companion change to InsightSoftwareConsortium/ITK#612 (replacing the retired Azuremacos-11job).Also hardens
CopyIterationBenchmarkagainst a SIGSEGV exposed by ITK commit1d87efa52, so the benchmark runs cleanly across the entire ITK v5.3 → current main range.Architecture (ASV harness)
environment_type: "existing"keeps ASV out of the ITK build loop. The consuming CI workflow builds ITK (base + head) and points the shim at each build viaITK_BENCHMARK_BIN.track_*returning seconds parsed from the jsonxx output ofHighPriorityRealTimeProbesCollector, bypassing ASV's wall-clock instrumentation of the Python callable.repo: "itk-repo"— the caller places a symlink nameditk-repoat the harness root pointing at the ITK clone. This lets ASV validate--set-commit-hashvalues against git, so result labels track ITK history rather than this repository's history.Contents
asv.conf.json— ASV configurationpython/itk_perf_shim/— subprocess shim parsing jsonxx timingsbenchmarks/{core,filtering,segmentation}.py— 11 prototype benchmarksREADME-asv.md— design notes and smoke-test recipe (validated)examples/Core/itkCopyIterationBenchmark.cxx— harden VectorImage pixel constructionCopyIterationBenchmark hardening
Previously,
CreateAndInitializeImageseeded pixels viait.Set(static_cast<PixelType>(count)). For scalar / FixedArray pixels this is a value cast, but forVectorImage— whosePixelTypeisitk::VariableLengthVector<T>— it invokes the VLV length constructor:VLV<float>(count)yields a vector of sizecount, not a 3-component vector with valuecount. The first iteration produces a length-0 VLV; ITK'sDefaultVectorPixelAccessor::Setthen copiesNumberOfComponentsPerPixelelements from that source's internal data pointer, which isnullptron ITK ≥1d87efa52→ SIGSEGV.This commit introduces a
PixelFiller<T>trait specialized forVariableLengthVector<T>that constructs a correctly-sized VLV andFills it withcount. The scalar / FixedArray path is unchanged. The benchmark now produces well-defined output across the full ITK bisect range regardless of the internal representation ofVariableLengthVector(0).A companion ITK-side fix is proposed in InsightSoftwareConsortium/ITK#6087 — defensive null-guard in the pixel accessor so any other caller that triggers the same class of bug no longer crashes.
Scope
Harness covers Core (2), Filtering (5), and Segmentation (4) benchmarks — all smoke-validated end-to-end. Registration and Resample benchmarks are intentionally omitted; their C++ sources hit unrelated ITK-level build issues (NrrdIO
airFloatQNaNlink, Resample-Wmaybe-uninitialized) that are outside the scope of this PR. Adding them later is a small registry + benchmarks/ edit.Relation to the prior wasm-asv effort
Supersedes the stalled
wasm-asvdirection on @thewtex's fork (last touched 2024-05-29), which introduced a pnpm+emscripten+wasi dependency surface inappropriate for a pure regression-detection harness.Smoke-test sample output
asv compareagainst two labeled runs of the same binary (same-machine jitter only):Test plan
asv check --python=samediscovers all benchmarks cleanlyasv runagainst a local ITK v5.4.5 build (79/79 tests pass, validated 2026-04-19)CopyIterationBenchmarkruns cleanly with the hardening (was SIGSEGV before this commit)HighPriorityRealTimeProbesCollectoroutput