From 22e10ca755a47d0bcd147ea1c4078af23d0e369e Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Thu, 8 Oct 2026 23:39:39 -0400 Subject: [PATCH 1/2] Avoid reject_step! RSwM3 temporaries on the in-place path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Form the S₁ stack entry by mutating the just-popped S₂ slot in place so warmed adaptive SDE steps no longer allocate L₂ - dWtilde / L₃ - dZtilde arrays on every nonempty-S₂ rejection. Co-Authored-By: Chris Rackauckas Co-Authored-By: Cursor Agent Agent-Harness: Cursor Agent 2026.10.01-14929f9 Agent-Model: unknown (Cursor auto) Agent-Session: local session, transcript /home/crackauc/sandbox/goals/performance/jobs/sde/pr-dnp-reject/log.txt on amdci2 --- .../noise_process_interface.jl | 6 ++++- test/RSwM_correctness_test.jl | 22 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/noise_interfaces/noise_process_interface.jl b/src/noise_interfaces/noise_process_interface.jl index 6d9250c..79e14f6 100644 --- a/src/noise_interfaces/noise_process_interface.jl +++ b/src/noise_interfaces/noise_process_interface.jl @@ -466,7 +466,11 @@ must throw an informative error instead of silently reusing an invalid increment # slot L₂ was popped from. cutLength = L₁ - dtM if cutLength > W.rswm.discard_length - if W.Z == nothing + if isinplace(W) + @.. L₂ -= W.dWtilde + W.Z !== nothing && @.. L₃ -= W.dZtilde + ResettableStacks.copyat_or_push!(W.S₁, (cutLength, L₂, L₃)) + elseif W.Z == nothing ResettableStacks.copyat_or_push!( W.S₁, (cutLength, L₂ - W.dWtilde, nothing) ) diff --git a/test/RSwM_correctness_test.jl b/test/RSwM_correctness_test.jl index 55d4d01..776017b 100644 --- a/test/RSwM_correctness_test.jl +++ b/test/RSwM_correctness_test.jl @@ -173,4 +173,26 @@ end end end + + @testset "RSwM3 in-place S₂ bridge reject_step! does not allocate" begin + # Forming L₂ - W.dWtilde / L₃ - W.dZtilde before copyat_or_push! allocates on + # every nonempty-S₂ rejection (~192 B/reject for length-4 W and Z). Mutating + # the popped S₂ slot in place must keep a warmed reject_step! at 0 B. + W = WienerProcess!( + 0.0, zeros(4), zeros(4); + rswm = RSWM(adaptivealg = :RSwM3), rng = Xoshiro(7) + ) + calculate_step!(W, 0.2, nothing, nothing) + for _ in 1:50 + reject_step!(W, 0.5 * W.dt, nothing, nothing) + accept_step!(W, 0.2, nothing, nothing) + end + total = 0 + for _ in 1:100 + @test !isempty(W.S₂) + total += @allocated reject_step!(W, 0.5 * W.dt, nothing, nothing) + accept_step!(W, 0.2, nothing, nothing) + end + @test total == 0 + end end From 5a6017422cd95dd9b7be9e5ea181ddf5b4d8c07e Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Fri, 9 Oct 2026 11:56:44 -0400 Subject: [PATCH 2/2] Fix LTS allocation test world-age false positive Measure reject_step! through a local function so @allocated sees a compiled call site under SciMLTesting's @safetestset on Julia 1.10. Co-Authored-By: Chris Rackauckas Co-Authored-By: Cursor Agent Agent-Harness: Cursor Agent CLI Agent-Model: auto --- test/RSwM_correctness_test.jl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/RSwM_correctness_test.jl b/test/RSwM_correctness_test.jl index 776017b..11c15e1 100644 --- a/test/RSwM_correctness_test.jl +++ b/test/RSwM_correctness_test.jl @@ -175,9 +175,6 @@ end @testset "RSwM3 in-place S₂ bridge reject_step! does not allocate" begin - # Forming L₂ - W.dWtilde / L₃ - W.dZtilde before copyat_or_push! allocates on - # every nonempty-S₂ rejection (~192 B/reject for length-4 W and Z). Mutating - # the popped S₂ slot in place must keep a warmed reject_step! at 0 B. W = WienerProcess!( 0.0, zeros(4), zeros(4); rswm = RSWM(adaptivealg = :RSwM3), rng = Xoshiro(7) @@ -187,10 +184,14 @@ reject_step!(W, 0.5 * W.dt, nothing, nothing) accept_step!(W, 0.2, nothing, nothing) end + # Measure through a local function so @allocated sees a compiled call site. + # A bare `@allocated reject_step!(...)` after `using` inside `@testset` / + # `@safetestset` leaves a 32 B/call world-age artifact on Julia 1.10. + measure_reject(W) = @allocated reject_step!(W, 0.5 * W.dt, nothing, nothing) total = 0 for _ in 1:100 @test !isempty(W.S₂) - total += @allocated reject_step!(W, 0.5 * W.dt, nothing, nothing) + total += measure_reject(W) accept_step!(W, 0.2, nothing, nothing) end @test total == 0