Repository navigation
Description
What happens
gnlse_raman_shock (one mode, 16384 samples, 8469 accepted steps, Runge-Kutta) on the native backend, in the 0.1.0 record (benchmarks/history/):
| hardware | 1 thread | all threads | ratio |
|---|---|---|---|
| AMD EPYC 9B45, Linux, 16 threads | 21.58 s | 24.26 s | 0.89 |
| AMD EPYC 9B45, Windows, 16 threads | 26.30 s | 23.63 s | 1.11 |
| AMD EPYC 7763, 16 threads | 44.15 s | 37.84 s | 1.17 |
| Apple M5 Max, 18 threads | 24.43 s | 20.96 s | 1.17 |
| 2x Xeon Gold 6240, 36 threads | 46.79 s | 33.69 s | 1.39 |
| Arm Neoverse-V2, 16 threads | 54.57 s | 36.67 s | 1.49 |
On the M5 Max at 18 threads, two collections on the same build gave 31.31 s (31.20 to 31.38) and 20.96 s (20.95 to 20.96). Each mode holds for all three repeats and for its process's warm-up (0.287 s against 0.187 s), so it is fixed per process. Only the 20.96 s row is in the CSV.
It is not only the M5 Max. A sweep on an idle 2x Xeon Gold 6240, on the released wheel, unpinned, one run per process, shows no gain beyond the spread past four threads, and a spread between processes as large as what scaling gains. From 8 threads up every column runs the same team of 8, so those columns differ only by process:
| threads | 1 | 2 | 4 | 8 | 12 | 18 | 36 |
|---|---|---|---|---|---|---|---|
| first round | 47.3 s | 41.7 s | 42.0 s | 36.3 s | 36.3 s | 40.6 s | 36.7 s |
| second round | 47.5 s | 42.0 s | 37.7 s | 43.9 s | 42.2 s | 35.5 s | 35.2 s |
Why it matters
The scalar GNLSE with Raman is a common run. At the default width it is, at best, modestly faster than one thread, on one platform slower, and its time varies between processes.
Context
cpu_compact_threads: Native performance push #59's compact team caps a one-column problem at 8 threads. These numbers are after that change.benchmarks.md, "Compact CPU teams" holds the earlier sweep.- Roadmap, "The thread budget on chips with efficiency cores": the macOS budget counts every core, which may bear on the two modes there.
docs/dev/benchmarking.md: how the record is taken. To repeat a width:python -m benchmarks track --case gnlse_raman_shock --threads 8 --production 16.
To do
- Repeat the sweep on an idle EPYC 9B45 (Google Cloud
c4d-highcpu-32, SMT off) and M5 Max, or say what you ran on so that a maintainer can repeat the rest. - Find where the threads go: FFT, stage passes or thread wake-ups.
- Find what is fixed per process: repeat one width many times with
SOLPROP_FFTW_PLAN=measureand with pinned threads. Thread placement is the first suspect: threaded rows are at estimate by default, so they have no measured plan to vary, and the one-thread column is the stable one. - Needs a decision: propose here whether the cap of 8 should be lower or per machine, and whether the macOS budget (ADR-056) should count only the fastest cores. A maintainer decides.
Done when
The cause of the poor scaling and of the variation between processes is recorded here with measurements. Then either a 16-thread run is no slower than a one-thread run on the EPYC 9B45, or the reason it cannot be is stated and the default width changed to suit.
Checked against commit 9d5d92f; the code links are pinned to it.
Also
Two more threading questions from the native Adams work, both on mode-averaged cases. This issue so far covers gnlse_raman_shock under Runge-Kutta.
The same pattern on mode-averaged Adams cases. SEP 39's phase 0 saw he_rdw_averaged and h2_raman_averaged slower at sixteen threads than at one on a shared 16-core domain of an AMD EPYC 7763, and said to re-measure before calling it a defect. The 0.1.0 record answers part of that. Native, default stepper (Multistep, exponential), median of three, one thread / all threads, read from benchmarks/history/:
| hardware | he_rdw_averaged |
h2_raman_averaged |
|---|---|---|
| Arm Neoverse-V2, 16 threads | 1.50 / 0.87 s | 8.06 / 5.93 s |
| Apple M5 Max, 18 threads | 0.65 / 0.42 s | 3.44 / 2.96 s |
| AMD EPYC 7763, 16 threads | 1.06 / 0.79 s | 6.12 / 5.25 s |
| AMD EPYC 9B45, Linux, 16 threads | 0.57 / 0.46 s | 3.07 / 2.88 s |
| AMD EPYC 9B45, Windows, 16 threads | 0.69 / 0.54 s | 3.78 / 3.89 s |
| 2x Xeon Gold 6240, 36 threads | 1.27 / 1.48 s | 6.65 / 6.92 s |
So the EPYC 7763 is faster at full width in this record. The 2x Xeon Gold 6240 is slower on both, outside the spread of the three repeats. Windows' h2_raman_averaged is level within that spread, as is its argon_blueshift_averaged (2.62 / 2.67 s). These are compact problems, so the cap of 8 applies by reading.
An unexplained slowdown on a host march. SEP 39's phase 3 and benchmarks.md record that on an Apple M5 Max at sixteen threads (October 2026) h2_raman_averaged took 2.24 s on the Python march with the staged trial, in all three rounds, against 1.74 s with host packing and 1.48 s natively. The SEP suspects the OpenMP workers' idle policy meeting the shorter host gaps between native calls, and it was not investigated. The native march, the default, does not show it, but the configurations that step solprop's march with a HostMarchWarning may. Whether it shares a cause with the two M5 Max modes above is unknown; it read alike in all three rounds. Read, not re-timed.
- Add
he_rdw_averagedandh2_raman_averagedto the thread-scaling runs, on a 2x Xeon Gold 6240 above all. - Re-time the host march on an idle M5 Max with
OMP_WAIT_POLICYvaried, then explain it or close it here as not reproduced. If the idle policy is the cause, fix it on the host march or record the cost besideHostMarchWarning.
Added on 2026-11-01, checked against commit 8a9f764.
Activity
jtravs commentedon Nov 9, 2026
SEP 46's verification (#582;
docs/dev/benchmarks.md, "Machine calibration against the built-in table"), at 16 cores (12 on the Emerald Rapids), the calibrated grain against the built-in table:gnlse_raman_shockran 0.85–0.86 on a Google Axion and 0.94 on an Intel Xeon Platinum 8581C (Emerald Rapids). Both chose medium width 8 with Raman and copy thresholds. It ran 1.011 on an Apple M5 Max, which chose a Raman threshold of 8193. The other machines kept the table.So part of the poor scaling is the grain, and on untuned machines a calibration recovers it. Why the case scales so poorly with threads, and varies between processes, is not explained, so this stays open. #593 asks whether the shared grain should become the table's default.
🤖 Generated with Claude Code