feat(engine): shared rayon pool for the disjoint-parallel core
Replace the per-call std::thread::scope fan-out in run_indexed with one process-wide rayon pool. run_indexed's callers nest — sweep (grid points), monte_carlo (seeds), and walk_forward (window bounds), where a walk_forward window runs an inner sweep — and each std::thread::scope spawned its own available_parallelism() OS-thread batch, so the two levels multiplied to ~available_parallelism()^2 threads (measured 150-240 concurrent on a 24-core box during a 42-cell campaign, ~10x oversubscription). rayon's pool is process-wide and persistent: a nested par_iter work-steals within the same N workers instead of spawning, so live workers never exceed the pool size. Determinism (C1) is preserved bit-for-bit: run_indexed collects via IndexedParallelIterator in enumeration order (not completion order), and the float aggregation (summarize_r / McAggregate / stitch) runs after the ordered collect, so IEEE-754 non-associativity introduces no variance. The existing _with_threads(1) == _with_threads(8) == public determinism tests stay green, now driving local rayon pools of 1 and N workers via ThreadPool::install. Structural inversion: the public sweep/monte_carlo/walk_forward become the core (calling run_indexed on the ambient pool through a shared assemble_* helper); the _with_threads variants collapse into thin, test-only wrappers (#[cfg(test)]) that run the same assembly inside a local pool. run_one stays Fn + Sync (no + Send): run_indexed borrows it in the map closure and the wrappers borrow it into install — passing it by value would move it into rayon's Map and force F: Send, a bound the public callers do not carry (hence the load-bearing #[allow(clippy::redundant_closure)] on run_indexed). Adds a nested-oversubscription regression test (asserts nested run_indexed never exceeds the pool size — the pre-rayon shape ran POOL^2) and an ignored wall-time benchmark. rayon admitted under the amended-C16 per-case dependency policy; it stays within C1 (parallelism across sims, never within one). This is the shared pool only — the first of three steps toward saturating the cores. The diagnosis found the larger loss is the idle valleys (~42% of the box idle: the sequential cell loop and the single-threaded bootstrap), which the pool alone does not fill. Two follow-ups are filed and recorded on #268: the Registry write path is not concurrency-safe (append_family races on a shared families.jsonl), the prerequisite for parallelizing the C1-disjoint cell loop with a RAM budget bounding concurrently-active instruments (the FileCache retains a symbol's parsed files while any reference is live). Verified: cargo test -p aura-engine (276 passed, the C1 determinism tests green), the new oversubscription test green, the benchmark runs (no overflow), clippy -D warnings clean, cargo test --workspace no failures. closes #268
This commit is contained in:
Generated
+46
@@ -168,6 +168,7 @@ dependencies = [
|
||||
"aura-std",
|
||||
"chrono",
|
||||
"chrono-tz",
|
||||
"rayon",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
@@ -404,6 +405,25 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
@@ -479,6 +499,12 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
@@ -803,6 +829,26 @@ version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.12.3"
|
||||
|
||||
Reference in New Issue
Block a user