diff --git a/ggml/src/ggml-hrx/dispatch/dispatch-scheduler.cpp b/ggml/src/ggml-hrx/dispatch/dispatch-scheduler.cpp index af4c17a959a2..022fec706366 100644 --- a/ggml/src/ggml-hrx/dispatch/dispatch-scheduler.cpp +++ b/ggml/src/ggml-hrx/dispatch/dispatch-scheduler.cpp @@ -1,3 +1,5 @@ +#include +#include #include "dispatch-scheduler.h" #include "ggml.h" @@ -126,7 +128,22 @@ static std::string unsupported_node_message(const Graph & graph, size_t index, c case AliasMiss::None: break; } } - stream << " alias=" << relation << why << " inputs=" << node.inputs.size(); + // THE FACTS, on top of the recorded reason: six hypotheses died on this node, so the message also carries the two + // ValueStorageIds and what layout the view describes (engine #1467). `why` above is the assignment-time reason + // (AliasMiss), which the pin's version computes and which must not be re-asked of the map here. + std::string facts; + if (!aliasing && out != nullptr && out->tensor != nullptr && node.inputs.size() == 1) { + const Value * in_v = graph.values().find(node.inputs[0]); + if (in_v != nullptr) { + char buf[192]; + const ggml_tensor * t = out->tensor; + std::snprintf(buf, sizeof buf, " storages=out%d/in%d nb=[%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 "] offs=%zu", + out->storage.value, in_v->storage.value, t->nb[0], t->nb[1], t->nb[2], t->nb[3], + t->view_offs); + facts = buf; + } + } + stream << " alias=" << relation << why << facts << " inputs=" << node.inputs.size(); } return stream.str(); } diff --git a/tests/test-hrx-view-alias-elision.cpp b/tests/test-hrx-view-alias-elision.cpp index 8c1946c8a6d1..eeada6bd0a97 100644 --- a/tests/test-hrx-view-alias-elision.cpp +++ b/tests/test-hrx-view-alias-elision.cpp @@ -50,7 +50,7 @@ const DispatchTarget kTarget{ "gfx1151" }; // A graph shaped like the failing one: an external leaf, one op that produces a value on this backend, and a // no-op layout alias on top of it. `produced` selects whether the alias's input is that produced value (the // real graph) or a second external leaf (what can_execute_standalone_op_as_graph builds). -enum class ViewKind { NoOpAlias, OffsetAlias, StridedView }; +enum class ViewKind { NoOpAlias, OffsetAlias, StridedView, WideWindow }; bool plans_with_view(ViewKind kind, bool produced) { ggml_init_params params = { /*mem_size*/ 32 * 1024 * 1024, /*mem_buffer*/ nullptr, /*no_alloc*/ false }; @@ -70,6 +70,17 @@ bool plans_with_view(ViewKind kind, bool produced) { case ViewKind::NoOpAlias: view = ggml_view_2d(ctx, base, 2048, 2, base->nb[1], 0); break; case ViewKind::OffsetAlias: view = ggml_view_2d(ctx, base, 2048, 2, base->nb[1], base->nb[1]); break; case ViewKind::StridedView: view = ggml_view_2d(ctx, base, 2048, 2, 2 * base->nb[1], 0); break; + case ViewKind::WideWindow: { + // THE SHAPE engine #1467 actually refuses, with the numbers the run printed: + // VIEW f32[2048,2,1,1] nb=[4,32768,65536,65536] offs=8192 + // i.e. 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). The wide source is never registered as a + // value - the run also printed view_src_unregistered - so both of find_alias_source's tensor-identity + // lookups miss and the view gets a storage of its own. + ggml_tensor * wide = ggml_new_tensor_2d(ctx, GGML_TYPE_F32, 8192, 4); + view = ggml_view_2d(ctx, wide, 2048, 2, 32768, 8192); + break; + } } REQUIRE(view != nullptr); ggml_tensor * out = ggml_scale(ctx, view, 0.5f); @@ -124,6 +135,8 @@ int main() { std::printf("no-op alias, produced input : %s\n", noop_produced ? "plans" : "REFUSED"); std::printf("offset alias, produced input: %s\n", offset ? "plans" : "REFUSED"); std::printf("strided view, produced input: %s\n", strided ? "plans" : "REFUSED"); + const bool wide = plans_with_view(ViewKind::WideWindow, true); + std::printf("wide window view (node 20) : %s\n", wide ? "plans" : "REFUSED"); // A no-op layout alias plans whether its input is an External leaf (the single-node graph that // can_execute_standalone_op_as_graph builds) or a value this backend produces (the real graph). That REFUTES @@ -138,5 +151,9 @@ int main() { // the safe outcome it is today: the plan is refused, not silently computed through a wrong layout. If a consumer // ever accepts a strided alias, THIS assertion is where it should become visible. REQUIRE(!strided); + // Documented CURRENT behaviour, and it is the defect: the projector's wide-window view is refused because it aliases + // bytes the graph never registered, and nothing can dispatch a layout-alias op. The densify dispatch that fixes this + // flips this assertion to REQUIRE(wide) - when that lands, this line is where the change is visible. + REQUIRE(!wide); return 0; }