(feat): setfield!-based N-D wrapper reuse (Julia 1.11+) with 1.10 legacy fallback#20
(feat): setfield!-based N-D wrapper reuse (Julia 1.11+) with 1.10 legacy fallback#20
setfield!-based N-D wrapper reuse (Julia 1.11+) with 1.10 legacy fallback#20Conversation
Replace 4-way set-associative cache with Dict{Int,Vector{Any}}-keyed
wrapper cache that uses setfield!(:size) and setfield!(:ref) for
zero-allocation Array reuse. Eliminates CACHE_WAYS=4 eviction limit —
unlimited dimension patterns per slot after warmup.
- types.jl: nd_arrays/nd_dims/nd_ptrs/nd_next_way → nd_wrappers Dict
- acquire.jl: rewrite get_nd_array! with setfield! + _store_nd_wrapper!
- bitarray.jl: rewrite get_bitarray! with setfield!(:len/:dims/:chunks)
- state.jl: simplify empty! (4 calls → 1)
- Bump julia compat 1.10 → 1.11, version 0.2.1 → 0.3.0
Fix: always update MemoryRef (no pointer guard) — resize! can grow
vectors in-place without changing pointer, staling cached Memory length.
Extend compat range from Julia 1.11 down to 1.10 by introducing
version-gated includes in AdaptiveArrayPools.jl. Julia 1.11+ uses the
setfield!-based N-D wrapper reuse path; Julia 1.10 falls back to
src/legacy/ (N-way eviction cache). Version bumped to 0.2.2.
- Add @static VERSION guards in main module for types/acquire/bitarray/state
- Add src/legacy/{types,acquire,bitarray,state}.jl for Julia 1.10
- Gate 5-way and 10+-pattern allocation tests by VERSION
- Exclude src/legacy/ from codecov reporting
- Trim verbose docstrings for clarity
Replace Dict{Int,Vector{Any}} (hash-based, ~5-10ns per lookup) with
Vector{Union{Nothing,Vector{Any}}} indexed directly by N (dimensionality,
~1ns per lookup) for the nd_wrappers cache in TypedPool and BitTypedPool.
Also fix _store_nd_wrapper! to use resize! instead of while+push! loop
for growing the per-slot wrapper vector.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #20 +/- ##
==========================================
- Coverage 96.47% 95.38% -1.09%
==========================================
Files 9 13 +4
Lines 1276 1756 +480
==========================================
+ Hits 1231 1675 +444
- Misses 45 81 +36
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR modernizes N-D wrapper reuse by switching the CPU unsafe_acquire!/BitArray paths to setfield!-based in-place wrapper mutation on Julia 1.11+, while preserving Julia 1.10 behavior via a src/legacy/ fallback. It also updates tests and documentation to reflect the new caching model (unlimited dimension patterns per slot after warmup).
Changes:
- Replace the CPU N-way set-associative N-D wrapper cache with
nd_wrappers+setfield!reuse (Julia 1.11+), withsrc/legacy/*providing the prior 1.10 implementation. - Update BitArray wrapper reuse to use
setfield!-based mutation (Julia 1.11+). - Add/version-gate tests and refresh docs for the new caching behavior and
CACHE_WAYSscope.
Reviewed changes
Copilot reviewed 24 out of 25 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
src/AdaptiveArrayPools.jl |
Version-gates includes to switch between 1.11+ and legacy 1.10 implementations. |
src/types.jl |
Replaces old N-way cache fields with nd_wrappers in pool types and updates docstrings. |
src/acquire.jl |
Implements _store_nd_wrapper! and get_nd_array! wrapper reuse via setfield! (1.11+). |
src/bitarray.jl |
Implements BitArray wrapper reuse via nd_wrappers + setfield! updates (1.11+). |
src/state.jl |
Simplifies empty! to clear nd_wrappers instead of multiple N-way vectors. |
src/legacy/types.jl |
Adds legacy 1.10 types/constants (including N-way cache + CACHE_WAYS). |
src/legacy/acquire.jl |
Adds legacy 1.10 acquire path with N-way cache logic. |
src/legacy/bitarray.jl |
Adds legacy 1.10 BitArray acquisition with N-way caching. |
src/legacy/state.jl |
Adds legacy 1.10 state management with empty! clearing N-way cache fields. |
test/runtests.jl |
Version-gates which tests/helpers to include (1.11+ vs legacy). |
test/test_state.jl |
Switches N-D cache preservation assertion to _test_nd_cache_preserved. |
test/test_nway_cache.jl |
Updates allocation expectations for 1.11+ and adds nd_wrappers-specific tests. |
test/legacy/test_nway_cache.jl |
Introduces legacy-only tests that preserve N-way eviction/allocation expectations. |
docs/src/reference/api.md |
Clarifies set_cache_ways! relevance (1.10/CUDA; no effect on 1.11+ CPU). |
docs/src/features/cuda-support.md |
Updates CUDA docs to distinguish CPU 1.11+ behavior vs CUDA N-way cache. |
docs/src/features/configuration.md |
Updates CACHE_WAYS documentation scope (1.10/CUDA). |
docs/src/features/bit-arrays.md |
Updates BitArray caching description for 1.11+ vs 1.10/CUDA. |
docs/src/basics/api-essentials.md |
Updates unsafe_acquire! allocation behavior by Julia version. |
docs/src/architecture/type-dispatch.md |
Documents new nd_wrappers approach + legacy N-way path. |
docs/src/architecture/how-it-works.md |
Documents wrapper reuse on 1.11+ and legacy/cuda behavior. |
docs/src/architecture/design-docs.md |
Notes N-way cache is now legacy on CPU 1.11+. |
docs/design/nd_array_approach_comparison.md |
Adds update notice re: setfield! wrapper reuse on 1.11+ CPU. |
docs/design/hybrid_api_design.md |
Adds update notice re: setfield! wrapper reuse and field changes. |
docs/design/cuda_extension_design.md |
Adds update notice clarifying CUDA still uses N-way cache. |
Project.toml |
Reorders/normalizes some entries without changing the version value. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- src/AdaptiveArrayPools.jl: merge 3 @static if blocks into one - test/runtests.jl: single @static if with version-specific helper - test/test_nway_cache.jl: remove @static, keep v1.11+ only - test/test_state.jl: replace @static with _test_nd_cache_preserved helper - test/legacy/test_nway_cache.jl: legacy N-way cache tests (≤1.10) - src/acquire.jl: _store_nd_wrapper! while→resize! optimization - src/state.jl: remove redundant inline type comments
Update all documentation to reflect that Julia 1.11+ CPU uses setfield!-based wrapper reuse (0-alloc, unlimited dimension patterns) instead of N-way cache. Clarify that CACHE_WAYS and N-way cache are now only relevant for CUDA backend and Julia 1.10 legacy path.
- Fix setfield! docstring signatures to use correct 3-arg form - Move _test_nd_cache_preserved helper before ARGS branch so it's defined when running individual test files - Add 10th dimension pattern to "10+ patterns" test to match name - Exclude src/legacy/ from codecov (0% on Julia 1.11+ by design)
c4cba3c to
11b8536
Compare
Summary
Replace the 4-way set-associative N-D wrapper cache with
setfield!-based in-place Array mutation (Julia 1.11+), eliminating theCACHE_WAYS=4eviction limit. After warmup, any number of dimension patterns per slot is zero-allocation.Motivation
The old N-way cache (
nd_arrays/nd_dims/nd_ptrs/nd_next_way) used round-robin eviction:CACHE_WAYS(default 4) dimension patterns per slotunsafe_wrapallocations (~112 bytes each)nd_ptrs) for resize invalidationJulia 1.11 changed
Arrayto a mutable struct withref::MemoryRef{T}andsize::NTuple{N,Int}, enabling direct field mutation viasetfield!.Changes
nd_arrays/nd_dims/nd_ptrs/nd_next_way) with singlend_wrappers::Vector{Union{Nothing, Vector{Any}}}indexed by N (dimensionality)get_nd_array!—setfield!(:ref, ...)+setfield!(:size, dims)for 0-alloc reuse; add_store_nd_wrapper!helperget_bitarray!—setfield!(:len/:dims/:chunks)for 0-alloc BitArray reuseempty!(4 cache clears → 1)@static if VERSION >= v"1.11-"gate for all includestest/legacy/test_nway_cache.jl; updatedtest_nway_cache.jlwith 10+ pattern zero-alloc testsPerformance
Compatibility
setfield!path (unlimited patterns, 0-alloc)src/legacy/)