Repository navigation
Conversation
…DR-076) Each plan key holds the wisdom of that transform alone, measured in place by the first run that planned it, in wisdom.json in the calibration store's directory of the machine and build (the profile's fingerprint), or beside the file SOLPROP_FFTW_WISDOM names. A workspace's own planning (the policy's or the profile's) is offered the stored plans and keeps what it measures: a seeded transform plans alone from its own stored wisdom, and the workspace's wisdom comes back over it; a transform left at estimate takes its stored plan unseeded. A profile's keys keep precedence and are never stored. SOLPROP_CALIBRATION=off keeps no default file; calibrate --clear removes the plans; a process remembers its own plans for later workspaces. An unusable name or file now warns and plans without stored plans, and the key tells Apple silicon models apart (#136). SOLPROP_FFTW_WISDOM no longer turns off a profile's FFT planning. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…erf/default-fftw-wisdom
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 139b844a3a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| fftw_forget_wisdom(); | ||
| if (const auto found = planning.stored.find(key); found != planning.stored.end()) | ||
| static_cast<void>(fftw_import_wisdom_from_string(found->second.c_str())); |
There was a problem hiding this comment.
Reuse plans already measured by the current workspace
On a cold cache, when a workspace seeds the same transform key more than once, this clears FFTW's accumulated wisdom and imports only planning.stored, which never receives the plans just recorded in planning.measured. Consequently, each occurrence measures the transform again instead of reusing the first measurement. This affects, for example, matching projected/coarse transforms across plasma streams in GeneralWorkspace::seed_stream_wisdom(), which previously shared process-local wisdom. Consult the current workspace's measured plans as well as the initial store before clearing wisdom, so construction does not repeat potentially expensive measurements for identical keys.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in bdf2498. A key measured earlier in the workspace is now reused (known_wisdom consults measured before stored). A transform being measured also starts from what the workspace has measured so far, so it shares their sub-plans as #598's single wisdom did. The Xeon timings showed the cost: cold construction of rdw took 6.7 s against #598's 1.4 s.
| digest = found.fingerprint.digest | ||
| removed = _native.store.Store(store_directory(environ)).clear(digest) | ||
| named = (os.environ if environ is None else environ).get("SOLPROP_FFTW_WISDOM", "") |
There was a problem hiding this comment.
Clear explicitly named wisdom even when calibration is off
With SOLPROP_CALIBRATION=off and SOLPROP_FFTW_WISDOM set, runs explicitly continue to persist plans, but clear() cannot remove that file: _profile.choose() returns a choice without a fingerprint in off mode, so the early return above makes this new deletion path unreachable. Thus solprop calibrate --clear silently leaves the active named plan cache intact in a supported configuration. Compute the machine/build fingerprint independently of profile selection in this case, as _wisdom.machine_key() already does when writing the file.
Useful? React with 👍 / 👎.
Documentation build overview
18 files changed ·
|
…; clear a named file under off A key measured earlier in the workspace is reused rather than measured again, and a transform to be measured starts from the plans the workspace measured so far, so that it shares their sub-plans as one wisdom does. `solprop calibrate --clear` takes the fingerprint itself when SOLPROP_CALIBRATION=off read no profile, so the file SOLPROP_FFTW_WISDOM names goes too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…erf/default-fftw-wisdom
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…g from the workspace's plans Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Follows #598 (merged; this PR was stacked on it and now targets
main). Fixes #136.What
The native backend now keeps the FFTW plans its runs measure, by default. Each transform shape is measured once per machine and build, not on every run. ADR-076 (proposed) records the decision.
fft_plan_key: kind, sizes, strides, placement, alignment, threads, as a calibration keys its winners) holds the wisdom of that transform alone. That wisdom is measured in place by the first run that planned it, inside its own workspace. A seeded transform plans alone: the workspace's accumulated wisdom is set aside, only the key's stored wisdom is imported, and afterwards the workspace's wisdom comes back over the transform's (FftPlanning::stored,keep,measured,reusedincore.hpp/fft_plan.hpp). A transform left at estimate takes its stored plan without being seeded, as FFTW does with wisdom.wisdom.jsonin the calibration store's directory for the machine and build (<store>/machines/<fingerprint>/, the profile's fingerprint), so different machines and builds never share plans.SOLPROP_FFTW_WISDOMmoves the file, to<name>.native-<fingerprint>, and no longer turns off a profile's FFT planning.SOLPROP_CALIBRATION=offkeeps no default file.solprop calibrate --clearremoves both files. A process keeps its own plans in memory for its later workspaces.off) do neither. The atomic-rename andflockscheme is unchanged.SOLPROP_FFTW_WISDOMstops the run, and Apple silicon models share a key #136. An unusable name (.,~nouser/w, no home) warns and plans without stored plans, instead of raising. The key is the fingerprint, which tells Apple silicon models apart.wisdom_loaded(the file held plans) andwisdom_digest(now a digest of the plans the workspace built from wisdom or measured).Measurements
All runs use
SOLPROP_FFTW_PLAN=measureandSOLPROP_CALIBRATION=off, length 0.05, with 5 interleaved rounds. "Stored" means the plans one earlier run kept.AMD EPYC 7763, 16 cores (one NUMA domain), DMOG node19, both builds from source. Construction, measured cold in place, then warm from stored plans:
ctch2_raman_averagedgrin_nonlinearrdwWindows with stored plans against plans measured in place (median ratio, range over rounds):
h2_raman_averagedctcrdwgrin_nonlinearSo
h2_raman_averagedis no slower with stored plans than with plans measured in place; the 1.17 seen on the AMD EPYC 9B45 with plans planned alone doesn't appear.ctcleans 0.3–1.7 % across these comparisons, and with a second stored measurement its ranges span 1. That is the spread between individual measurements of the same plan, which stored plans fix to one draw.Intel Xeon Gold 6240, 18 and 36 threads, same build. Construction:
ctc23.2 → 0.12 s,rdw6.7 → 0.10,h2_raman_averaged4.9 → 0.07,grin_nonlinear3.5 → 0.6. Windows: geometric mean 1.015, every range spans 1. The cold times here come from an earlier commit that measured each transform from nothing (see Codex's first finding). Later Xeon timings were disturbed by another session's load outside Slurm, so the comparison against #598 ran on DMOG instead.The store holds about 20 kB per case at one width.
Not changed
The policy's threaded-rows effort stays at estimate. Plans measured once now cost nothing afterwards, so switching threaded rows to
measureby default is a separate call for the maintainer.Checks
Targeted tests pass on the Xeon:
native/tests/test_wisdom.py(rewritten),test_store.py,test_profile.py,test_planning.py,test_backend.py,test_fftw_plan_refusal.py,tests/calibration/,tests/backends/test_execution_record_cost.py,test_native_forced_threads.py,tests/driver/test_scan_kept_backend.py. The full gates run in CI.🤖 Generated with Claude Code