Skip to content

gnlse_raman_shock scales poorly with threads: slower at 16 than at 1 on an EPYC 9B45, and varies between processes #81

Open

Description

@jtravs

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

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=measure and 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_averaged and h2_raman_averaged to 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_POLICY varied, 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 beside HostMarchWarning.

Added on 2026-11-01, checked against commit 8a9f764.

Activity

  1. added
    priority: mediumReal work that should not wait long
    performanceSlower or larger than it should be, with no wrong result
    area: nativeThe native backend, threading and FFT planning
    on Nov 1, 2026
  2. jtravs commented on Nov 9, 2026

    @jtravs
    ContributorAuthor

    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_shock ran 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: nativeThe native backend, threading and FFT planningperformanceSlower or larger than it should be, with no wrong resultpriority: mediumReal work that should not wait long

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions