Commit cb44fdb18 for llama.cpp
commit cb44fdb1892eebca072e0949875a60c11245a8bb
Author: Georgi Gerganov <ggerganov@gmail.com>
Date: Wed Nov 11 19:58:39 2026 +0200
llama : reuse graph result instances across scheduler reserves (#32089)
Allocate gf_res_reserve and both gf_res_prev entries once in the llama_context constructor. Add llm_graph_result::set_max_nodes() and reset the existing instances in sched_reserve() instead of recreating them. get_gf_res_prev() now only selects the arena for the current batch.
Assisted-by: dsh:llama.cpp/ggml-org/DeepSeek-V4.1-Flash-1017-GGUF (Mac Studio, M5 Ultra, 256GB)
diff --git a/src/llama-context.cpp b/src/llama-context.cpp
index 89961847b..12db2068e 100644
--- a/src/llama-context.cpp
+++ b/src/llama-context.cpp
@@ -449,6 +449,15 @@ llama_context::llama_context(
__func__, cparams.n_ctx_seq, hparams.n_ctx_train);
}
+ {
+ const int64_t max_nodes = graph_max_nodes();
+
+ gf_res_reserve = std::make_unique<llm_graph_result>(max_nodes);
+ for (auto & res : gf_res_prev) {
+ res = std::make_unique<llm_graph_result>(max_nodes);
+ }
+ }
+
if (!hparams.vocab_only) {
// GPU backends
for (const auto & dev : model.devices) {
@@ -797,11 +806,14 @@ void llama_context::sched_reserve() {
LLAMA_LOG_DEBUG("%s: max_nodes = %zu\n", __func__, max_nodes);
+ gf_res_prev_active = nullptr;
+
+ gf_res_reserve->set_max_nodes(max_nodes);
+ gf_res_reserve->reset();
for (auto & res : gf_res_prev) {
- res.reset();
+ res->set_max_nodes(max_nodes);
+ res->reset();
}
- gf_res_reserve.reset(new llm_graph_result(max_nodes));
- gf_res_prev_active = nullptr;
sched_new({
/*.max_nodes =*/ max_nodes,
@@ -1047,9 +1059,7 @@ bool llama_context::memory_update(bool optimize) {
// reset the previous graph results to make sure that they won't be reused
// TODO: make mctx->apply() report if a graph reserve is needed, then reset graph results only if the memory module reset the scheduler
for (auto & res : gf_res_prev) {
- if (res) {
- res->reset();
- }
+ res->reset();
}
gf_res_prev_active = nullptr;
@@ -2947,11 +2957,7 @@ llm_graph_result * llama_context::get_gf_res_reserve() const {
}
llm_graph_result * llama_context::get_gf_res_prev() {
- auto & res = gf_res_prev[n_outputs > 0];
- if (!res) {
- res.reset(new llm_graph_result(gf_res_reserve->get_max_nodes()));
- }
- return res.get();
+ return gf_res_prev[n_outputs > 0].get();
}
// pack sampler outputs into as few sequences as possible before using sequences without samplers
@@ -3025,9 +3031,7 @@ ggml_cgraph * llama_context::graph_reserve(
// when the scheduler is reset, we cannot reuse old graphs, so we reset the previous graph results
for (auto & res : gf_res_prev) {
- if (res) {
- res->reset();
- }
+ res->reset();
}
gf_res_prev_active = nullptr;
diff --git a/src/llama-graph.cpp b/src/llama-graph.cpp
index 847a3e1ec..1174909bc 100644
--- a/src/llama-graph.cpp
+++ b/src/llama-graph.cpp
@@ -1413,6 +1413,10 @@ int64_t llm_graph_result::get_max_nodes() const {
return max_nodes;
}
+void llm_graph_result::set_max_nodes(int64_t max_nodes) {
+ this->max_nodes = max_nodes;
+}
+
void llm_graph_result::reset() {
t_inp_tokens = nullptr;
t_inp_embd = nullptr;
diff --git a/src/llama-graph.h b/src/llama-graph.h
index 8242ebb89..89370a97e 100644
--- a/src/llama-graph.h
+++ b/src/llama-graph.h
@@ -943,6 +943,8 @@ public:
int64_t get_max_nodes() const;
+ void set_max_nodes(int64_t max_nodes);
+
void reset();
void set_inputs(const llama_ubatch * ubatch);
@@ -996,9 +998,9 @@ public:
ggml_cgraph * gf;
+private:
int64_t max_nodes;
-private:
// keep a copy of the previous graph parameters
// we will use this to determine whether the graph can be reused by comparing them with the new parameters
// note: these are updated after constructing the new graph