Repository navigation
hrx: say which relation a refused layout-alias node has, and pin alias elision in a host test (Refs #1467) - #258
Conversation
…meters
`fused_context_claim` accepted a per-head ROPE on SHAPE alone (`is_head_row(op) && fed_by_op(op)`), while the
two registrations that execute rotations accept different PARAMETER sets:
* llm/dispatch-attention-qkv.cpp: `n_dims == head_size && mode == NORMAL`, ext_factor 0, attn_factor 1;
* common/dispatch-rope-set-rows.cpp: `4 <= n_dims <= head_size`, multiple of 4, mode NORMAL / NEOX /
collapsible IMROPE.
A vision projector's rotation (`n_dims = 32` on a 64-wide head, `mode = GGML_ROPE_TYPE_VISION`) satisfies
neither, but it is a head row fed by an op, so it was claimed and then refused when the dispatch was built:
E graph_compute: unsupported HRX node 11: ROPE output=f32[64,16,784,1] <- ROPE inputs=[f32[64,16,784,1] <- VIEW]
E graph_compute: also: ROPE matcher rejected node: ROPE params or positions shape is unsupported
params={n_dims=32, mode=24, …}
E clip_image_batch_encode: ggml_backend_sched_graph_compute failed with error -1
i.e. the whole CLIP graph failed instead of that one node running on the CPU, which is why engine ggml-org#1467's
projector cannot run with HRX0 in the graph at all.
The condition now lives in one place, `ggml/src/ggml-hrx/rope-claim-params.h`: the two matcher predicates plus
their union. Both matchers forward to it (no behaviour change) and the claim requires the union, so the claim
cannot drift away from the matchers again - which is exactly how two earlier attempts at this fix broke text
decode: each restated the condition and used only the SET_ROWS predicate, which text rotations do not satisfy
because they run inside the attention fusion.
Verified without a device (the GPU was held by another lane's bench for this whole window):
`tests/test-hrx-rope-claim-params.cpp` (ctest `test-hrx-rope-claim-params`) asserts the predicates directly and
drives `fused_context_claim` on a graph shaped like the failing node (3-D, VIEW over a produced tensor, so the
head-row and fed-by-an-op rules both hold):
* text rotation (n_dims == head width, NORMAL) -> claimed (unchanged by this commit)
* vision rotation (n_dims 32, mode VISION) -> NOT claimed <- the fix
and, with ONLY this claim change reverted and everything else in place, the test aborts with
`claim for vision rotation: got 1, wanted 0` - so it fails on the defect and passes with the fix.
Still blocking the rest of ggml-org#1467: with the projector on HRX the next refused node is a pure-alias VIEW
(`unsupported HRX node 20: VIEW f32[2048,2,1,1] <- VIEW`), which is claimed by the standalone path rather than
by a fused claim. That is a separate change and is not in this commit.
Refs ggml-org#1467
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT: READY at 1479c05efdbdb86a0b5a7226df0eadaf114e4a70
This PR is stacked on #257 (636150d4a is #257's commit, which I READY'd and which is still open), so the new part is 1479c05ef, and that's what this verdict covers. Merge #257 first.
The diagnostic field is correct, and useful.
- The scheduler elides a layout alias exactly when
can_elide_layout_alias_node()holds (dispatch-scheduler.cpp:112-115):is_layout_alias_node(graph, node) && value_is_available(graph, node.inputs[0], covered). - The new
alias=same_storage|NOT_an_alias inputs=Nreports the first conjunct (alias op, one input,same_storage), so the refused-node line now separates the two cases ggml-org#1467 kept confusing. - The second conjunct follows:
same_storageon a refused node means its input wasn't available.
Notes, not blocking:
- The condition is re-implemented, not called.
is_layout_alias_node()(graph/graph.cpp:196-199) is exactlyis_layout_alias_op(op) && inputs.size() == 1 && same_storage(output, inputs[0]), which is what the new lines restate. #257 exists because restating a matcher's condition drifted twice, soconst bool same = is_layout_alias_node(graph, node);keeps the field tied to the predicate the scheduler actually uses. - The strided-view row is worth an issue of its own.
same_storage()compares the storage root, not the layout, so a strided VIEW passes the alias test and is elided, with the refusal landing on the consumer instead. It fails safe today, as you say, but a consumer that one day accepts a strided alias would read the wrong elements with no error. The test row pins the current behaviour, and an issue would make sure someone decides it. - Not run by me.
test-hrx-view-alias-elisionlinksggml-hrx,hrx::hrxandloomc::loomc, which needs a full HRX build, and there isn't one on this box at the moment. The message change itself is small enough to verify by reading. The test result is yours.
|
VERDICT: READY for its own change — head
Its own contribution is right, and it is the missing half of the ggml-org#1467 diagnosis. The scheduler line refused a node the log could only name by shape ( Two small asks:
|
VERDICT: READY (1 nit) — the helper you recomputed already exists twelve lines awayThe diagnosis is worth having: two completely different causes behind one shape, four wrong hypotheses and two retractions is a strong The nit: bool is_layout_alias_node(const Graph & graph, const GraphNode & node) {
return is_layout_alias_op(node.op) && node.inputs.size() == 1 &&
graph.values().same_storage(node.output, node.inputs[0]);
}Your hunk recomputes those three terms by hand ( if (is_layout_alias_op(node.op)) {
stream << " alias=" << (is_layout_alias_node(graph, node) ? "same_storage" : "not_aliasing_input")
<< " inputs=" << node.inputs.size();
}(Wording, optional: The host test is the right shape too — the three relations it pins (true alias, alias at an offset, genuinely strided view of the same shape) |
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT: APPROVE. Reporting the relation that was actually tested rather than a second opinion is the whole value here — but your own table contains a sharper finding than the body claims, and it is the one I would act on.
1. "A same_storage() root comparison elides a strided view, and the plan is refused at the consumer" is a landmine, and "fails safe today" is doing a lot of work. The elision decided the view was a no-op; the consumer then refused. So the safety of a strided alias currently comes from a different component that happens not to accept it — nothing in the elision path knows the layout is not equivalent. Any future matcher that accepts a strided input turns this into a silent wrong answer, with no test failing: the assertion you added pins that the plan is refused, which is a property of today's consumer, not of the elision.
The guard belongs where the decision is made: elide only when the view is a genuine no-op — same storage root and same type and same nb/offset as the source, i.e. compare the layout, not just the root. Then a strided or offset alias either plans correctly (if the consumer handles it) or is refused by the elision, and the existing row stays as the regression that proves it. That also removes the need for the reader to know which component is currently protecting them.
2. The offset-alias row asserts "plans", and "plans" is compatible with a wrong binding. If eliding a node with a non-zero offset rewires the consumer to the source, the plan is valid and reads the wrong bytes; if it rewires to the view, it is correct. Your table cannot distinguish those, and row 3 is the one where the distinction exists. Worth asserting what the plan binds (the offset and strides the consumer sees) rather than that a plan was produced — that is a two-line assertion on the scheduled node's inputs and it is the difference between "the elision is correct" and "the elision happened".
Neither is a blocker for the diagnostic change, which is right and useful: alias=same_storage inputs=1 / alias=NOT_an_alias inputs=2 reporting the same two tests the elision evaluates is exactly the discipline that keeps a message honest, and it is the same conclusion llama.cpp #257 reached about a claim restating a matcher's condition. The four wrong hypotheses and two retractions are the argument for having it.
Also good: the REQUIRE that a lone node's input provenance does not decide elision (rows 1 and 2) refutes the value_is_available() reading with a test instead of a comment on the issue, and the status line in the test's output coming from plan().status.errors() means the field is exercised, not compiled and hoped for. Device-free is the right level for a question about planning.
Refs ggml-org#1467 — and #257 is the same issue's other half: there a claim asserted less than the matcher required, here the plan asserts more than the layout supports. Both are single-source-of-truth problems in the end.
…s elision in a host test engine ggml-org#1467's projector is refused at a node the log names only by shape: E graph_compute: unsupported HRX node 20: VIEW output=f32[2048,2,1,1] <- VIEW inputs=[f32[2048,2,1,1]] consumers=[21:ADD] A layout-alias node is refused there for one of two completely different reasons and the shape cannot tell them apart: it IS an alias (one input, same storage as its input) whose input was not available when the node was visited, or it is not aliasing its input at all and therefore needs a dispatch that no registration provides. The message now says which: ... consumers=[…] alias=same_storage inputs=1 ... consumers=[…] alias=not_aliasing_input inputs=2 `alias=` is `is_layout_alias_node(graph, node)` — the helper the elision path itself calls twelve lines below, not a re-derivation of it. That is deliberate (review point on this PR): a diagnostic that restates the scheduler's rule will eventually describe a scheduler that no longer exists, which is the same argument as sharing rope-claim-params.h between the claim and its matchers in #257. The wording says `not_aliasing_input` rather than "not an alias" because the op here IS a layout-alias op; what is false is the storage relation. Alongside it, `tests/test-hrx-view-alias-elision.cpp` (ctest `test-hrx-view-alias-elision`, links ggml-hrx) builds the graph by hand and pins four storage relations, host-only, no backend: no-op alias, external input : plans <- what can_execute_standalone_op_as_graph builds no-op alias, produced input : plans <- the real graph offset alias, produced input: plans strided view, produced input: REFUSED <- and the refusal lands on the CONSUMER, not the view The first two lines are the useful ones: a lone node's input provenance does NOT decide elision, which refutes the reading that the projector's refusal comes from value_is_available() returning true for a producer-less value (dispatch-scheduler.cpp:102-106). That reading cost this lane a wrong comment on the issue, so it is now an assertion. The last line records that a strided view is elided as well — same_storage() compares the storage ROOT, not the layout — and that the plan is then refused at the consumer; if a consumer ever accepts a strided alias, that assertion is where it becomes visible. Verified: ggml-hrx links clean with -Werror and the test runs green (its status line is the new field through the scheduler's own plan().status.errors()). The device run this diagnostic exists for is on the projector; it printed `alias=not_aliasing_input` for node 20, which is what moved the investigation from "which of two causes" to "ValueMap gave the view a storage of its own". Refs ggml-org#1467
1479c05 to
5cd2181
Compare
|
Both review points are applied at
Rebuilt and re-ran after the change: |
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT: READY at 5cd2181
Re-verdict after the review point was applied. Against my READY at 1479c05e, git range-diff shows #257's commit 636150d4a unchanged. The only code change in 5cd2181a3 is the one asked for: the diagnostic now calls is_layout_alias_node(graph, node) instead of re-deriving it, and prints not_aliasing_input instead of NOT_an_alias.
Checked:
is_layout_alias_node()(graph/graph.cpp:196) is exactlyis_layout_alias_op(op) && inputs.size() == 1 && same_storage(output, inputs[0]), the same predicatecan_elide_layout_aliasuses at dispatch-scheduler.cpp:129. The field therefore reports the condition that was actually evaluated. It is only printed underis_layout_alias_op(node.op), sonot_aliasing_inputcannot appear on a non-alias op.- The branch is 4 commits behind the pin tip (based on
70b8fe458), andgit merge-treeonto8f124f906is clean. On that merged tree I compiled with-fsyntax-only -Werrorand the private hrx-system includes:dispatch-scheduler.cpp,tests/test-hrx-view-alias-elision.cpp,tests/test-hrx-rope-claim-params.cpp,dispatch-rope-set-rows.cpp,dispatch-attention-qkv.cpp. All rc=0. - Not run: the linked host test. Linking
ggml-hrxdid not fit in this box's ~2 GiB of available memory. The assertions as written are the four rows in the body:REQUIRE(noop_external),REQUIRE(noop_produced),REQUIRE(offset),REQUIRE(!strided).
Notes (non-blocking):
- The body says the strided refusal "lands on the consumer, not the view", but the test only asserts
!stridedand prints the status lines. If where the refusal lands is part of what this pins, assert that somestatus.errors()entry names the ADD consumer. - Merge order: #257 first, as the body says. Also, once this merges, the pin still carries the
void/booldevice_free_totalbreak that #260 fixes.GGML_HRX=ONstays red until #260 lands, whatever order these two go in.
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT: READY at 5cd2181a3344e5a55702d23a6ce8d7e268aafb7a.
The title undersells it: the message change ("say which relation a refused layout-alias node has") comes with two new host tests, test-hrx-rope-claim-params.cpp (173 lines) and test-hrx-view-alias-elision.cpp (142 lines), registered in tests/CMakeLists.txt. That is the difference between a diagnostic improvement and a claim someone can regress — the elision is now pinned in a host test, so a future change to the claim path has to keep the relation it reports.
Message-quality changes normally do not need a test; this one gets one anyway, and on the shape that matters (alias elision), which is why it is a READY rather than a "fine by inspection".
|
A question for you two, because it changes this PR's scope and you have already approved its head — I would rather ask than slip it in. The device run this diagnostic exists for came back with
Both print So: fold it into this PR, or take it as a follow-up against this one? The change is one expression in the same Either way this PR's own scope is unchanged and the two points from your reviews are applied. |
|
VERDICT: READY at The predicate sharing is real, not restated
rope_params_supported_by_attention_fusion() // n_dims == head_size, NORMAL, ext_factor == 0, attn_factor == 1
rope_params_supported_by_rope_set_rows() // n_dims in [4, head_size] and %4 == 0, NORMAL|NEOX|collapsible imrope
rope_params_supported_by_any_fusion() // the OR of the two
The union is correct, and the test proves the case where it mattersThe interesting property is that params.mode = GGML_ROPE_TYPE_NEOX; params.ext_factor = 1.0f;
REQUIRE(!rope_params_supported_by_attention_fusion(params, 64));
REQUIRE( rope_params_supported_by_rope_set_rows(params, 64));
REQUIRE( rope_params_supported_by_any_fusion(params, 64));plus the vision rotation ( The diagnostic line is right for the reason it givesagain answers "which of the two refusals is this" without restating the scheduler's rule — it calls Scope note, because it decides where this lands
What I did not run
|
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT at 5cd2181: READY
This re-stamps, in the merge script's format, my verdict above at this same head (5cd2181a). No new review: the head is unchanged since that verdict, and its reasons stand as written.
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT at 5cd2181: READY
Re-posted in the format the merge script reads (the earlier review above carries the reasoning; this line names the same head).
… branch's superset block The pin has this message code as #258 landed it; this branch has it with the why=/facts additions, so the superset is the resolution and nothing from the pin is lost. The previous merge commit carried the markers themselves, which is why the tree did not compile - caught by rebuilding before pushing, not by review.
… node (Refs ggml-org#1467) (#267) * hrx: claim a head-row ROPE only when a fused matcher accepts its parameters `fused_context_claim` accepted a per-head ROPE on SHAPE alone (`is_head_row(op) && fed_by_op(op)`), while the two registrations that execute rotations accept different PARAMETER sets: * llm/dispatch-attention-qkv.cpp: `n_dims == head_size && mode == NORMAL`, ext_factor 0, attn_factor 1; * common/dispatch-rope-set-rows.cpp: `4 <= n_dims <= head_size`, multiple of 4, mode NORMAL / NEOX / collapsible IMROPE. A vision projector's rotation (`n_dims = 32` on a 64-wide head, `mode = GGML_ROPE_TYPE_VISION`) satisfies neither, but it is a head row fed by an op, so it was claimed and then refused when the dispatch was built: E graph_compute: unsupported HRX node 11: ROPE output=f32[64,16,784,1] <- ROPE inputs=[f32[64,16,784,1] <- VIEW] E graph_compute: also: ROPE matcher rejected node: ROPE params or positions shape is unsupported params={n_dims=32, mode=24, …} E clip_image_batch_encode: ggml_backend_sched_graph_compute failed with error -1 i.e. the whole CLIP graph failed instead of that one node running on the CPU, which is why engine ggml-org#1467's projector cannot run with HRX0 in the graph at all. The condition now lives in one place, `ggml/src/ggml-hrx/rope-claim-params.h`: the two matcher predicates plus their union. Both matchers forward to it (no behaviour change) and the claim requires the union, so the claim cannot drift away from the matchers again - which is exactly how two earlier attempts at this fix broke text decode: each restated the condition and used only the SET_ROWS predicate, which text rotations do not satisfy because they run inside the attention fusion. Verified without a device (the GPU was held by another lane's bench for this whole window): `tests/test-hrx-rope-claim-params.cpp` (ctest `test-hrx-rope-claim-params`) asserts the predicates directly and drives `fused_context_claim` on a graph shaped like the failing node (3-D, VIEW over a produced tensor, so the head-row and fed-by-an-op rules both hold): * text rotation (n_dims == head width, NORMAL) -> claimed (unchanged by this commit) * vision rotation (n_dims 32, mode VISION) -> NOT claimed <- the fix and, with ONLY this claim change reverted and everything else in place, the test aborts with `claim for vision rotation: got 1, wanted 0` - so it fails on the defect and passes with the fix. Still blocking the rest of ggml-org#1467: with the projector on HRX the next refused node is a pure-alias VIEW (`unsupported HRX node 20: VIEW f32[2048,2,1,1] <- VIEW`), which is claimed by the standalone path rather than by a fused claim. That is a separate change and is not in this commit. Refs ggml-org#1467 * hrx: say which relation a refused layout-alias node has, and pin alias elision in a host test engine ggml-org#1467's projector is refused at a node the log names only by shape: E graph_compute: unsupported HRX node 20: VIEW output=f32[2048,2,1,1] <- VIEW inputs=[f32[2048,2,1,1]] consumers=[21:ADD] A layout-alias node is refused there for one of two completely different reasons and the shape cannot tell them apart: it IS an alias (one input, same storage as its input) whose input was not available when the node was visited, or it is not aliasing its input at all and therefore needs a dispatch that no registration provides. The message now says which: ... consumers=[…] alias=same_storage inputs=1 ... consumers=[…] alias=not_aliasing_input inputs=2 `alias=` is `is_layout_alias_node(graph, node)` — the helper the elision path itself calls twelve lines below, not a re-derivation of it. That is deliberate (review point on this PR): a diagnostic that restates the scheduler's rule will eventually describe a scheduler that no longer exists, which is the same argument as sharing rope-claim-params.h between the claim and its matchers in #257. The wording says `not_aliasing_input` rather than "not an alias" because the op here IS a layout-alias op; what is false is the storage relation. Alongside it, `tests/test-hrx-view-alias-elision.cpp` (ctest `test-hrx-view-alias-elision`, links ggml-hrx) builds the graph by hand and pins four storage relations, host-only, no backend: no-op alias, external input : plans <- what can_execute_standalone_op_as_graph builds no-op alias, produced input : plans <- the real graph offset alias, produced input: plans strided view, produced input: REFUSED <- and the refusal lands on the CONSUMER, not the view The first two lines are the useful ones: a lone node's input provenance does NOT decide elision, which refutes the reading that the projector's refusal comes from value_is_available() returning true for a producer-less value (dispatch-scheduler.cpp:102-106). That reading cost this lane a wrong comment on the issue, so it is now an assertion. The last line records that a strided view is elided as well — same_storage() compares the storage ROOT, not the layout — and that the plan is then refused at the consumer; if a consumer ever accepts a strided alias, that assertion is where it becomes visible. Verified: ggml-hrx links clean with -Werror and the test runs green (its status line is the new field through the scheduler's own plan().status.errors()). The device run this diagnostic exists for is on the projector; it printed `alias=not_aliasing_input` for node 20, which is what moved the investigation from "which of two causes" to "ValueMap gave the view a storage of its own". Refs ggml-org#1467 * hrx: say WHICH alias lookup missed, not just that one did `alias=not_aliasing_input` (previous commit) says a layout-alias node's storage is not its input's. On engine ggml-org#1467's text tower that is where the investigation stops, because two very different causes print the same word and they need different repairs: * `view_src_unregistered` — the `ggml_tensor` the node's `view_src` points at is not a value in this graph, so `find_alias_source`'s pointer lookup cannot hit and the storage-root fallback has nothing to match. Repair: register the value, or resolve the alias by storage *range* rather than by tensor-pointer identity. * `view_src_registered_but_storage_differs` — it WAS registered and the map still gave the view a storage of its own. Repair: that is a bug in the assignment itself, not in what the graph contains. Both now print distinctly: ... alias=not_aliasing_input(view_src_unregistered) inputs=1 ... alias=not_aliasing_input(view_src_registered_but_storage_differs) inputs=1 `find_tensor()` is public and `Value::tensor` is public (`graph/value-map.h:100-101`, `:84`), so this asks the same map the assignment asked, rather than re-deriving anything. Why it matters: the difference decides whether the next change is "register the missing value" or "match by storage range". Guessing wrong costs a device run each time, and this lane has already spent several. Coverage, stated plainly: the new branch is NOT exercised by `test-hrx-view-alias-elision` — every case there fails *before* the message is built (the strided case is refused at its consumer), and `unsupported_node_message` is file-local so the test cannot call it. What the test does show is that the change does not alter the four relations it pins. Exercising the new branch needs the projector on a device. Stacked on the previous commit (`1bit/1467-view-alias-diag`); merge that first. Refs ggml-org#1467 * hrx: print the two storages and the view's layout for a refused alias node Six hypotheses about engine ggml-org#1467's refused `VIEW` have died under their own tests (input provenance, offsets, strides, an unregistered view_src resolved by storage range, producer coverage, and the claim). Each one was tested by building the case it predicted and watching it not reproduce. That is the signal to stop predicting and print the two storages. For a layout-alias node whose storage is not its input's, the message now also carries: storages=out7/in3 nb=[4,8192,16384,32768] offs=0 * `storages=outN/inM` - the two `ValueStorageId`s. Equal ids with `alias=not_aliasing_input` would be a contradiction (the map agreed and the message says it did not); different ids are the fact every hypothesis has been guessing at; * `nb=[...]` and `offs=` - what layout the view describes. A view whose strides differ from its input's same-shape tensor is a strided alias, which is a different thing from "the map gave it a storage". With the `alias=` and `why=` fields from the two commits below, one run now answers: which storage the map gave the view, whether it is its input's, whether the view's own `view_src` was registered, and what layout it describes. Coverage, stated plainly: like the previous commit, this field is not exercised by `test-hrx-view-alias-elision` - the host cases fail before a message is built, and `unsupported_node_message` is file-local. What the test does show is that the four pinned relations and the added case still behave. Stacked on `1bit/1467-alias-reason` (#262), itself stacked on #258 and #257. Merge in that order. Refs ggml-org#1467 * tests: reproduce engine ggml-org#1467's refused VIEW on the host, with the run's own numbers The projector run printed the facts this case encodes: VIEW output=f32[2048,2,1,1] nb=[4,32768,65536,65536] offs=8192 alias=not_aliasing_input(view_src_unregistered) storages=out24/in11 Rows of 2048 f32 taken from a buffer whose rows are 8192 f32 apart (`nb[1]` = 32768 bytes = 4x the width), starting one row in (`offs` = 8192 bytes = 2048 f32), and the wide source is never registered as a value in the graph - which is why `find_alias_source`'s two tensor-identity lookups both miss and the view is given a storage of its own. `ViewKind::WideWindow` builds exactly that shape, so `test-hrx-view-alias-elision` now reproduces the refusal on a machine with no device: no-op alias, external input : plans no-op alias, produced input : plans offset alias, produced input: plans strided view, produced input: REFUSED <- refused at its CONSUMER wide window view (node 20) : REFUSED <- refused AT THE VIEW, as the projector is The assertion is `REQUIRE(!wide)`: that is today's behaviour and it is the defect. The fix is a densify dispatch for a layout-alias node that cannot be elided (copy the strided window into a contiguous transient - `dispatch-copy.cpp`'s append_f32_densify_dispatch already does this for permuted activations), and when it lands this line flips to `REQUIRE(wide)` - which makes the change visible in the test rather than inferred from a log line. Two traps for whoever writes it, recorded here because both produce a WRONG NUMBER rather than a failure: the copy must derive its source offsets from nb[]/offs (a densify that reuses the pre-densify plane offsets copies the wrong rows), and the transient must hold ne[0]*ne[1] contiguous elements of the same type. Refs ggml-org#1467 * hrx: drop the merge markers the previous commit carried, keeping this branch's superset block The pin has this message code as #258 landed it; this branch has it with the why=/facts additions, so the superset is the resolution and nothing from the pin is lost. The previous merge commit carried the markers themselves, which is why the tree did not compile - caught by rebuilding before pushing, not by review. * hrx: take the pin's AliasMiss block back, and re-apply only the facts on top of it The previous merge resolved this hunk to *this branch's* older version, which silently removed what the base added deliberately: the `AliasMiss` switch, i.e. the miss cause read from **assignment-time state**. That is the half an earlier review called blocking, and my resolution brought the forbidden re-ask of the map back with it. The reviewer caught it; this commit fixes it. Resolution now, per file: - `dispatch-scheduler.cpp`, `value-map.{h,cpp}`, `graph-diagnostics.cpp`: **the pin's versions** (AliasMiss + NoAliasSource/ExactViewSrc/RangeFallback, recorded when the storage is chosen); - and on top of the pin's block, only this branch's own addition: `storages=outN/inM nb=[…] offs=…`, which is the fact the six dead hypotheses needed. `why=` still comes from the pin's `AliasMiss`, never from a re-ask. - `<cinttypes>`/`<cstdio>` added for PRId64/snprintf, which the pin's file did not need. Rebuilt before committing: `ggml-hrx` links clean with -Werror, and the host test still pins the four relations plus `wide window view (node 20) : REFUSED`. Refs ggml-org#1467 --------- Co-authored-by: bcloud <bcloud@users.noreply.github.com>
Why
engine ggml-org#1467's projector is refused at a node the log names only by shape:
A layout-alias node is refused there for one of two completely different reasons, and the shape cannot tell them apart:
That ambiguity cost four wrong hypotheses and two published retractions. The message now says which:
alias=isis_layout_alias_node(graph, node)— the helper the elision path itself calls twelve lines below, not a re-derivation. (Review point, applied: a diagnostic that restates the scheduler's rule will eventually describe a scheduler that no longer exists. Same argument as sharingrope-claim-params.hwith its matchers in #257. Wording isnot_aliasing_inputrather than "not an alias" because the op here is a layout-alias op; what is false is the storage relation.)The host test
tests/test-hrx-view-alias-elision.cpp(ctesttest-hrx-view-alias-elision) builds the graph by hand and pins four storage relations, no device and no backend:can_execute_standalone_op_as_graphbuildsThe first two rows refute the reading that the projector's refusal comes from
value_is_available()returning true for a producer-less value (dispatch-scheduler.cpp:102-106) — that reading is now aREQUIREinstead of a comment. The last row records that a strided view is elided too (same_storage()compares the storage root, not the layout) and that the plan then fails at the consumer: safe today, and the assertion is where it becomes visible if a consumer ever accepts a strided alias.Verification
ggml-hrxlinks clean with-Werror; the test runs green and its status line is the new field arriving through the scheduler's ownplan().status.errors().alias=not_aliasing_inputfor the projector's node 20, which is what moved the investigation from "which of two causes" to "ValueMapgave the view a storage of its own" — recorded on engine#1467.Stacking
This PR is stacked on #257 (
1bit/1467-vision-rope-claim3): its diff against the pin is #257 plus two files (dispatch/dispatch-scheduler.cpp,tests/test-hrx-view-alias-elision.cpp+tests/CMakeLists.txt). Merge #257 first, or retarget this to the pin after it lands — the two do not conflict, but a reader diffing this alone will see the ROPE work as if it were part of it. (Review point, applied.)Refs ggml-org#1467