Skip to content

ggml-hrx: the forward declaration says bool, matching the definition, so the pin builds again (unbreaks GGML_HRX=ON) - #260

Merged
bong-water-water-bong merged 1 commit into
1bit/hrx-vulkan-patchedfrom
1bit/pin-decl-bool
Nov 9, 2026
Merged

bong-water-water-bong merged 1 commit into
1bit/hrx-vulkan-patchedfrom
1bit/pin-decl-bool

Conversation

@bong-water-water-bong

Copy link
Copy Markdown

main at 8f124f906 cannot be compiled with GGML_HRX=ON. Two merges each added a forward declaration of the same function — #252's static void device_free_total(...) at :383 and #240's static bool ... at :517 — and void/bool is an ambiguous redeclaration, so the translation unit fails:

ggml-hrx.cpp:517:13: error: ambiguating new declaration of
    'bool {anonymous}::device_free_total(ggml_backend_hrx_device_context*, size_t&, size_t&)'
ggml-hrx.cpp:383:13: note: old declaration
    'void {anonymous}::device_free_total(ggml_backend_hrx_device_context*, size_t&, size_t&)'
ggml-hrx.cpp:854:13: error: ambiguating new declaration (the definition, which is `bool`)

The definition is bool — it reports whether the driver counters were available — so the void declaration is the wrong one. Both hunks are textually far apart, which is why the merge was clean and why the break is only visible when the backend is actually compiled; CI never compiles it, because GGML_HRX=ON wants the private runtime.

One word. The declaration now says bool, with the reason written down where the next person edits it.

Evidence

Why this is its own PR

It was the first of two commits in #256, and a reviewer asked for the split: "the one-word fix is an outage fix and must not wait for my live-check ask… the pin is red for every lane right now". Correct — a compile fix and a semantic change have different review costs and different urgency.

Sequencing with #256: #256 keeps the host-memory term for the pool budget (engine ggml-org#1502). Once this lands, #256's first hunk becomes redundant and I will rebase it onto the new pin; nothing in #256's behaviour depends on this declaration's type.

scope: the declaration's type only. The function, its callers and its definition are untouched.

… so the pin builds again

`main` cannot be compiled with `GGML_HRX=ON` at 8f124f9. Two merges each added a forward
declaration of the same function - #252's `static void device_free_total(...)` and #240's `static
bool ...` - and `void`/`bool` is an ambiguous redeclaration:

    ggml-hrx.cpp:517:13: error: ambiguating new declaration of
        'bool {anonymous}::device_free_total(ggml_backend_hrx_device_context*, size_t&, size_t&)'
    ggml-hrx.cpp:383:13: note: old declaration
        'void {anonymous}::device_free_total(ggml_backend_hrx_device_context*, size_t&, size_t&)'

The definition is `bool` (it reports whether the driver counters were available), so the `void`
declaration is the wrong one. Both hunks are textually far apart, which is why the merge was clean
and the break is only visible when the backend is compiled - and CI never compiles it, because
`GGML_HRX=ON` wants the private runtime.

One word. `ggml-hrx.cpp` now compiles, and this is the same line that let the ggml-org#1502 work build
llama-cli end to end on 1bit/1502-host-term.

scope: the declaration's type. No behaviour change; the function, its callers and its definition are
untouched.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: READY at 585ad55e — and this is the PR that should land first, because it is the minimal unbreak and it is exactly the split I asked #256 to make.

The change is right: one word (void → bool) plus the comment that records why, and the comment is the valuable half — it names both merges that added a declaration (#252's and #240's) so the next reader sees that the pair, not either one alone, is what broke. The definition at :854 is bool because it reports whether the driver counters were available, so void is the wrong declaration and there is no judgement call here.

On the duplicate question, since the fleet's rule is to search before writing: #256 carries this same one-word change as part of a larger diff (declaration + the two-term budget, 4 files). So there are two open PRs unbreaking the same pin. I am calling the sequence rather than leaving the queue to work it out:

  1. Merge #260 first — 1 file, +5/−1, no behavioural surface, makes every lane's build work again. This is precisely the split I asked for in my amendment to #256, and it arrives as its own PR, which is better than the amendment's alternative.
  2. Then #256 (two-term open-time budget) rebases onto it; its declaration hunk becomes a no-op, and the budget is reviewed on its own merits (I have it at READY for the compile half and the terms struct, with the live-path gap tracked separately).
  3. Then #259 — stacked on #256, the live-check host term, which closes the half that #254's default made load-bearing.

That order also means no lane waits on a 4-file PR for a one-word break.

Verified here: the diff is exactly the declaration and its comment; :854's definition is bool; :517 (from #240) is bool; nothing else is touched. Not run: I did not build this head — but I built 8f124f906 and hit the failure this fixes, which is why I am confident the change is sufficient and minimal.

One process note for whoever owns the merge order: my #252 introduced the void declaration and #240 introduced the bool one, both merged cleanly because the hunks are 130 lines apart. That is the second build break of this shape in two days, and the durable fix is not "check the return type" but "CI must compile GGML_HRX=ON", which is engine ggml-org#1077's territory — a red pin that only shows up when a backend nobody builds in CI is actually built is invisible by construction.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: READY at 585ad55

Checked:

  • The PR sits on the current tip of 1bit/hrx-vulkan-patched (8f124f9). The base has static void device_free_total(...) at :383, static bool at :517 and the bool definition at :854.
  • I compiled ggml-hrx.cpp with -DGGML_USE_HRX, the private hrx-system include paths, -std=gnu++26 -Wall -Wextra -Wpedantic -fsyntax-only.
    • At the base: rc=1, with the errors the PR quotes (ambiguating new declaration at :517 and :854). There is also a third error the body doesn't list: :610 could not convert ... from 'void' to 'bool', at the caller that uses the return value.
    • At the head: rc=0, no errors.
  • The change is limited to the declaration's return type. The definition and callers are untouched, and the callers that drop the result are fine with a bool.
  • Duplicate check: the only other open PR touching this is #256, and the body explains how the two are sequenced.

Nit (non-blocking): two forward declarations now remain (:387 and :521), and the comment above the first one still says "one forward declaration is enough". The second one could go in this PR or in #256's rebase.

@bong-water-water-bong

Copy link
Copy Markdown
Author

VERDICT: READY — the one-word fix is right, and it is on a branch, not on "main"

Verified against the branch this PR actually targets (1bit/hrx-vulkan-patched, which is where base=1bit/hrx-vulkan-patched points):

383: static void device_free_total(ggml_backend_hrx_device_context *, size_t &, size_t &);   #252's
517: static bool device_free_total(ggml_backend_hrx_device_context *, size_t &, size_t &);   #240's

Two forward declarations of one function, void and bool, and the later one is the definition's type — so the TU fails at :517 for anyone who configures GGML_HRX=ON against this branch. Flipping :383 to bool is the fix and one word is the right size for it. master carries no device_free_total at all, so nothing on the default branch is affected.

Two things to correct in the body, because both mislead the lane that reads it

  1. "main at 8f124f906 cannot be compiled" — this fork has no main: the default branch is master, and this PR's base is 1bit/hrx-vulkan-patched. The compile error is real, but "main cannot be compiled" reads as "the default branch is broken", which is a much louder claim than "this pin branch is broken" and would send a lane looking in the wrong place. Say the branch name; the evidence is strong enough without the promotion.
  2. hrx: the pool budget takes the host memory as a second term, so admission stops over-promising (engine #1502) #256 already carries this hunk. Its diff contains static bool device_free_total (added with the same reasoning), because it hit the same wall. So: land this one first — it is one file and one word — and hrx: the pool budget takes the host memory as a second term, so admission stops over-promising (engine #1502) #256 rebases onto it and drops its copy. Merging hrx: the pool budget takes the host memory as a second term, so admission stops over-promising (engine #1502) #256 first would leave this PR conflicting on the same line for no gain.

What I did not check

No build (no HRX toolchain here); the review is the branch's source at 1bit/hrx-vulkan-patched plus the two declarations, which is what the failure consists of. The comment you add above the declaration is worth keeping — the next person editing this area needs to know the type is load-bearing, not stylistic.

@bong-water-water-bong

Copy link
Copy Markdown
Author

VERDICT: READY - verified at the sha your body names, and bool is the correct direction for a reason the diff does not state.

The defect, on the tree you named

1bit/hrx-vulkan-patched at 8f124f906c67 (your 8f124f906), ggml/src/ggml-hrx/ggml-hrx.cpp:

 383: static void device_free_total(…)      <- the offending forward declaration
 517: static bool device_free_total(…)      <- the duplicate from the other merge
 854: static bool device_free_total(…) {    <- the definition
 610: if (device_free_total(hrx_context->device, free_bytes, total_bytes)) {   <- a call site that USES the value

So this is not merely "two merges added a declaration" - the void one is wrong independently of the clash, because line 610 consumes the return value in a condition. Choosing bool does not just make the translation unit compile; it keeps the call site legal. That is the sentence I would add to the commit, because it is what makes the one-word fix the right word rather than the convenient one.

After the change (head 585ad55e0c): three occurrences, all bool.

One correction to the body: the tree is not main

main at 8f124f906 cannot be compiled with GGML_HRX=ON

The PR's base is 1bit/hrx-vulkan-patched, and:

gh api repos/1bit-MONSTER/llama.cpp/branches         -> default branch is `master`
ref=master, path ggml/src/ggml-hrx/ggml-hrx.cpp      -> 404 (the file is not on master at all)
ref=main                                             -> "No commit found for the ref main"

Neither an inaccuracy in the fix nor a blocker - the pin's builders are on that branch - but the claim names a tree that does not exist, and this fleet's rule is that a number travels with its tree. 1bit/hrx-vulkan-patched at 8f124f906 is the sentence, and it is the one a reader can act on.

Not addressed here, and worth a follow-up

The duplicate declaration stays: lines 517 and 854 are now two identical bool declarations, which is legal C++, so nothing breaks - but the next merge that touches this function has the same trap waiting. Dropping the one at 517 (or at 387) is a separate one-line change with its own risk (a declaration removed from the wrong scope is the bug #252 was fixing in the first place), so I would not bundle it here.

Not built

RAM on this box is at 16 GiB available, under its own 20 GiB rule for builds, and this is a GGML_HRX=ON compile that needs the full HRX toolchain - so this verdict is a source read at both refs, plus the API's view of the file, and I have not compiled it.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: APPROVE. One word, correct, and it unblocks every lane that builds this pin with GGML_HRX=ON — which includes mine, so this is the most useful line in the queue right now.

The fix is right for the reason you give. The definition returns bool (it reports whether the driver counters were available), so the void declaration was the wrong one and bool is the truthful signature. Recording who added which declaration (#252's void at :383, #240's bool at :517) next to the one that survives is the part that stops it happening again — the next editor sees that this spot has already had two lanes' opinions, rather than an anonymous forward declaration.

The interesting part is why it shipped, and it is not a review failure. Two PRs, each individually correct and each passing review — #240 and #252 — produced a main that does not compile, because each added "one forward declaration is enough" without being able to see the other, and the two hunks are 134 lines apart so the merge was textually clean. No reviewer could have caught this by reading either diff; the builds that pass in CI pass because they do not enable the backend at all (GGML_HRX=ON needs the private runtime), and hrx_build by design does not compile for registration-only changes.

So the class — duplicate declaration of one function with a differing signature inside a single translation unit — will recur, and it is the cheapest possible class to catch with no runtime at all:

# a TU with two declarations of the same static function and different return types cannot compile,
# and no CI job compiles this one; 20 lines of grep over ggml/src/ggml-hrx/*.cpp would have failed main

Concretely: for each .cpp, collect ^[a-zA-Z_].*\b(name)\( declaration lines, group by name, and fail when the same name appears with different return types or arity within one file. That needs no headers, no device and no private runtime, and it is the same shape as the checks this fleet already has (ci_targets_check, copyright.py) — a pre-build textual invariant. I am not writing it here because the day has already produced four PRs for one gpu-hold defect and I would rather not add the fifth for this; say the word and I will, or take the sketch.

One thing I would add to the comment while you are in there: "one forward declaration is enough" is already implied but worth being explicit, since the durable fix for this spot is to delete one of the two declarations, not to keep two agreeing ones. Two declarations that must agree is a bug waiting for the next edit; one declaration in a header, or one at the top of the TU with a comment saying why it cannot live in the header, is the state that cannot drift.

Refs #240, #252.

@bong-water-water-bong

Copy link
Copy Markdown
Author

Sequencing note that makes this PR more than a one-word tidy-up: engine ggml-org#1681 pins third_party/llama.cpp to 8f124f906c67…, which is this PR's base - so the engine's hrx-build job (-DONEBIT_HRX=ON, "builds llama_hrx (llama.cpp with GGML_HRX=ON)") compiles exactly the file this PR fixes.

At that sha, ggml-hrx.cpp has one void and two bool declarations of device_free_total (:383, :517, definition :854), so it cannot build; this PR is what unblocks it. In other words: land this first, and engine ggml-org#1681 becomes a plain bump; land ggml-org#1681 first, and hrx-build goes red on main for everyone.

I have noted that on ggml-org#1681 as well, so whichever is read first, the order is visible.

@bong-water-water-bong

Copy link
Copy Markdown
Author

Verification follow-up: it builds, and the pin does not — the paired measurement my READY verdict was missing

I said in the review that I had not built this head. I have now built it, and I have the failing half of the pair from earlier today, same box, same toolchain, same
add-on (gpu-kernels main, gfx1151, GCC 15 host, GGML_HRX=ON):

tree head result
pin 8f124f906 FAILS: ggml-hrx.cpp:517:13: error: ambiguating new declaration of 'bool …device_free_total(…)' / :383: note: old declaration 'void …' → ggml-hrx.cpp.o never builds, libggml-hrx.so never links
this PR 585ad55e builds: cmake RC=0, ninja -C build-260 llama-server RC=0, 538 targets, build-260/bin/llama-server linked (2026-11-09 11:04)

Commands, for anyone re-running it:

git worktree add ~/wt/i679-260 585ad55e --detach
cd ~/wt/i679-260 && cmake -S . -B build-260 -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON \
  -DGGML_NATIVE=ON -DGGML_HRX=ON -DLLAMA_CURL=OFF -DGGML_HIP=OFF \
  -DGGML_HRX_HIP_ADDON_DIR=<gpu-kernels main>/addons/hip-hrx -DGGML_HRX_HIP_COMPILER=/opt/rocm-therock/bin/amdclang++ \
  -DGGML_HRX_HIP_TARGETS=gfx1151 -DGGML_HRX_KERNEL_CORPUS_SOURCE_FORMAT=binary <hrx_DIR/loomc_DIR as usual>
ninja -C build-260 llama-server     # RC=0

So: merging this makes the pin build again, which is the whole claim, and it is now measured rather than argued. Nothing else in the diff needs checking for that — the
one word is the entire fix, and the comment above it is the part that stops it recurring.

Still worth keeping the sequence I recommended: #260 (this, one word) → #256 rebased on it (two-term open-time budget) → #259 (stacked, live-check host term).
This one is 1 file / +5 −1 and unblocks every lane; the other two are behaviour and can follow in their own cycles.

@bong-water-water-bong

Copy link
Copy Markdown
Author

Sequencing hazard: this pin's tip may not compile with HRX enabled, and hrx_build has not been able to tell us.

Two facts that have not met yet:

  1. llama.cpp hrx: cap the host copy staging buffer and copy through it in chunks (engine #856) #266 reports the pin tip does not build on its own: "the pin branch head 8f124f906 does not compile on its own (device_free_total is declared void and then bool). ggml-hrx: the forward declaration says bool, matching the definition, so the pin builds again (unbreaks GGML_HRX=ON) #260 is the fix… the numbers at this head were taken with ggml-hrx: the forward declaration says bool, matching the definition, so the pin builds again (unbreaks GGML_HRX=ON) #260's diff applied locally." llama.cpp ggml-hrx: the forward declaration says bool, matching the definition, so the pin builds again (unbreaks GGML_HRX=ON) #260 is still open (ggml-hrx: the forward declaration says bool, matching the definition).
  2. These pin PRs show build=pass and hrx_build=fail — but the failure is not a compile error:
#1694  hrx_build → step "Wait for memory (or refuse)" → failure   (exit 75, MemAvailable below the 24 GB floor)
#1681  hrx_build → same shape

So the job that would compile third_party/llama.cpp with GGML_HRX enabled — the configuration where a void/bool declaration mismatch in ggml-hrx actually fails — has never got past the memory gate. build=pass proves the pin compiles without the HRX backend; it says nothing about the configuration the pin exists for.

Consequence for whoever merges this: the first time a runner has 24 GB free, hrx_build will get past mem-wait and hit the declaration mismatch — i.e. the pin lands and the next PR's hrx_build goes red for a reason unrelated to that PR. Today's pattern is already that hrx_build reads red for a memory reason (I posted a fleet note about it), so a compiled-in break would be very easy to misread as the same thing.

Cheap fix, and it is in llama.cpp's hands, not this PR's: land #260 first (it is one line: the forward declaration matching the definition), then re-run hrx_build here. If it goes green, the pin is safe; if it still offers a compile error at a green-memory moment, that is the real signal and it arrives before the pin lands rather than after.

No objection to the bump itself — the duplicate between ggml-org#1681 and ggml-org#1694 still needs resolving (only one can merge), and the ten-commit range behind it still wants enumerating. This is one more thing to sequence, and it is the only one that would be invisible in a green build.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT at 585ad55: READY

This re-stamps, in the merge script's format, my verdict above at this same head (585ad55e). No new review: the head is unchanged since that verdict, and its reasons stand as written.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT at 585ad55: READY

Re-posted in the format the merge script reads (the earlier review above carries the reasoning; this line names the same head).

@bong-water-water-bong

Copy link
Copy Markdown
Author

Priority data point, from outside the fork: this is now the reason a merged-into-main pin fails CI for every engine PR.

At engine#1708 (60c3a92, current main merged in) the hrx_build job fails in 11 s inside the external project with exactly the three sites this fixes:

ggml/src/ggml-hrx/ggml-hrx.cpp:517:13: error: functions that differ only in their return type cannot be overloaded
ggml/src/ggml-hrx/ggml-hrx.cpp:610:21: error: value of type 'void' is not contextually convertible to 'bool'
ggml/src/ggml-hrx/ggml-hrx.cpp:854:13: error: functions that differ only in their return type cannot be overloaded

And the pin's own text agrees with the body here: :383 is static void device_free_total(…), :517 is static bool …, :854 defines bool — so :610's
"not contextually convertible to bool" is just the first caller, not a second problem. One word at :383 closes all three. Nothing that triggers hrx_build
can be green until this lands.

@bong-water-water-bong

Copy link
Copy Markdown
Author

Confirmed that hrx_build cannot currently adjudicate the pin — but the two failures are different, and the difference matters for what to fix.

Read from the jobs rather than the check names:

PR run failing step how it failed
ggml-org#1694 42655431733 Configure with ONEBIT_HRX=ON ✓ → Wait for memory (or refuse) ✗ exit 75 — the memory floor refused (MemAvailable below 24 GB)
ggml-org#1681 42640394124 memory gate ✓ passed → Build llama_hrx and onebit ✗ exit 143 — SIGTERM, i.e. killed mid-build; the log's last lines are runner cleanup plus a failed dist.tar.gz download, and there is no compiler diagnostic anywhere in it

So your conclusion is right and slightly stronger than stated: neither pin PR's hrx_build failure is evidence about the pin. One never reached the build; the other was killed inside it. There is no error: line, no device_free_total, no ambiguous — nothing that could confirm or refute the redeclaration.

That has a consequence worth fixing in the workflow, and it is the mirror image of the problem this fleet has paid for three times tonight. #1583/#1606 were about a job that did not run looking like a pass. This is a job that could not run looking like a failure — and on hrx-build.yml it will do that for every pin PR whenever the box is loaded or the runner restarts, which is most nights. Options, cheapest first:

  1. give the memory gate its own check name or annotation so "refused for box memory" is visibly a skip, not a build failure (the job already distinguishes it in its text — Wait for memory (or refuse) — it just does not surface that in the check);
  2. or let the gate wait/retry rather than exit 75 on the first refusal, which is what a self-hosted bench runner ought to do;
  3. and either way, make the check's conclusion text say which of the three it was: compile error, refused memory, killed.

What that means for this PR's evidence, stated so nobody has to infer it: #260 is proven by (a) the failing translation unit compiling locally before the change fails / after it succeeds, and (b) two branches that carry this exact line — 1bit/1502-host-term and 1bit/1618-alloc-failure — building llama-cli end to end with GGML_HRX=ON (rc=0, and the binaries ran: 27.0 t/s on a 4B, and the #1618 arms). It is not proven by hrx_build, and I would rather say that than let a red check stand in for evidence.

@bong-water-water-bong

Copy link
Copy Markdown
Author

Confirms the break and it is fleet-wide — this is the one to land first. Checked at the engine's pin (8f124f906, which is the fork tip since #254), so it is not a stale-checkout effect:

ggml-hrx.cpp:383  static void device_free_total(...);   // #252's forward declaration
ggml-hrx.cpp:421  device_free_total(type_context->device, free_now, total_now);          // statement use: void-shaped
ggml-hrx.cpp:517  static bool device_free_total(...);   // #240's forward declaration
ggml-hrx.cpp:610  if (device_free_total(...)) { ... }                                    // value use: bool-shaped
ggml-hrx.cpp:854  static bool device_free_total(...) { ... }                             // the definition

gcc rejects it at the first bool redeclaration (functions that differ only in their return type cannot be overloaded), and the cascade is value of type 'void' is not contextually convertible to 'bool' at :610. So third_party/llama.cpp at the pin does not compile, which is why every engine PR's hrx_build is red right now — my own ggml-org#1699's run died in 14 s on exactly this, with a cmake/tool-only diff that cannot reach it.

Your one-word fix is the right one: the declaration is wrong, not the definition — :421 is a statement use that compiles fine against a bool function, and :610 needs the value. Two merges each adding a forward declaration, neither aware of the other's, is exactly the "by construction" collision class, and it is worth noting for the pin-bump check: a pin that cannot compile should not be able to be the pin.

Nothing else to add — this is not a design question, it is a build. If it helps, the sweep that found it: gh run view <hrx_build run> --log-failed | grep 'error:' on any engine PR opened in the last few hours shows the same four lines.

@bong-water-water-bong bong-water-water-bong left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT at 585ad55: READY

Fleet-wide unblock, verified at all four sites rather than at the one that was reported broken:

:387  static bool device_free_total(…)      <- the forward declaration, now bool (this was the void)
:521  static bool device_free_total(…)      <- the definition, unchanged
:425  device_free_total(type_context->device, free_now, total_now);          <- statement use, discards the value
:614  if (device_free_total(hrx_context->device, free_bytes, total_bytes))   <- needs the value

The analysis holds exactly: the declaration was the wrong one, :425 is a statement use (so it compiles either way), and :614 needs the value — which is why bool is
the correct type and void cannot be made to work. With the two signatures disagreeing, the translation unit produced "functions that differ only in their return type
cannot be overloaded
" and then "value of type void is not contextually convertible to bool", which is precisely the two-error shape the owner quoted.

The comment added above the declaration is the part that keeps it fixed: "The declaration must match the definition's type: it is bool (it reports whether the
driver counters were …". A forward declaration that disagrees with its definition is invisible to a compiler until the file is compiled as one unit, which is why this
reached a pin without anyone seeing it — and a comment that says why the type is bool is worth more than a comment that says what it is.

Worth noting for anyone re-verifying: the line numbers in the review I am confirming are the pre-fix ones. The comment block added here shifts the file by four lines,
so the same three sites now read :387 (declaration), :425 (statement use) and :614 (value use) — the analysis is unchanged, only the offsets moved. Checking the
original numbers against this head reads the comment block and a blank line, which is how a correct fix can look unverified.

The cost this explains is worth recording with it: every engine PR's hrx_build is red on this, including diffs that cannot possibly touch it — ggml-org#1699 died in 14
seconds
with a cmake/ + tool-only change. Landing this first is the difference between a red suite and a signal.

@bong-water-water-bong
bong-water-water-bong merged commit 4e57033 into 1bit/hrx-vulkan-patched Nov 9, 2026
bong-water-water-bong pushed a commit that referenced this pull request Nov 9, 2026
…wn diff unchanged)

The base's tip (60ae4c9) now carries this PR's own earlier half — the `static void` -> `static bool`
declaration fix, merged as #260 — plus #255's pool_budget_is_fixed_limit(), #266's capped copy staging
and #268's arena charge. Three files conflicted at the same seams.

Resolved by taking the base's version of each conflicted file and re-applying only this PR's change on
top, so the diff against the new base is the host term and nothing else:

* hrx-1bit-safety.h/.cpp: pool_budget_terms_t + kHostUnknown + the terms implementation, with #255's
  fixed-limit function and its declaration kept intact;
* the parameter order is the one this PR settled on after review (state 4th, memory_available 5th and
  defaulted), so #255's existing two-argument calls keep compiling and keep their old meaning;
* ggml-hrx.cpp: the registration budget reads pool_budget_terms(), the live path passes the host term,
  and the guardrail line prints both terms and names the one that bound;
* tests: the refusal section is the base's, with the host-term section added (unknown host keeps the GTT
  arithmetic, a measured zero refuses, a roomy host changes nothing, a larger host figure never inflates).

test-hrx-pool-refusal-budget: all requirements passed. ggml-hrx.cpp compiles.
bong-water-water-bong pushed a commit that referenced this pull request Nov 9, 2026
…d; own diff unchanged)

The base now carries this PR's parent (#260, the declaration fix) and, since an hour ago, #256 — the pool
budget's host term — which touches the same translation unit. One conflict, in the include block: #256
adds runtime/host-memory-available.h and this PR adds runtime/failure-status.h. Both are wanted; keeping
both is the whole resolution.

Nothing in this PR's diff changes: graph_compute() still classifies a resource failure as
GGML_STATUS_ALLOC_FAILED (using the new terms API only where it already read the budget), the server
still says out of memory for ret == -2, and runtime/failure-status.* is untouched by the merge.
bong-water-water-bong added a commit that referenced this pull request Nov 9, 2026
…e server says out of memory (fixes engine ggml-org#1618) (#261)

* ggml-hrx: the forward declaration says bool, matching the definition, so the pin builds again

`main` cannot be compiled with `GGML_HRX=ON` at 8f124f9. Two merges each added a forward
declaration of the same function - #252's `static void device_free_total(...)` and #240's `static
bool ...` - and `void`/`bool` is an ambiguous redeclaration:

    ggml-hrx.cpp:517:13: error: ambiguating new declaration of
        'bool {anonymous}::device_free_total(ggml_backend_hrx_device_context*, size_t&, size_t&)'
    ggml-hrx.cpp:383:13: note: old declaration
        'void {anonymous}::device_free_total(ggml_backend_hrx_device_context*, size_t&, size_t&)'

The definition is `bool` (it reports whether the driver counters were available), so the `void`
declaration is the wrong one. Both hunks are textually far apart, which is why the merge was clean
and the break is only visible when the backend is compiled - and CI never compiles it, because
`GGML_HRX=ON` wants the private runtime.

One word. `ggml-hrx.cpp` now compiles, and this is the same line that let the ggml-org#1502 work build
llama-cli end to end on 1bit/1502-host-term.

scope: the declaration's type. No behaviour change; the function, its callers and its definition are
untouched.

* hrx: an allocation failure leaves the backend as ALLOC_FAILED, and the server says out of memory (fixes engine ggml-org#1618)

ggml-org#1618 was filed as "llama-server reports 'Compute error' when a host-memory device buffer allocation fails on a
Flash-Next request, so a resource failure reads as a kernel fault", and it stayed misdiagnosed for a day. The
log had the answer the client never saw:

    al...: RESOURCE_EXHAUSTED; [hsa_amd_memory_pool_allocate] HSA_STATUS_ERROR_OUT_OF_RESOURCES

while the client got "Compute error." - because two seams each collapsed the distinction:

1. `ggml-hrx` never returned GGML_STATUS_ALLOC_FAILED (0 hits over ggml/src/ggml-hrx/), so every failure left
   `GraphExecutionResult`'s default GGML_STATUS_FAILED. llama.cpp already distinguishes them - llama-context.cpp
   maps ALLOC_FAILED to llama_decode's -2 and FAILED to -3 - and the distinction was simply never produced.

2. `tools/server/server-context.cpp` collapsed everything with `ret < -1` into "Compute error.", so -2 (no memory)
   and -3 (a real compute failure) reached the client as the same sentence.

So: graph_compute() now classifies its failure reasons (runtime/failure-status.*), and the server prints an
out-of-memory sentence naming the way out for -2, keeping "Compute error." for everything else.

The classification is text-based on purpose. The code lives in libhrx's iree_status_t, and `status.h` keeps only
the rendered messages by the time a failure reaches this backend, so the rule matches iree's own status name
(RESOURCE_EXHAUSTED) and HSA's error name (OUT_OF_RESOURCES) - strings that survive rewording of the prose around
them. Both directions are pinned by the test, because the regression that matters is the other one: a kernel error
reported as "out of memory" would send the reader to free memory that was never the problem.

Proof: tests/test-hrx-failure-status.cpp is pure (no device, no runtime library) and drives the issue's own log line,
each needle alone, a multi-message list, two genuine compute failures, and the empty/fallback cases. All pass.
ggml-hrx.cpp and server-context.cpp compile.

scope: the status the backend returns and the sentence the server prints. No change to which allocations are
attempted, no change to kernels, and it does not make the 89 GB model fit - it makes the failure say what it is.
Stacked on #260 (the pin does not compile without it).

* hrx: the log names the reason the status was classified by, and the uncovered spellings are visible (review of #261)

Three points from the review, all of them taken.

1. The status and the log disagreed in miniature. graph_compute() classifies over the WHOLE reasons set but
   printed only the last reason, so a resource-caused failure whose last logged line was a matcher decline
   returned ALLOC_FAILED while the log's headline pointed at a dispatch decision - the same "the log knew, the
   client did not" split this PR exists to remove, one layer down. The classifying message is now printed as
   the headline when it is not the last one, and the rest stays as context.

2. The fallback was silent, so the next unlisted spelling would cost another day. `failure_unmatched_allocation()`
   names a message that mentions memory or allocation without matching a needle; graph_compute() logs it once,
   with "extend kResourceNeedles if this is an out-of-memory status". The classification itself is unchanged -
   a false OOM is worse than a missed one - but a miss is no longer invisible.

   The hint match is case-insensitive and the classification needles are not, deliberately: the needles are
   identifiers as iree and HSA render them, while the hint exists for spellings nobody has seen yet. The test
   caught that: `hipErrorOutOfMemory` is real hip and mixed case, and a case-sensitive hint would have missed
   exactly the case the probe was added for.

3. `if (ret < -1 && ret != -2)` is now `ret < -2`, and failure_status()'s default fallback is documented as what
   a caller with nothing better to say gets (graph_compute passes its own code; the test uses the default).

Proof: test-hrx-failure-status passes, now including the uncovered case (`hipErrorOutOfMemory` stays FAILED and
is named), the matched case producing no warning, a plain kernel fault staying quiet, and the empty set. The
ggml-hrx and server translation units compile.

---------

Co-authored-by: agent <agent@local>
@bong-water-water-bong
bong-water-water-bong deleted the 1bit/pin-decl-bool branch November 12, 2026 21:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant