Skip to content

ggml: allow passing alloc dependencies in graph_optimize - #27301

Merged
am17an merged 3 commits into
ggml-org:masterfrom
am17an:graph-opt-alloc-dep
Aug 30, 2026
Merged

ggml: allow passing alloc dependencies in graph_optimize#27301
am17an merged 3 commits into
ggml-org:masterfrom
am17an:graph-opt-alloc-dep

Conversation

@am17an

@am17an am17an commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Overview

Currently a backend doesn't have a good way to tell the allocator to not re-use memory for tensor operations which can be used for fusion or same-gpu parallelization (concurrent streams), this necessitates backends to work around this by implementing memory checks + also disabling fusion when memory checks fail. Some fusions never run because of this (e.g. #25952 (comment), #21897),

This PR introduces an extension to the graph_optimize API which can used by backends to add allocator dependencies in graph_optimize, e.g.

  static void ggml_backend_mybackend_graph_optimize(ggml_backend_t backend, ggml_cgraph * cgraph,
                                                    ggml_backend_graph_optimize_params * params) {
      // ... detect fork/join regions, decide stream assignment ...

      for (const auto & branch : branches) {
          for (const ggml_tensor * n : branch) {
              // the node itself: another branch must not reuse its memory before the join
              params->add_alloc_dep(params->user_data, const_cast<ggml_tensor *>(n), join_node);

              // its sources: e.g. attn_norm's output is read by all three branches concurrently,
              // and inp_pos is read by Qrope and Krope - none of them may be recycled mid-region
              for (int i = 0; i < GGML_MAX_SRC; ++i) {
                  if (n->src[i]) {
                      params->add_alloc_dep(params->user_data, n->src[i], join_node);
                  }
              }
          }
      }
  }

This can be also be used for fusion to avoid creating scratch buffers:

e.g. for MoE reduce in #25952

  params->add_alloc_dep(params->user_data, experts,      reduce_node);
  params->add_alloc_dep(params->user_data, weights,      reduce_node);
  params->add_alloc_dep(params->user_data, expert_scale, reduce_node);

Additional information

Requirements

@am17an
am17an requested review from a team as code owners August 18, 2026 06:29
@github-actions github-actions Bot added Vulkan Issues specific to the Vulkan backend ggml changes relating to the ggml tensor library for machine learning Apple Metal https://en.wikipedia.org/wiki/Metal_(API) Hexagon CUDA Related to the CUDA backend labels Aug 18, 2026
@ggerganov ggerganov self-assigned this Aug 18, 2026
@am17an
am17an requested a review from ggerganov as a code owner August 22, 2026 15:32
@github-actions github-actions Bot added the testing Everything test related label Aug 22, 2026
@anujj

anujj commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

I tested #25952 locally with this PR, and this PR solves the lifetime issue cleanly. I registered experts, weights, and the optional expert_scale as allocation dependencies.

@anujj

anujj commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

@ggerganov: did you get chance to review this PR ?

@ggerganov

Copy link
Copy Markdown
Member

@anujj For my understanding, how did you test it? The PR currently does not provide any dependency information from the CUDA backend.

Comment thread ggml/src/ggml-backend.cpp

@ggerganov ggerganov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Before merging, can we get a sample fusion implementation based on this mechanism to understand better how it would work in the a real case?

@am17an

am17an commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

I've put them in the PR desc earlier, do you want to me actually add one here?

@ggerganov

ggerganov commented Aug 29, 2026

Copy link
Copy Markdown
Member

Not needed to add to this PR. If you have a branch with #21897 for example using this new dependency information?

@am17an

am17an commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

@ggerganov in 56339ee I have made the changes to use this PR and enable concurrent streams

@am17an am17an added the merge ready A maintainer can use this label to indicate that they consider the changes final and ready to merge. label Aug 29, 2026
@am17an

am17an commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

cc @jeffbolznv if you have any thoughts before we merge

@max-krasnyansky max-krasnyansky left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good to me. We might have a use for this soon in ggml-hexagon

@jeffbolznv

Copy link
Copy Markdown
Contributor

It's not immediately obvious to me in which situations graph_optimize should call it vs when we can get away without doing it, or if we should just be calling it for all fusions. I also think the new view nodes have a chance of breaking fusions if they're not carefully placed. e.g. vulkan's graph_optimize goes to some effort to bunch view nodes together into groups so they aren't interleaved with non-empty ops, and using this callback will potentially scatter more views in between real ops. Like, if I have fusions for both rms_norm+mul and rms_norm+mul+rope, then I don't want to make mul depend on rms_norm and end up with a graph of rms_norm+mul+view+rope that breaks my rms_norm+mul+rope fusion.

I think when I had first suggested something like this in the past, my idea was to add the dependencies as additional operands to the existing nodes rather than additional nodes. That would avoid the issue of the additional views getting in the way. But it has drawbacks, too, like needing to modify tensors that should be treated as const.

@ggerganov

ggerganov commented Aug 29, 2026

Copy link
Copy Markdown
Member

Maybe an alternative approach is to carry the dependencies as part of ggml_cgraph instead of trying to modify or add new nodes to express those dependencies. The allocator can be adjusted to respect the dependencies from ggml_cgraph. (note I didn't look if it makes sense implementation-wise, just a thought to consider)

@am17an

am17an commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

I think it can be refactored to do that if we find big issues with the current approach. For now as its opt-in I don't see issues doing this since it's already an established pattern in the scheduler.

I plan to add this for big perf improvement fusions like topk-moe and some others and let the rest just be as they are today.

@am17an
am17an merged commit 57291f2 into ggml-org:master Aug 30, 2026
42 of 48 checks passed
jbooth pushed a commit to jbooth/llama.cpp that referenced this pull request Aug 30, 2026
)

* ggml: allow passing alloc dependencies in graph_optimize

* add alloc dep tests

* add TODO about using flat array
fewtarius pushed a commit to fewtarius/CachyLLama that referenced this pull request Sep 5, 2026
)

* ggml: allow passing alloc dependencies in graph_optimize

* add alloc dep tests

* add TODO about using flat array
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Apple Metal https://en.wikipedia.org/wiki/Metal_(API) CUDA Related to the CUDA backend ggml changes relating to the ggml tensor library for machine learning Hexagon merge ready A maintainer can use this label to indicate that they consider the changes final and ready to merge. testing Everything test related Vulkan Issues specific to the Vulkan backend

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants