From a0139326742396c4c97988397ecdf9275932fae8 Mon Sep 17 00:00:00 2001 From: leejet Date: Sun, 1 Nov 2026 04:08:53 +0800 Subject: [PATCH] revert: restore public graph helper usage --- docs/build.md | 9 ++++--- docs/ggml_extensions.md | 24 +++++++++++-------- ggml | 2 +- src/core/compute_workspace.cpp | 12 +++++----- src/core/ggml_compat.cpp | 20 +++++++++------- src/core/ggml_compat.h | 35 +++++++++++++++++----------- src/core/ggml_extend_backend.cpp | 2 +- src/core/ggml_graph_cut.cpp | 40 ++++++++++++++++---------------- 8 files changed, 80 insertions(+), 64 deletions(-) diff --git a/docs/build.md b/docs/build.md index 5519d809..c2e9e47a 100644 --- a/docs/build.md +++ b/docs/build.md @@ -33,9 +33,8 @@ cmake --build build-upstream --config Release ``` Both patched and upstream builds use the selected library and matching private -headers for application graph helpers and backend integration. The generic -operator registration API remains in `ggml-ext.h`. Backend options such as -`-DSD_CUDA=ON` apply to the selected tree as usual. +headers for backend integration. Backend options such as `-DSD_CUDA=ON` apply +to the selected tree as usual. `SD_USE_UPSTREAM_GGML` defaults to `OFF`, which enables the patched GGML extensions. Set it to `ON` when using upstream GGML; it selects the compatibility @@ -53,8 +52,8 @@ quantization types remain available, subject to backend operator support. `SD_USE_SYSTEM_GGML=ON` instead links an installed GGML CMake package, located with `ggml_DIR` or `CMAKE_PREFIX_PATH`. An installed patched package must include -the extension API. Set `SD_GGML_SOURCE_DIR` to its matching source tree for -private graph and backend headers, including CUDA/HIP/MUSA vendor headers. +the extension and graph APIs. Set `SD_GGML_SOURCE_DIR` to its matching source +tree for private backend headers, including CUDA/HIP/MUSA vendor headers. The installed library must use the same ABI settings as sd.cpp, including `GGML_MAX_NAME`. For an upstream package, also set `SD_USE_UPSTREAM_GGML=ON` and point `SD_GGML_SOURCE_DIR` to its matching source diff --git a/docs/ggml_extensions.md b/docs/ggml_extensions.md index 31d050e3..4b7c22a8 100644 --- a/docs/ggml_extensions.md +++ b/docs/ggml_extensions.md @@ -448,18 +448,22 @@ kernel compiled for SM80 or newer. CPU, HIP, MUSA, and Vulkan do not advertise support. ggml no longer contains a Sol-Attn opcode, constructor, allocation rule, or backend kernel. -## Internal graph access +## Public graph access -`src/core/ggml_compat.cpp` uses `ggml-impl.h` for leaf enumeration, graph copying, -use-count preservation and range execution. Patched and upstream builds share -this implementation; ggml does not expose a separate public graph API for these -application helpers. Mapped copies retain node order and consumer counts, -including consumers outside a graph view. Invalid mappings leave the destination -unchanged. Workspace measurement, graph cuts and evaluation callbacks use these -helpers. +`ggml-graph.h` exposes leaf enumeration, append-only leaf construction, recorded +use counts, mapped inference-graph copying, use-count copying for segments, and +backend execution of a node range. Mapped copies retain node order and consumer +counts from the original graph, including consumers outside a graph view. The +caller owns tensor copies and remaps their storage and edges; invalid mappings +leave the destination graph unchanged. Range execution uses already allocated +tensors and retains the original graph's consumer counts. -The compatibility layer also retains the workaround for old Metal backends -wrapping failed host mappings. The patched Metal backend returns null directly. +Workspace measurement, graph cuts, and evaluation callbacks use these APIs. +Backend extensions require matching private headers. Compatibility with an +upstream ggml lacking this header is isolated in `src/core/ggml_compat.cpp`; that +optional build still requires matching upstream private headers. The compatibility +layer also retains the workaround for old Metal backends wrapping failed host +mappings. The patched Metal backend returns null directly when mapping fails. Vulkan command recording services are declared in the private `ggml/src/ggml-ext-vulkan.h`. Pipeline ownership, submission and synchronization diff --git a/ggml b/ggml index 18ffcfde..f70551c0 160000 --- a/ggml +++ b/ggml @@ -1 +1 @@ -Subproject commit 18ffcfde29cd0fc87f412314597ca86efde9c23e +Subproject commit f70551c00e3ee8d22c79ce93e605b8b59141cd9a diff --git a/src/core/compute_workspace.cpp b/src/core/compute_workspace.cpp index 2b300281..eaf13184 100644 --- a/src/core/compute_workspace.cpp +++ b/src/core/compute_workspace.cpp @@ -69,7 +69,7 @@ namespace sd { bool ComputeWorkspace::allocate(ggml_cgraph* graph, const AssignNodes& assign_nodes) { GGML_ASSERT(!active_); - const size_t capacity = static_cast(ggml_graph_n_nodes(graph) + sd_ggml_graph_n_leafs(graph)) + 8; + const size_t capacity = static_cast(ggml_graph_n_nodes(graph) + ggml_graph_n_leafs(graph)) + 8; if (scheduler_ == nullptr || capacity > scheduler_capacity_) { release(); scheduler_ = make_scheduler(capacity); @@ -104,8 +104,8 @@ namespace sd { for (int i = 0; i < ggml_graph_n_nodes(graph); ++i) { visit(ggml_graph_node(graph, i)); } - for (int i = 0; i < sd_ggml_graph_n_leafs(graph); ++i) { - visit(sd_ggml_graph_leaf(graph, i)); + for (int i = 0; i < ggml_graph_n_leafs(graph); ++i) { + visit(ggml_graph_leaf(graph, i)); } for (size_t i = 0; i < tensors.size(); ++i) { visit(tensors[i]->view_src); @@ -121,7 +121,7 @@ namespace sd { key.insert(key.end(), bytes, bytes + sizeof(value)); }; append(ggml_graph_n_nodes(graph)); - append(sd_ggml_graph_n_leafs(graph)); + append(ggml_graph_n_leafs(graph)); for (auto tensor : tensors) { append(tensor); append(tensor->type); @@ -150,7 +150,7 @@ namespace sd { const auto alignment_offset = reinterpret_cast(tensor->data) % ggml_backend_get_alignment(external); append(alignment_offset); } - const int32_t uses = sd_ggml_graph_use_count(graph, tensor); + const int32_t uses = ggml_graph_use_count(graph, tensor); append(uses); } // Match the full allocation metadata, including topology and external placement. @@ -197,7 +197,7 @@ namespace sd { const auto found = mapped.find(tensor); return found == mapped.end() ? nullptr : found->second; }; - GGML_ASSERT(sd_ggml_graph_cpy_mapped(graph, copy_graph, map_tensor, &copies)); + GGML_ASSERT(ggml_graph_cpy_mapped(graph, copy_graph, map_tensor, &copies)); Measurement result; auto scheduler = make_scheduler(graph_size); if (scheduler != nullptr) { diff --git a/src/core/ggml_compat.cpp b/src/core/ggml_compat.cpp index 3e64dbd1..061b3370 100644 --- a/src/core/ggml_compat.cpp +++ b/src/core/ggml_compat.cpp @@ -1,6 +1,8 @@ #include "core/ggml_compat.h" #include "core/ggml_extend_backend.h" +#ifdef SD_GGML_GRAPH_COMPAT +// Upstream ggml still requires its private graph layout for these operations. #include "ggml-impl.h" #include @@ -8,11 +10,11 @@ #include #include -int sd_ggml_graph_n_leafs(const ggml_cgraph* graph) { +int ggml_graph_n_leafs(const ggml_cgraph* graph) { return graph->n_leafs; } -ggml_tensor* sd_ggml_graph_leaf(const ggml_cgraph* graph, int index) { +ggml_tensor* ggml_graph_leaf(const ggml_cgraph* graph, int index) { if (index < 0) { index += graph->n_leafs; } @@ -20,12 +22,12 @@ ggml_tensor* sd_ggml_graph_leaf(const ggml_cgraph* graph, int index) { return graph->leafs[index]; } -void sd_ggml_graph_add_leaf(ggml_cgraph* graph, ggml_tensor* tensor) { +void ggml_graph_add_leaf(ggml_cgraph* graph, ggml_tensor* tensor) { GGML_ASSERT(tensor && graph->n_leafs < graph->size); graph->leafs[graph->n_leafs++] = tensor; } -int32_t sd_ggml_graph_use_count(const ggml_cgraph* graph, const ggml_tensor* tensor) { +int32_t ggml_graph_use_count(const ggml_cgraph* graph, const ggml_tensor* tensor) { if (!graph || !tensor || !graph->visited_hash_set.size) { return 0; } @@ -35,7 +37,7 @@ int32_t sd_ggml_graph_use_count(const ggml_cgraph* graph, const ggml_tensor* ten : 0; } -bool sd_ggml_graph_cpy_mapped(const ggml_cgraph* src, ggml_cgraph* dst, sd_ggml_graph_tensor_map_fn map, void* user_data) { +bool ggml_graph_cpy_mapped(const ggml_cgraph* src, ggml_cgraph* dst, ggml_graph_tensor_map_fn map, void* user_data) { if (!src || !dst || src == dst || !map || dst->grads || dst->grad_accs || src->n_nodes > dst->size || src->n_leafs > dst->size) { return false; @@ -102,7 +104,7 @@ bool sd_ggml_graph_cpy_mapped(const ggml_cgraph* src, ggml_cgraph* dst, sd_ggml_ ggml_graph_add_node(dst, tensor); } for (auto* tensor : leafs) { - sd_ggml_graph_add_leaf(dst, tensor); + ggml_graph_add_leaf(dst, tensor); } for (const auto& entry : counts) { const size_t index = ggml_hash_insert(&dst->visited_hash_set, entry.first); @@ -111,7 +113,7 @@ bool sd_ggml_graph_cpy_mapped(const ggml_cgraph* src, ggml_cgraph* dst, sd_ggml_ return true; } -bool sd_ggml_graph_cpy_use_counts(const ggml_cgraph* src, ggml_cgraph* dst) { +bool ggml_graph_cpy_use_counts(const ggml_cgraph* src, ggml_cgraph* dst) { if (!src || !dst || !src->visited_hash_set.size || !dst->visited_hash_set.size) { return false; } @@ -150,7 +152,7 @@ bool sd_ggml_graph_cpy_use_counts(const ggml_cgraph* src, ggml_cgraph* dst) { return true; } -ggml_status sd_ggml_backend_graph_compute_async_range(ggml_backend_t backend, ggml_cgraph* graph, int first, int last) { +ggml_status ggml_backend_graph_compute_async_range(ggml_backend_t backend, ggml_cgraph* graph, int first, int last) { if (!backend || !graph || first < 0 || last < first || last > graph->n_nodes) { return GGML_STATUS_FAILED; } @@ -160,6 +162,8 @@ ggml_status sd_ggml_backend_graph_compute_async_range(ggml_backend_t backend, gg auto view = ggml_graph_view(graph, first, last); return ggml_backend_graph_compute_async(backend, &view); } +#endif + #ifdef SD_USE_UPSTREAM_GGML #include "ggml-backend-impl.h" #endif diff --git a/src/core/ggml_compat.h b/src/core/ggml_compat.h index 86bcc429..9f64262f 100644 --- a/src/core/ggml_compat.h +++ b/src/core/ggml_compat.h @@ -3,14 +3,19 @@ #include "ggml-backend.h" -int sd_ggml_graph_n_leafs(const struct ggml_cgraph* graph); -struct ggml_tensor* sd_ggml_graph_leaf(const struct ggml_cgraph* graph, int index); -// Like ggml_graph_add_node, appends metadata without traversing tensor dependencies. -void sd_ggml_graph_add_leaf(struct ggml_cgraph* graph, struct ggml_tensor* tensor); -// Returns zero when the tensor has no recorded use count. Includes uses outside graph views. -int32_t sd_ggml_graph_use_count(const struct ggml_cgraph* graph, const struct ggml_tensor* tensor); +#if __has_include("ggml-graph.h") +#include "ggml-graph.h" +#elif defined(SD_USE_UPSTREAM_GGML) +#define SD_GGML_GRAPH_COMPAT -typedef struct ggml_tensor* (*sd_ggml_graph_tensor_map_fn)(const struct ggml_tensor* tensor, void* user_data); +int ggml_graph_n_leafs(const struct ggml_cgraph* graph); +struct ggml_tensor* ggml_graph_leaf(const struct ggml_cgraph* graph, int index); +// Like ggml_graph_add_node, appends metadata without traversing tensor dependencies. +void ggml_graph_add_leaf(struct ggml_cgraph* graph, struct ggml_tensor* tensor); +// Returns zero when the tensor has no recorded use count. Includes uses outside graph views. +int32_t ggml_graph_use_count(const struct ggml_cgraph* graph, const struct ggml_tensor* tensor); + +typedef struct ggml_tensor* (*ggml_graph_tensor_map_fn)(const struct ggml_tensor* tensor, void* user_data); // Copies forward node/leaf order and recorded use counts, including external consumers. // The callback must be injective and may return NULL for dependencies outside the @@ -18,17 +23,21 @@ typedef struct ggml_tensor* (*sd_ggml_graph_tensor_map_fn)(const struct ggml_ten // Tensor storage and edges are mapped by the caller. // The destination must have no gradients and enough capacity. Gradients are not copied. // Invalid mappings leave the destination unchanged. src and dst must be distinct. -bool sd_ggml_graph_cpy_mapped(const struct ggml_cgraph* src, struct ggml_cgraph* dst, sd_ggml_graph_tensor_map_fn map, void* user_data); +bool ggml_graph_cpy_mapped(const struct ggml_cgraph* src, struct ggml_cgraph* dst, ggml_graph_tensor_map_fn map, void* user_data); // Copies recorded counts for tensors in dst's node/leaf lists. Other metadata is unchanged. // This preserves external consumers when constructing an inference graph segment. -bool sd_ggml_graph_cpy_use_counts(const struct ggml_cgraph* src, struct ggml_cgraph* dst); +bool ggml_graph_cpy_use_counts(const struct ggml_cgraph* src, struct ggml_cgraph* dst); // Executes nodes [first, last) with the original graph's use counts. No graph ownership // is transferred. Tensor storage must already be allocated; invalid bounds fail. -enum ggml_status sd_ggml_backend_graph_compute_async_range(ggml_backend_t backend, - struct ggml_cgraph* graph, - int first, - int last); +enum ggml_status ggml_backend_graph_compute_async_range(ggml_backend_t backend, + struct ggml_cgraph* graph, + int first, + int last); + +#else +#error "Patched ggml requires ggml-graph.h; select SD_USE_UPSTREAM_GGML for upstream compatibility" +#endif #endif diff --git a/src/core/ggml_extend_backend.cpp b/src/core/ggml_extend_backend.cpp index 40554cb5..47fe80ff 100644 --- a/src/core/ggml_extend_backend.cpp +++ b/src/core/ggml_extend_backend.cpp @@ -647,7 +647,7 @@ ggml_status sd_backend_graph_compute_with_eval_callback(ggml_backend_t backend, need = callback_eval(t, true, callback_eval_user_data); } - status = sd_ggml_backend_graph_compute_async_range(backend, gf, j0, j1 + 1); + status = ggml_backend_graph_compute_async_range(backend, gf, j0, j1 + 1); if (status != GGML_STATUS_SUCCESS) { break; } diff --git a/src/core/ggml_graph_cut.cpp b/src/core/ggml_graph_cut.cpp index cf0f63b3..fc6d8c63 100644 --- a/src/core/ggml_graph_cut.cpp +++ b/src/core/ggml_graph_cut.cpp @@ -35,8 +35,8 @@ namespace sd::ggml_graph_cut { static int graph_leaf_index(ggml_cgraph* gf, const ggml_tensor* tensor) { GGML_ASSERT(gf != nullptr); GGML_ASSERT(tensor != nullptr); - for (int i = 0; i < sd_ggml_graph_n_leafs(gf); ++i) { - if (sd_ggml_graph_leaf(gf, i) == tensor) { + for (int i = 0; i < ggml_graph_n_leafs(gf); ++i) { + if (ggml_graph_leaf(gf, i) == tensor) { return i; } } @@ -389,7 +389,7 @@ namespace sd::ggml_graph_cut { return fail(segment_label + " references an unavailable cut node " + std::to_string(input.node_index)); } - } else if (input.leaf_index < 0 || input.leaf_index >= sd_ggml_graph_n_leafs(gf)) { + } else if (input.leaf_index < 0 || input.leaf_index >= ggml_graph_n_leafs(gf)) { return fail(segment_label + " references an invalid leaf " + std::to_string(input.leaf_index)); } @@ -444,15 +444,15 @@ namespace sd::ggml_graph_cut { int leaf_count(ggml_cgraph* gf) { GGML_ASSERT(gf != nullptr); - return sd_ggml_graph_n_leafs(gf); + return ggml_graph_n_leafs(gf); } ggml_tensor* leaf_tensor(ggml_cgraph* gf, int leaf_index) { GGML_ASSERT(gf != nullptr); - if (leaf_index < 0 || leaf_index >= sd_ggml_graph_n_leafs(gf)) { + if (leaf_index < 0 || leaf_index >= ggml_graph_n_leafs(gf)) { return nullptr; } - return sd_ggml_graph_leaf(gf, leaf_index); + return ggml_graph_leaf(gf, leaf_index); } ggml_backend_buffer_t tensor_buffer(const ggml_tensor* tensor) { @@ -548,11 +548,11 @@ namespace sd::ggml_graph_cut { }; std::vector graph_layout(ggml_cgraph* graph, bool include_bindings) { - const size_t graph_size = static_cast(sd_ggml_graph_n_leafs(graph)) + ggml_graph_n_nodes(graph); + const size_t graph_size = static_cast(ggml_graph_n_leafs(graph)) + ggml_graph_n_nodes(graph); GraphLayoutTensors layout_tensors(graph_size); const auto& tensors = layout_tensors.tensors; - for (int i = 0; i < sd_ggml_graph_n_leafs(graph); ++i) { - layout_tensors.add(sd_ggml_graph_leaf(graph, i)); + for (int i = 0; i < ggml_graph_n_leafs(graph); ++i) { + layout_tensors.add(ggml_graph_leaf(graph, i)); } for (int i = 0; i < ggml_graph_n_nodes(graph); ++i) { layout_tensors.add(ggml_graph_node(graph, i)); @@ -568,9 +568,9 @@ namespace sd::ggml_graph_cut { GGML_MAX_OP_PARAMS / sizeof(int32_t) + (include_bindings ? 2 : 0); signature.reserve(2 + graph_size + tensors.size() * tensor_fields); signature.push_back(ggml_graph_n_nodes(graph)); - signature.push_back(sd_ggml_graph_n_leafs(graph)); - for (int i = 0; i < sd_ggml_graph_n_leafs(graph); ++i) { - signature.push_back(layout_tensors.index(sd_ggml_graph_leaf(graph, i))); + signature.push_back(ggml_graph_n_leafs(graph)); + for (int i = 0; i < ggml_graph_n_leafs(graph); ++i) { + signature.push_back(layout_tensors.index(ggml_graph_leaf(graph, i))); } for (int i = 0; i < ggml_graph_n_nodes(graph); ++i) { signature.push_back(layout_tensors.index(ggml_graph_node(graph, i))); @@ -606,12 +606,12 @@ namespace sd::ggml_graph_cut { const Plan& plan, const std::vector& layout) { GGML_ASSERT(gf != nullptr); - if (plan.leaf_names.size() != static_cast(sd_ggml_graph_n_leafs(gf)) || + if (plan.leaf_names.size() != static_cast(ggml_graph_n_leafs(gf)) || plan.layout != layout) { return false; } - for (int i = 0; i < sd_ggml_graph_n_leafs(gf); ++i) { - if (plan.leaf_names[i] != sd_ggml_graph_leaf(gf, i)->name) { + for (int i = 0; i < ggml_graph_n_leafs(gf); ++i) { + if (plan.leaf_names[i] != ggml_graph_leaf(gf, i)->name) { return false; } } @@ -654,7 +654,7 @@ namespace sd::ggml_graph_cut { } return ggml_graph_node(gf, input_ref.node_index); } - if (input_ref.leaf_index < 0 || input_ref.leaf_index >= sd_ggml_graph_n_leafs(gf)) { + if (input_ref.leaf_index < 0 || input_ref.leaf_index >= ggml_graph_n_leafs(gf)) { return nullptr; } return leaf_tensor(gf, input_ref.leaf_index); @@ -735,7 +735,7 @@ namespace sd::ggml_graph_cut { GGML_ASSERT(segment_graph != nullptr); for (ggml_tensor* leaf : leaves) { - sd_ggml_graph_add_leaf(segment_graph, leaf); + ggml_graph_add_leaf(segment_graph, leaf); } for (int output_node_index : segment.output_node_indices) { @@ -752,7 +752,7 @@ namespace sd::ggml_graph_cut { for (int node_idx : segment.internal_node_indices) { ggml_graph_add_node(segment_graph, ggml_graph_node(gf, node_idx)); } - GGML_ASSERT(sd_ggml_graph_cpy_use_counts(gf, segment_graph)); + GGML_ASSERT(ggml_graph_cpy_use_counts(gf, segment_graph)); *graph_ctx_out = graph_ctx; return segment_graph; } @@ -888,8 +888,8 @@ namespace sd::ggml_graph_cut { return plan; } plan.layout = graph_layout(gf, false); - for (int i = 0; i < sd_ggml_graph_n_leafs(gf); ++i) { - plan.leaf_names.emplace_back(sd_ggml_graph_leaf(gf, i)->name); + for (int i = 0; i < ggml_graph_n_leafs(gf); ++i) { + plan.leaf_names.emplace_back(ggml_graph_leaf(gf, i)->name); } plan.compute_buffer_size = measure_graph_compute_buffer(backend, gf, params_tensor_set);