fix(asr): guard THREAD_POWER_THROTTLING_STATE to feature-detect for MinGW - #5377
fix(asr): guard THREAD_POWER_THROTTLING_STATE to feature-detect for MinGW#5377NF0T wants to merge 1 commit into
Conversation
…inGW Under MinGW-w64, winbase.h defines the ThreadPowerThrottling enum value (so SetThreadInformation(..., ThreadPowerThrottling, ...) resolves) but not the THREAD_POWER_THROTTLING_STATE struct or the THREAD_POWER_THROTTLING_EXECUTION_SPEED/THREAD_POWER_THROTTLING_CURRENT_VERSION macros ggml_thread_apply_priority() fills in, so the existing _WIN32_WINNT-only guard fails to compile under MinGW GCC 13.1.0 (Qt's mingw_64 kit). MSVC's Windows SDK already has these, so this is invisible on the CI/installer path. Narrows the guard to feature-detect the actually-missing macro rather than gate on the toolchain, so it self-resolves if mingw-w64 ever adds the struct and also covers MinGW-clang. Under MinGW this only forgoes a Windows-11 core-parking performance hint -- SetThreadPriority() immediately below is unconditional and still applies. Originally proposed as aethersdr#4406 and closed there as an in-place vendored edit, before this tree's AETHERSDR-PATCHES.md exception convention existed. aethersdr#4553 (2026-07-31) documented that convention here for a different fix in the same tree; this re-lands aethersdr#4406's fix through it, recorded as the third local patch alongside the two Metal changes. Verified with a from-scratch MinGW build (Qt 6.11.2 mingw1310_64): ggml-cpu.c compiles clean and AetherSDR.exe links, with no separate apply/reverse patch step needed.
There was a problem hiding this comment.
Issue fit
Yes, for the code change. There is no linked issue — the reference is PR #4406, which is closed-unmerged, so I reviewed against the PR's own stated intent plus #4406's thread. #4406's body documents the exact compile error (ggml-cpu.c:2533:10: error: request for member 'StateMask' in something not a structure or union) under MinGW GCC 13.1.0, and its closing comment — from the same author, after a maintainer-agent process finding — proposes precisely the defined(THREAD_POWER_THROTTLING_CURRENT_VERSION) && _WIN32_WINNT >= 0x0602 form this PR lands, and states the plan to carry it as a documented local patch once a convention existed. #4553 created that convention. So the mechanism objection that closed #4406 is genuinely resolved, not sidestepped.
GOVERNANCE: a one-line build fix with a root cause in hand does not need an RFC. The prior maintainer-agent ruling on #4406 was about mechanism (in-place vendored edit with no record), and this PR is the remediation of that ruling — it adds the record.
Scope
| File | What it changes | Claimed by title/body | Verdict |
|---|---|---|---|
ggml/src/ggml-cpu/ggml-cpu.c |
One preprocessor guard, #if _WIN32_WINNT >= 0x0602 → #if defined(THREAD_POWER_THROTTLING_CURRENT_VERSION) && _WIN32_WINNT >= 0x0602 |
Yes | In scope |
AETHERSDR-PATCHES.md |
Adds patch #3 entry + refresh checklist; rewords Metal wording to "the two Metal changes" | Yes — required by AETHER_VENDORING.md |
In scope |
AETHER_VENDORING.md |
two→three throughout, adds the ggml-cpu.c bullet |
Yes | In scope |
Everything in the diff is explained by the stated fix. 2 insertions / 2 deletions of code, the rest documentation that the vendoring policy requires for any in-place edit. No CHANGELOG.md entry (correct). No new public surface, no settings, no protocol verb, no deleted guard — the only - line in code is the guard being narrowed, and narrowing it cannot re-open a previously-fixed bug because the removed condition is retained as the second conjunct.
Sibling-site check: THREAD_POWER_THROTTLING and SetThreadInformation appear in exactly one place in the whole tree (ggml-cpu.c:2528–2535). There is no second vendored ggml, and ggml-cpu.cpp does not carry a parallel copy. Nothing is left unfixed.
Blockers
None.
Nits (non-blocking)
-
AETHERSDR-PATCHES.md:10— "(#4406) landed separately" is not accurate. #4406 is closed and was never merged; this PR is what lands the change. A future refresher following this doc will open #4406, find a closed PR, and have to reconstruct what actually happened. Suggest naming this PR instead. Inline comment with a suggestion fence. -
AETHERSDR-PATCHES.md:67-68— "which fixed the same compile error the same way" is not what #4406 did. #4406's body proposes#if defined(_MSC_VER) && _WIN32_WINNT >= 0x0602— a toolchain gate. The feature-detect form landed here appears only in #4406's closing comment, and the difference is the entire reason the paragraph immediately above argues for feature-detection over_MSC_VER. As written the doc contradicts its own rationale. Inline comment. -
The guard is fail-silent, and nothing gates that. If the sentinel macro name were ever wrong (or the SDK renamed it), the block compiles out everywhere including MSVC, CI stays green on all three jobs, and the only symptom is the silent loss of the Win11 core-parking hint on the shipped Windows build. The refresh checklist added here tells the refresher to verify a MinGW compile; it says nothing about verifying the block is still enabled under MSVC. Worth one clause in the checklist. I'm confident the name is right (
THREAD_POWER_THROTTLING_CURRENT_VERSIONships with the struct in the same Win10 SDK block), but "confident" is the point — nothing here would catch it if I'm wrong. -
AETHER_VENDORING.md's own bar is "genuinely cannot live outside the tree" — worth one sentence saying why this clears it. Atarget_compile_definitions(... -D_WIN32_WINNT=0x0601)on the ggml-cpu target underMINGWwould also disable the block without touching vendored source. I think the in-tree guard is the better choice — it is narrower (that cmake route re-gates every version check in the TU) and self-resolves when mingw-w64 adds the struct — but the doc that exists to justify deviations should say that out loud. Maintainer's call.
What I tried to break
- "MSVC is unaffected either way." CI is green on
build,check-windows(MSVC) andcheck-macosforc48c69f, which proves the MSVC path still compiles. It does not prove the block stays enabled under MSVC — green is indistinguishable between the two. That gap is nit 3; I could not close it headlessly and am not claiming it as a defect. - Undefined-
_WIN32_WINNTbehaviour. Grepped the whole project: nothing outside the vendored tree defines_WIN32_WINNT, so it comes from the toolchain. If it were undefined the preprocessor substitutes 0 and the conjunct is simply false — no error, and identical to the pre-patch behaviour since_WIN32_WINNTis used the same way on both sides of the diff. No new-Wundefsurface either. - Sibling call sites and second copies.
find/grepacross the head checkout: one guard site, one ggml tree, no parallel.cppcopy, no otherSetThreadInformationcaller. Nothing left half-fixed. - The removal side of the diff. Read the
-lines: the old condition survives intact as the right-hand conjunct, so the patch can only ever narrow, never re-enable something a previous fix disabled. No deleted comment naming a symptom. - Doc-vs-tree consistency. Confirmed both Metal patch files exist as described and that "three files" now matches the enumerated list in both docs. I found no automated drift/vendor-check script that counts patched files, so no gate needs updating alongside — if one exists outside
tools/,.github/anddocs/, I missed it. - The claim I could not test: that mingw-w64's header set defines the
ThreadPowerThrottlingenum but not the struct/macros. I have no MinGW toolchain here. It is corroborated by the compile error quoted in #4406 and by the author's rebuild-to-clean report, and the failure mode if it were wrong is a compile error on the author's own kit, not a silent runtime bug.
Everything above is reasoned from the diff and the head checkout at /tmp/aetherclaude/pr-5377 — I built nothing and ran nothing.
Tests: no test is added and none is warranted. The regression is a compile failure on a toolchain CI does not run; there is no socket, state-machine or DSP seam here to test, and the honest coverage boundary is exactly what the PR states — a MinGW configure + build. Adding a MinGW CI lane is a separate, larger decision. No socket tests or fake peers are added, modified or removed by this PR.
Recommendation
Approve with nits. The code change is minimal, strictly narrowing, correct in the undefined-macro edge case, has no sibling site left behind, and closes the exact mechanism objection that closed #4406 by adding the record the vendoring policy demands. The two doc inaccuracies (nits 1 and 2) are worth fixing before merge precisely because this file's whole job is to be the authoritative record for the next refresher — they cost one line each. Nits 3 and 4 are judgment calls for the maintainer, not merge conditions.
Thanks for coming back to this the long way round rather than just re-pushing the original edit — the paper trail from #4406 through #4553 to here is unusually easy to audit.
🤖 aethersdr-agent · cost: $5.1759 · model: claude-opus-5
| AetherSDR carries three local changes: two in the ggml Metal backend, from the | ||
| same fix (#4535, PR #4553), and one in the ggml CPU backend, a MinGW build fix | ||
| (#4406) landed separately. |
There was a problem hiding this comment.
#4406 is closed and was never merged — this PR is what lands the change, so "landed separately" points a future refresher at a dead end. (Verified: #4406 state is closed, no merge.)
| AetherSDR carries three local changes: two in the ggml Metal backend, from the | |
| same fix (#4535, PR #4553), and one in the ggml CPU backend, a MinGW build fix | |
| (#4406) landed separately. | |
| AetherSDR carries three local changes: two in the ggml Metal backend, from the | |
| same fix (#4535, PR #4553), and one in the ggml CPU backend, a MinGW build fix | |
| (PR #5377). |
| Originally proposed as PR #4406, which fixed the same compile error the | ||
| same way but was closed as an in-place vendored edit before this file's |
There was a problem hiding this comment.
Not quite — #4406 proposed a toolchain gate, not this feature-detect:
- #if _WIN32_WINNT >= 0x0602
+ #if defined(_MSC_VER) && _WIN32_WINNT >= 0x0602(that's from #4406's body). The defined(THREAD_POWER_THROTTLING_CURRENT_VERSION) form only appears in #4406's closing comment. Since the paragraph directly above this one argues specifically for feature-detection over _MSC_VER, saying #4406 fixed it "the same way" undercuts that rationale.
| Originally proposed as PR #4406, which fixed the same compile error the | |
| same way but was closed as an in-place vendored edit before this file's | |
| Originally proposed as PR #4406, which fixed the same compile error by | |
| gating on `_MSC_VER` instead, and was closed as an in-place vendored edit | |
| before this file's |
| // all our threads onto the first 4 cores which results in terrible performance with | ||
| // n_threads > 4 | ||
| #if _WIN32_WINNT >= 0x0602 | ||
| #if defined(THREAD_POWER_THROTTLING_CURRENT_VERSION) && _WIN32_WINNT >= 0x0602 |
There was a problem hiding this comment.
The guard itself checks out. Things I specifically tried to break, none of which did:
- Undefined
_WIN32_WINNT: nothing in this project defines it (grepped the whole tree outsidethird_party/whisper.cpp), so it comes from the toolchain. If absent, the preprocessor substitutes0and the conjunct is false — no error, and identical to the pre-patch line, which used it the same way. - Narrowing only: the original condition survives verbatim as the right-hand conjunct, so this can never re-enable something a prior fix disabled.
- Sentinel choice:
THREAD_POWER_THROTTLING_CURRENT_VERSIONships in the same Win10-SDK block asTHREAD_POWER_THROTTLING_STATEand..._EXECUTION_SPEED, so detecting one implies the other two. Keying on the macro rather than_MSC_VERis the better call — it also covers MinGW-clang and self-resolves when mingw-w64 adds the struct.
One property worth noting in the refresh checklist (body nit 3): this is fail-silent. If the sentinel name were ever wrong, the block compiles out on MSVC too, all three CI jobs stay green, and the only symptom is the silently-lost Win11 core-parking hint on the shipped Windows build. The checklist added in AETHERSDR-PATCHES.md covers verifying a MinGW compile; nothing covers verifying the block is still live under MSVC.
ten9876
left a comment
There was a problem hiding this comment.
Issue fit
Re-lands #4406 (closed for using the vendored-edit exception before it existed): ggml_thread_apply_priority() guards a Windows-11 core-parking hint with #if _WIN32_WINNT >= 0x0602, but MinGW-w64's headers define the ThreadPowerThrottling enum value while omitting the THREAD_POWER_THROTTLING_STATE struct/macros the block fills in, so it fails to compile under MinGW GCC. The one-line fix — #if defined(THREAD_POWER_THROTTLING_CURRENT_VERSION) && _WIN32_WINNT >= 0x0602 — is exactly right: it feature-detects the actually-missing macro rather than gating on toolchain (_MSC_VER), so MSVC (which has the macro) is unaffected and any toolchain lacking it skips the block cleanly. Correct and portable.
The governance question, which is the real review here
This is an in-place edit to a vendored tree — the sensitive part, and the reason #4406 was closed. The PR is compliant with the convention #4553 established for exactly this tree:
- The change genuinely cannot live outside the tree (a preprocessor guard inside a vendored
.cfunction body), which isAETHER_VENDORING.md's stated bar for the exception. AETHERSDR-PATCHES.mdis updated with the rationale, the compile error, and a refresh checklist; no.patchfile is kept (git history is the record), matching howwdsp/smartsdr-dsp/libmosquitto/rnnoisealready work.- Build fix, RFC-exempt.
So the box is checked by the letter of the convention. Two things I'd still surface to you as the maintainer, since vendored edits and re-lands of closed PRs are both your call:
- Whether re-landing a previously-closed change on a now-existing exception is something you want to wave through or look at yourself.
- The
AETHER_VENDORING.mdedit (+21/−13) touches the vendoring policy doc, not just the per-patch log — worth a glance that it only documents this patch and doesn't quietly widen the exception clause itself.
Scope / blockers
Three files: the one-line code guard + the two vendoring docs. No CHANGELOG.md. Preflight: no sockets. No blockers.
What was verified vs read
- Verified: the guard change is minimal and feature-detects the correct macro;
AETHERSDR-PATCHES.mdcarries the entry with a refresh checklist. - Read, not independently checked: the "upstream whisper.cpp still has the bare guard" claim (the PR says it was checked at #4406 time) — worth a re-confirm against current upstream before merge, since a vendored patch that upstream already fixed is churn. I did not diff against upstream.
- No build run (MinGW-only path, MSVC CI green); no bridge session (compile-time guard).
Recommendation: approve with nits, pending your ruling on the two governance items above — the code is correct and the convention is followed; the judgment calls are the vendored-edit acceptance and the policy-doc touch.
Summary
Re-lands #4406, using the vendored-file exception convention #4553 established for this same tree eight days after #4406 was closed for using it before it existed.
ggml_thread_apply_priority()in the vendoredthird_party/whisper.cpp/ggml/src/ggml-cpu/ggml-cpu.cguards a Windows-11 core-parking thread-priority hint with#if _WIN32_WINNT >= 0x0602, butTHREAD_POWER_THROTTLING_STATEand theTHREAD_POWER_THROTTLING_EXECUTION_SPEED/THREAD_POWER_THROTTLING_CURRENT_VERSIONmacros it fills in are only declared in the MSVC Windows SDK headers. MinGW-w64'swinbase.hdefines theThreadPowerThrottlingenum value (so theSetThreadInformation(..., ThreadPowerThrottling, ...)call resolves) but not the struct/macros, so this fails to compile under MinGW GCC:This repo's CI and the official installer build with MSVC, so the bug is invisible there — it only surfaces on a local MinGW dev build.
Why an in-place vendored edit, and why now
AETHER_VENDORING.mdprohibits modifying vendored sources in place unless the change genuinely cannot live outside the tree — and #4406 (this same fix, opened 2026-07-23) was correctly closed for landing it without that exception, since the doc had no exception clause yet and noAETHERSDR-PATCHES.mdexisted for this tree.AETHERSDR-PATCHES.mdand the exception clause were added to this tree on 2026-07-31 by #4553, fixing an unrelated Metal-backend bug (#4535) the same way: narrow in-place edit, documented with rationale and a refresh checklist, no.patchfile kept — git history is the diff record. This PR uses that exact convention, already in production forthird_party/wdsp,third_party/smartsdr-dsp,third_party/libmosquitto, andthird_party/rnnoise.Fix
Feature-detects the actually-missing macro rather than gating on the toolchain (
_MSC_VER), so it self-resolves the day mingw-w64 adds the struct and also covers MinGW-clang. Under MinGW this only forgoes the core-parking performance hint —SetThreadPriority()immediately below is unconditional and still applies. No behavior change under MSVC.Also updates
AETHERSDR-PATCHES.mdandAETHER_VENDORING.mdto record this as the tree's third local patch, following the existing two Metal entries' format (rationale, refresh checklist, no.patchfile kept).Test plan
mingw1310_64, GCC 13.1.0):ggml-cpu.ccompiles clean,AetherSDR.exelinks — confirmed with this exact commit checked out, no separate patch-apply stepFollow-up (not in this PR)
Once merged, I'll retire the local
~/aethersdr-mingw-throttle.patchworkaround and the corresponding apply/build/reverse step from my personal MinGW build tooling — it exists only to carry this exact fix locally until now.👨🏼💻 Co-authored by Claude Sonnet 5