Skip to content

Run tests with JULIA_NUM_THREADS=2 so #570 regression test is covered#571

Merged
ChrisRackauckas merged 1 commit intoSciML:masterfrom
ChrisRackauckas-Claude:fix-issue-570-threaded-voa-test-coverage
Apr 5, 2026
Merged

Run tests with JULIA_NUM_THREADS=2 so #570 regression test is covered#571
ChrisRackauckas merged 1 commit intoSciML:masterfrom
ChrisRackauckas-Claude:fix-issue-570-threaded-voa-test-coverage

Conversation

@ChrisRackauckas-Claude
Copy link
Copy Markdown
Contributor

@ChrisRackauckas-Claude ChrisRackauckas-Claude commented Apr 5, 2026

Summary

  • Issue Multi-threading VectorOfArray of SVectors is broken on RecursiveArrayTools.jl version 4 #570 reported @.. thread=true on VectorOfArray{SArray} blew up on v4.0.1. PRs Multithreading with RecursiveArrayTools.VectorOfArray is broken #564/Add Polyester threading extension for FastBroadcast VectorOfArray #567 already fixed the dispatch path on master (base-ext ::Threaded fallback → Serial, plus a Polyester ext for <:AbstractVector{<:SArray} storage), and master does handle Ranocha's reproducer correctly — verified locally against a Pkg.develop'd master.
  • However, the regression testset added in Multithreading with RecursiveArrayTools.VectorOfArray is broken #564 (test/interface_tests.jl "Threaded @.. with VectorOfArray{SArray}") only triggers the failing code path when Threads.nthreads() >= 2. FastBroadcast's Polyester-backed threaded materialize splits work along the last axis via view(dst, :, r); with a single thread that split is a no-op and the bad scalar setindex! loop is never reached.
  • Previously .github/workflows/Tests.yml delegated to SciML/.github/.github/workflows/tests.yml@v1, which does not accept a thread-count input and does not set JULIA_NUM_THREADS, so CI ran with Threads.nthreads() == 1 and the regression test silently passed without covering the bug.
  • Inline the test job (dropping the reusable workflow) and set JULIA_NUM_THREADS: "2" as env on the julia-actions/julia-runtest@v1 step. Mirrors SciML/OrdinaryDiffEq.jl's SublibraryCI.yml, which passes JULIA_NUM_THREADS: ${{ matrix.num_threads }} the same way. No test-file changes needed.

Root cause (for context, already fixed on master)

  1. @.. thread=true v = v + u on VectorOfArray{Float64,2,Matrix{SVector{2,Float64}}} dispatches to FastBroadcast.fast_materialize!(::Threaded, dst, bc).
  2. On v4.0.1 there was no ::Threaded method for VectorOfArray in the RAT extension, so dispatch fell through to the fully generic FastBroadcast.jl:215 fallback → Polyester batches work by taking view(dst, :, r), producing a SubArray wrapping the VoA.
  3. Each batch then called FastBroadcast's generic __fast_materialize! scalar loop → subview[i,j] = valueVectorOfArray.setindex!(VA, v, I::Int...) at src/vector_of_array.jl:904VA.u[col][inner_I...] = vsetindex!(::SVector, …) which throws on the immutable SVector.
  4. Multithreading with RecursiveArrayTools.VectorOfArray is broken #564/Add Polyester threading extension for FastBroadcast VectorOfArray #567 added a base-ext fast_materialize!(::Threaded, ::AbstractVectorOfArray, ::Broadcasted) fallback that shunts to Serial(), avoiding the view-splitting path, plus a Polyester ext that genuinely threads <:AbstractVector{<:SArray} storage. The Matrix{<:SArray} case from Ranocha's reproducer still only runs serially (the type alias is <:AbstractVector{<:SArray}), but the fallback keeps it correct.

Test plan

  • Local: ran test/interface_tests.jl with JULIA_NUM_THREADS=2 against a Pkg.develop'd master → Threaded @.. with VectorOfArray{SArray} | 2 pass.
  • Local: ran Ranocha's exact reproducer from Multi-threading VectorOfArray of SVectors is broken on RecursiveArrayTools.jl version 4 #570 under JULIA_NUM_THREADS=2 against master → v = [2.0 2.0 2.0 2.0; 2.0 2.0 2.0 2.0]; against v4.0.1 the same reproducer still throws as reported.
  • CI green on the existing {version × group} matrix, now with 2 threads per job.

Follow-up (not in this PR)

🤖 Generated with Claude Code

…ciML#570

The regression test added in SciML#564 for `@.. thread=true` on
`VectorOfArray{SArray}` only triggers the bug path when
`Threads.nthreads() >= 2`. FastBroadcast's Polyester-backed threaded
materialize splits work along the last axis via `view(dst, :, r)`; with
a single thread that split is a no-op, so the `setindex!` loop that
originally blew up on the immutable `SVector` element in issue SciML#570 is
never reached. CI was delegating to SciML/.github's reusable tests
workflow with no thread configuration, meaning `Threads.nthreads() == 1`
in CI and the regression test was silently passing without actually
exercising the regression.

Inline the previously-reusable test job and set `JULIA_NUM_THREADS: "2"`
on the `julia-actions/julia-runtest` step, mirroring SciML/OrdinaryDiffEq.jl's
SublibraryCI.yml. No changes to the test file are needed.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@ChrisRackauckas-Claude ChrisRackauckas-Claude force-pushed the fix-issue-570-threaded-voa-test-coverage branch from adffd1e to 65a3b35 Compare April 5, 2026 13:23
@ChrisRackauckas-Claude ChrisRackauckas-Claude changed the title Actually exercise multi-threading in VoA{SArray} regression test (#570) Run tests with JULIA_NUM_THREADS=2 so #570 regression test is covered Apr 5, 2026
@ChrisRackauckas ChrisRackauckas merged commit 9afa4f2 into SciML:master Apr 5, 2026
33 of 37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants