Configuration
AdaptiveArrayPools can be configured via LocalPreferences.toml:
[AdaptiveArrayPools]
use_pooling = false # ⭐ Primary: Disable pooling entirely
runtime_check = 1 # Safety: Enable runtime safety checks
cache_ways = 8 # Advanced: N-way cache size (default: 4)All compile-time preferences require restarting Julia to take effect.
Compile-time: STATIC_POOLING (⭐ Primary)
The most important configuration. Completely disable pooling to make acquire! behave like standard allocation.
# LocalPreferences.toml
[AdaptiveArrayPools]
use_pooling = falseOr programmatically:
using Preferences
Preferences.set_preferences!(AdaptiveArrayPools, "use_pooling" => false)
# Restart Julia for changes to take effectWhen STATIC_POOLING = false:
poolbecomesDisabledPool{backend}()instead of an active pool- All pool functions fall back to standard allocation
- Backend context is preserved:
:cudastill returnsCuArray
# These become equivalent:
@with_pool pool acquire!(pool, Float64, n, n) → Matrix{Float64}(undef, n, n)
@with_pool pool acquire!(pool, Float64, n) → Vector{Float64}(undef, n)
# With CUDA backend:
@with_pool :cuda pool zeros!(pool, 100) → CUDA.zeros(Float32, 100)Use pooling_enabled(pool) to check if pooling is active.
Use cases:
- Debugging: Compare behavior with/without pooling
- Benchmarking: Measure pooling overhead vs direct allocation
- Gradual adoption: Add
@with_poolannotations now, enable pooling later - CI/Testing: Run tests without pooling to isolate issues
All pooling code is completely eliminated at compile time (zero overhead).
Compile-time: RUNTIME_CHECK
Enable runtime safety checks to catch pool-escape bugs. See Safety for full details.
# LocalPreferences.toml
[AdaptiveArrayPools]
runtime_check = 1 # enable (0 = off, 1 = on)
# runtime_check = true # also acceptedOr programmatically:
using Preferences
Preferences.set_preferences!(AdaptiveArrayPools, "runtime_check" => 1)
# Restart Julia for changes to take effectAccepts both Bool and Int values — internally normalized to Int:
false/0→ off (zero overhead, all safety branches eliminated)true/1→ on (poisoning + invalidation + escape detection + borrow tracking)
The safety level is baked into the pool type parameter: AdaptiveArrayPool{0} or AdaptiveArrayPool{1}. This enables dead-code elimination — at RUNTIME_CHECK = 0, all safety branches are completely removed by the compiler.
Runtime: MAYBE_POOLING
Only affects @maybe_with_pool. Toggle without restart.
MAYBE_POOLING[] = false # Disable
MAYBE_POOLING[] = true # Enable (default)Compile-time: CACHE_WAYS (≤1.11 / CUDA only)
Configure the N-way cache size for acquire!. On Julia 1.12+ CPU, this setting has no effect — the setfield!-based wrapper reuse supports unlimited dimension patterns with zero allocation.
This setting is relevant for:
- Julia ≤1.11 (legacy N-way cache path)
- CUDA backend (N-way cache for
CuArraywrappers)
# LocalPreferences.toml
[AdaptiveArrayPools]
cache_ways = 8 # Default: 4, Range: 1-16Or programmatically:
using AdaptiveArrayPools
set_cache_ways!(8)
# Restart Julia for changes to take effectWhen to increase: If your CUDA code or Julia ≤1.11 code alternates between more than 4 dimension patterns per acquire! call, increase cache_ways to avoid cache eviction (~100 bytes header per miss).
Compile-time: auto_manage
Master switch for the background memory reclamation engine (see Automatic Memory Management). Default true — a background timer periodically auto-compacts and auto-trims the task-local pool.
# LocalPreferences.toml
[AdaptiveArrayPools]
auto_manage = false # compile the feature out; restart Julia to take effectSetting it to false (compile-time) dead-code-eliminates the @with_pool reclamation hook entirely, guaranteeing a zero-allocation hot path; enable_auto_manage! then becomes a no-op-with-warning and you reclaim memory only via manual compact! / trim!.
Tuning the timer (auto_manage_*)
When auto_manage is on, the background timer's cadence and thresholds default from these flat keys (read once at startup; enable_auto_manage! overrides them at runtime). All optional:
[AdaptiveArrayPools]
auto_manage_compact_interval = 30.0 # seconds — how often to auto-compact
auto_manage_trim_interval = 120.0 # seconds — how often to auto-trim (Inf disables)
auto_manage_compact_bloat_factor = 10 # compact a slot at ≥ this × its live size
auto_manage_compact_target_ratio = 1.5 # shrink it down to this × live size
auto_manage_compact_min_bytes = 1048576 # skip if it would reclaim lessSee Automatic Memory Management for what each does.
Summary
| Setting | Scope | Restart? | Priority | Affects |
|---|---|---|---|---|
use_pooling | Compile-time | Yes | ⭐ Primary | All macros, acquire! behavior |
runtime_check | Compile-time | Yes | Safety | Poisoning, invalidation, escape detection |
cache_ways | Compile-time | Yes | Advanced | acquire! N-D caching (≤1.11 / CUDA only) |
auto_manage | Compile-time | Yes | Optional | Background auto-compact/auto-trim (default on) |
MAYBE_POOLING | Runtime | No | Optional | @maybe_with_pool only |