From 11a30a0e330e77082a7d61a3340c38cc71fbe38b Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Mon, 12 Jan 2026 07:10:53 -0500 Subject: [PATCH] Add allocation tests to prevent performance regressions This adds a new test file `test/alloc_tests.jl` that verifies zero allocations for all core solver step functions. The tests verify: - SimpleTsit5 step! (OOP and IIP) - SimpleRK4 step! (OOP and IIP) - SimpleEuler step! (OOP and IIP) - SimpleATsit5 step! (OOP and IIP) The tests use @allocated to verify zero heap allocations at runtime, ensuring the high-performance characteristics of these solvers are maintained. The tests are included in the "nopre" CI group alongside the existing JET static analysis tests. Co-Authored-By: Claude Opus 4.5 --- test/alloc_tests.jl | 92 +++++++++++++++++++++++++++++++++++++++++++++ test/runtests.jl | 1 + 2 files changed, 93 insertions(+) create mode 100644 test/alloc_tests.jl diff --git a/test/alloc_tests.jl b/test/alloc_tests.jl new file mode 100644 index 0000000..1a5cb33 --- /dev/null +++ b/test/alloc_tests.jl @@ -0,0 +1,92 @@ +using SimpleDiffEq +using DiffEqBase +using StaticArrays +using Test + +@testset "Allocation Tests - Zero Allocation Verification" begin + # Define test problems (Lorenz system) + function loop_oop(u, p, t) + @inbounds begin + σ = p[1] + ρ = p[2] + β = p[3] + du1 = σ * (u[2] - u[1]) + du2 = u[1] * (ρ - u[3]) - u[2] + du3 = u[1] * u[2] - β * u[3] + return SVector{3}(du1, du2, du3) + end + end + + function loop_iip!(du, u, p, t) + σ = p[1] + ρ = p[2] + β = p[3] + du[1] = σ * (u[2] - u[1]) + du[2] = u[1] * (ρ - u[3]) - u[2] + du[3] = u[1] * u[2] - β * u[3] + return nothing + end + + u0_vec = [10.0, 10.0, 10.0] + u0_svec = SVector{3}(10.0, 10.0, 10.0) + dt = 0.01 + p = [10.0, 28.0, 8 / 3] + + @testset "SimpleTsit5 step! - zero allocations" begin + # OOP (out-of-place) with SVector + integ_oop = SimpleDiffEq.simpletsit5_init(loop_oop, false, u0_svec, 0.0, dt, p) + step!(integ_oop) # warmup + allocs = @allocated step!(integ_oop) + @test allocs == 0 + + # IIP (in-place) with Vector + integ_iip = SimpleDiffEq.simpletsit5_init(loop_iip!, true, copy(u0_vec), 0.0, dt, p) + step!(integ_iip) # warmup + allocs = @allocated step!(integ_iip) + @test allocs == 0 + end + + @testset "SimpleRK4 step! - zero allocations" begin + # OOP (out-of-place) with SVector + integ_oop = SimpleDiffEq.simplerk4_init(loop_oop, false, u0_svec, 0.0, dt, p) + step!(integ_oop) # warmup + allocs = @allocated step!(integ_oop) + @test allocs == 0 + + # IIP (in-place) with Vector + integ_iip = SimpleDiffEq.simplerk4_init(loop_iip!, true, copy(u0_vec), 0.0, dt, p) + step!(integ_iip) # warmup + allocs = @allocated step!(integ_iip) + @test allocs == 0 + end + + @testset "SimpleEuler step! - zero allocations" begin + # OOP (out-of-place) with SVector + integ_oop = SimpleDiffEq.simpleeuler_init(loop_oop, false, u0_svec, 0.0, dt, p) + step!(integ_oop) # warmup + allocs = @allocated step!(integ_oop) + @test allocs == 0 + + # IIP (in-place) with Vector + integ_iip = SimpleDiffEq.simpleeuler_init(loop_iip!, true, copy(u0_vec), 0.0, dt, p) + step!(integ_iip) # warmup + allocs = @allocated step!(integ_iip) + @test allocs == 0 + end + + @testset "SimpleATsit5 step! - zero allocations" begin + # OOP (out-of-place) with SVector + prob_oop = ODEProblem{false}(loop_oop, u0_svec, (0.0, 100.0), p) + integ_oop = DiffEqBase.__init(prob_oop, SimpleATsit5(), dt = dt) + step!(integ_oop) # warmup + allocs = @allocated step!(integ_oop) + @test allocs == 0 + + # IIP (in-place) with Vector + prob_iip = ODEProblem{true}(loop_iip!, copy(u0_vec), (0.0, 100.0), p) + integ_iip = DiffEqBase.__init(prob_iip, SimpleATsit5(), dt = dt) + step!(integ_iip) # warmup + allocs = @allocated step!(integ_iip) + @test allocs == 0 + end +end diff --git a/test/runtests.jl b/test/runtests.jl index ffd59d1..f562f3c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -20,5 +20,6 @@ const GROUP = get(ENV, "GROUP", "Core") import Pkg Pkg.add("JET") @time @safetestset "JET Static Analysis Tests" include("jet_tests.jl") + @time @safetestset "Allocation Tests" include("alloc_tests.jl") end end