From 7dcb702063ffaebbb88d3e073d528b2b1e3a37cf Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Fri, 11 Sep 2026 17:58:53 -0400 Subject: [PATCH] Add AirspeedVelocity benchmarking CI Adds a benchmark workflow (Julia 1 and lts) and a benchmark/benchmarks.jl suite covering representative workloads so PRs check for performance regressions. Co-Authored-By: Chris Rackauckas Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> Agent-Harness: devin 3000.10.21 (611c1cba) Agent-Model: SWE-2 High Agent-Session: local session transcript /home/crackauc/sandbox/tmp_20260911_112052_59120/history_6a789c0b69c64ca3.md --- .github/workflows/benchmark.yml | 29 ++++++++++++++ benchmark/benchmarks.jl | 71 +++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 .github/workflows/benchmark.yml create mode 100644 benchmark/benchmarks.jl diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 0000000..b35da5d --- /dev/null +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,29 @@ +name: Benchmark this PR + +on: + pull_request: + branches: [master] + paths-ignore: ['docs/**'] + +permissions: + pull-requests: write + contents: read + +jobs: + benchmark: + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + version: ["1", "lts"] + env: + # Force consistent Julia depot path for self-hosted runners + JULIA_DEPOT_PATH: ~/.julia + steps: + - uses: MilesCranmer/AirspeedVelocity.jl@action-v1 + with: + julia-version: ${{ matrix.version }} + script: "benchmark/benchmarks.jl" + extra-pkgs: "StableRNGs" + job-summary: true diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl new file mode 100644 index 0000000..b988ba3 --- /dev/null +++ b/benchmark/benchmarks.jl @@ -0,0 +1,71 @@ +using MultiScaleArrays, BenchmarkTools +using StableRNGs + +const SUITE = BenchmarkGroup() +const rng = StableRNG(123) + +# Minimal multi-scale hierarchy: Cell -> Population -> Tissue +struct Cell{B} <: AbstractMultiScaleArrayLeaf{B} + values::Vector{B} +end +struct Population{T <: AbstractMultiScaleArray, B <: Number} <: + AbstractMultiScaleArray{B} + nodes::Vector{T} + values::Vector{B} + end_idxs::Vector{Int} +end +struct Tissue{T <: AbstractMultiScaleArray, B <: Number} <: + AbstractMultiScaleArrayHead{B} + nodes::Vector{T} + values::Vector{B} + end_idxs::Vector{Int} +end + +function make_tissue(npops, ncells) + cells = [Cell(rand(rng, 4)) for _ in 1:ncells] + pops = [construct(Population, deepcopy(cells)) for _ in 1:npops] + return construct(Tissue, pops) +end + +tissue = make_tissue(10, 20) +tissue_big = make_tissue(50, 40) + +# ============================================================================= +# Construction +# ============================================================================= + +SUITE["construct"] = BenchmarkGroup() + +cells_small = [Cell(rand(rng, 4)) for _ in 1:20] +pops_small = [construct(Population, deepcopy(cells_small)) for _ in 1:10] + +SUITE["construct"]["population"] = @benchmarkable construct( + Population, $(deepcopy(cells_small)) +) +SUITE["construct"]["tissue"] = @benchmarkable construct( + Tissue, $(deepcopy(pops_small)) +) + +# ============================================================================= +# Traversal +# ============================================================================= + +SUITE["iterate"] = BenchmarkGroup() + +SUITE["iterate"]["level_iter"] = @benchmarkable collect(level_iter($tissue, 1)) +SUITE["iterate"]["level_iter_big"] = @benchmarkable collect( + level_iter($tissue_big, 2) +) +SUITE["iterate"]["eachindex"] = @benchmarkable sum(x -> x, $tissue_big) + +# ============================================================================= +# Node mutation +# ============================================================================= + +SUITE["nodes"] = BenchmarkGroup() + +SUITE["nodes"]["add_node!"] = @benchmarkable add_node!(t, p) setup = ( + t = make_tissue(10, 20); + p = construct(Population, [Cell(rand($rng, 4)) for _ in 1:5]) +) +SUITE["nodes"]["num_nodes"] = @benchmarkable num_nodes($tissue_big)