Repository navigation
Remove native CPU cost cliffs at 2-3-5-smooth grid sizes - #24
Conversation
Two size boundaries made some smooth sizes 1.6-1.8x slower per source evaluation than the neighbouring power of two on the native CPU backend: - The node-chunk admissions take budget // per_node, so the four-mode RDW's 33 nodes at n_t 8640 ran a 32-node pass and then a one-node tail on one thread. Translation now spreads the nodes evenly over the same number of passes (17 + 16), never above the admitted chunk. - The stage threshold (8192 elements) and the modal FFT threshold (32768 samples) sat just above the RDW's sizes at n_t 4000 (8004 and 32000), so its stage entry (708 us vs 59 us threaded on one Xeon Gold 6240 socket) and transforms ran serially. They are now 4096 and 16384. RDW per evaluation on 18 cores: n_t 4000 2.47 -> 1.32 ms (4096: 1.24-1.36), 8640 3.55 -> 2.54 ms (8192: 2.28-2.31); other sizes unchanged. Adds the native/benchmarks/size_cliffs.py regression benchmark. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Documentation build overview
50 files changed ·
|
|
Mac A/B (18-core arm64 laptop, NEON FFTW, same commit, base/fix/fix/base interleaved, load 2.6–6; ms per evaluation,
The node-chunk balancing helps on both machines (8640: −26 % here, −28 % on the Xeon). The threshold change does not: here n_t 4000 is 17 % slower (now level with 4096). On this machine the serial stage and FFT were faster at that size; even 4096, threaded under the old thresholds, costs more than 4000 serial. So the stage and FFT crossovers differ between the two hosts by more than a factor of two, and one shared constant cannot suit both. 🤖 Generated with Claude Code |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
Zen 3 A/B (DMOG node12, dual EPYC 7643, idle node, GCC 16.2, FFTW 3.3.11,
Both Linux x86 hosts gain, at n_t 4000 (Zen 3 −24 to −27 %, Cascade Lake −47 %) and at 8640 (−4 to −13 %, −28 %). The Apple arm64 laptop loses 17 % at 4000. The other sizes move by at most 5 %, within the spread as the node's load rose from 5 to 10 during the 24-thread run. A first attempt on a node shared with other jobs (load ~117 of 128, cores scattered over five NUMA domains) varied 2× between rounds of the same build and was discarded. 🤖 Generated with Claude Code |
The lower starts (4096 elements, 16384 samples) gain on Linux: n_t 4000 RDW is 47 % faster on Cascade Lake and 24-27 % on Zen 3. On an Apple arm64 laptop the serial stage and transforms are the faster ones at those sizes (n_t 4000 went from 0.88 to 1.04 ms), so macOS keeps 8192 and 32768 until its own crossover is swept (roadmap item). The node-chunk balancing is unchanged and gains on every host. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The roadmap linked a MyST label as a page anchor (docs -W), and the native lane's strict basedpyright saw the execution mapping as partially unknown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Summary
Some 2-3-5-smooth grid sizes cost 1.6–1.8× the neighbouring power of two per source evaluation on the native CPU backend. FFTW is not the cause; two size boundaries in our own code are:
budget // per_node. At n_to 17280 the four-mode RDW's 33 nodes were cut to a chunk of 32, so every evaluation ran a 32-node pass and then a one-node pass on one thread._balanced_chunk(translation) now spreads the nodes evenly over the same number of passes (17 + 16). Chunks never exceed the admitted size, planar chunks keep whole rows, and sub-row chunks are left as they are.Platform split. The lower thresholds apply on Linux only. macOS keeps 8192 and 32,768: on an Apple arm64 laptop the serial stage and transforms are the faster ones at these sizes, so the change made n_t 4000 17 % slower there (see the comments below). A roadmap item asks for a sweep of the Mac crossover. The node-chunk balancing applies on every platform.
Results
Xeon Gold 6240, 18 pinned cores, GCC 16, FFTW 3.3.11, ms per evaluation (
native/benchmarks/size_cliffs.py, two rounds each):On a loaded 18-core arm64 laptop, RDW at n_t 4000 went from 0.82 to 0.95 ms, level with 4096 (0.98 ms). Thread wake-ups cost more there. SSFS and reduced CtC did not move.
Tests
CpuThreadPolicy.SmoothGridSizesKeepThePowerOfTwoWidths. The whole native GoogleTest binary passes locally (136); CI does not build it.test_budget_chunks_spread_the_nodes_evenly_over_their_passes,test_planar_chunks_stay_whole_rows_when_balanced, and the_even_chunkdoctest.tests/translate, the held-plasma, memory and multimode backend tests (1821 passed), andnative/tests(383 passed). The only failure istest_public_surface_is_exacton the local dirty-tree version suffix.SEP 30 core A/B (same machine, 18 threads, 3 rounds, candidate/baseline)
Geometric mean 0.996. Every case did the same work, and the fields agree to rounding (largest difference 5e-15).
🤖 Generated with Claude Code