revert: restore public graph helper usage

This commit is contained in:
leejet committed 2026-11-01 04:08:53 +08:00
1 parent ee12f0ea97
commit a013932674
8 files changed
+77 -61

No files matched your search

+4 -5
View File
@@ -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
+14 -10
View File
@@ -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
+1 -1
Submodule ggml updated: 18ffcfde29...f70551c00e.
+6 -6
View File
@@ -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<size_t>(ggml_graph_n_nodes(graph) + sd_ggml_graph_n_leafs(graph)) + 8;
const size_t capacity = static_cast<size_t>(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<uintptr_t>(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) {
+12 -8
View File
@@ -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 <unordered_map>
@@ -8,11 +10,11 @@
#include <utility>
#include <vector>
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
+19 -10
View File
@@ -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,
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
+1 -1
View File
@@ -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;
}
+20 -20
View File
@@ -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<uint64_t> graph_layout(ggml_cgraph* graph, bool include_bindings) {
const size_t graph_size = static_cast<size_t>(sd_ggml_graph_n_leafs(graph)) + ggml_graph_n_nodes(graph);
const size_t graph_size = static_cast<size_t>(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<uint64_t>& layout) {
GGML_ASSERT(gf != nullptr);
if (plan.leaf_names.size() != static_cast<size_t>(sd_ggml_graph_n_leafs(gf)) ||
if (plan.leaf_names.size() != static_cast<size_t>(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);