Skip to content

Commit cc81675

Browse files
committed
feat: CUDA graph plan short-circuit for Phase 2 MoE (#huanglawsded)
- Add ggml_backend_graph_plan_{create,free,update,compute} for CUDA backend - cudaGraphExecUpdate dynamically patches addresses per token - Dedicated sched_phase2 isolates galloc from Phase 1 - REPLAY path bypasses scheduler compute_splits via graph_plan_compute - graphs_reused counter tracks cache hits on Token 2+
1 parent 76195d5 commit cc81675

7 files changed

Lines changed: 253 additions & 47 deletions

File tree

ggml/include/ggml-backend.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,9 @@ extern "C" {
9797

9898
GGML_API void ggml_backend_synchronize(ggml_backend_t backend);
9999

100-
GGML_API ggml_backend_graph_plan_t ggml_backend_graph_plan_create(ggml_backend_t backend, struct ggml_cgraph * cgraph);
100+
GGML_API ggml_backend_graph_plan_t ggml_backend_graph_plan_create(ggml_backend_t backend, struct ggml_cgraph * cgraph);
101101
GGML_API void ggml_backend_graph_plan_free (ggml_backend_t backend, ggml_backend_graph_plan_t plan);
102-
102+
GGML_API void ggml_backend_graph_plan_update(ggml_backend_t backend, ggml_backend_graph_plan_t plan, struct ggml_cgraph * cgraph);
103103
GGML_API enum ggml_status ggml_backend_graph_plan_compute (ggml_backend_t backend, ggml_backend_graph_plan_t plan);
104104
GGML_API enum ggml_status ggml_backend_graph_compute (ggml_backend_t backend, struct ggml_cgraph * cgraph);
105105
GGML_API enum ggml_status ggml_backend_graph_compute_async(ggml_backend_t backend, struct ggml_cgraph * cgraph);

ggml/src/ggml-backend.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,11 @@ enum ggml_status ggml_backend_graph_plan_compute(ggml_backend_t backend, ggml_ba
441441
return backend->iface.graph_plan_compute(backend, plan);
442442
}
443443

444+
void ggml_backend_graph_plan_update(ggml_backend_t backend, ggml_backend_graph_plan_t plan, struct ggml_cgraph * cgraph) {
445+
if (!backend || !backend->iface.graph_plan_update) return;
446+
backend->iface.graph_plan_update(backend, plan, cgraph);
447+
}
448+
444449
enum ggml_status ggml_backend_graph_compute(ggml_backend_t backend, struct ggml_cgraph * cgraph) {
445450
enum ggml_status err = ggml_backend_graph_compute_async(backend, cgraph);
446451
ggml_backend_synchronize(backend);

ggml/src/ggml-cuda/ggml-cuda.cu

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5091,6 +5091,89 @@ static void ggml_backend_cuda_graph_optimize(ggml_backend_t backend, ggml_cgraph
50915091
}
50925092
}
50935093

5094+
struct ggml_cuda_graph_plan {
5095+
cudaGraph_t graph = nullptr;
5096+
cudaGraphExec_t instance = nullptr;
5097+
};
5098+
5099+
static ggml_backend_graph_plan_t ggml_backend_cuda_graph_plan_create(ggml_backend_t backend, const struct ggml_cgraph * cgraph) {
5100+
ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *)backend->context;
5101+
ggml_cuda_set_device(cuda_ctx->device);
5102+
5103+
auto * plan = new ggml_cuda_graph_plan();
5104+
5105+
{
5106+
std::lock_guard<std::mutex> lock(ggml_cuda_lock);
5107+
ggml_cuda_lock_counter.fetch_add(1, std::memory_order_relaxed);
5108+
}
5109+
5110+
CUDA_CHECK(cudaStreamBeginCapture(cuda_ctx->stream(), cudaStreamCaptureModeRelaxed));
5111+
5112+
ggml_cuda_graph_evaluate_and_capture(cuda_ctx, const_cast<ggml_cgraph *>(cgraph), false, false, nullptr);
5113+
5114+
CUDA_CHECK(cudaStreamEndCapture(cuda_ctx->stream(), &plan->graph));
5115+
CUDA_CHECK(cudaGraphInstantiate(&plan->instance, plan->graph, nullptr, nullptr, 0));
5116+
5117+
return (ggml_backend_graph_plan_t)plan;
5118+
}
5119+
5120+
static void ggml_backend_cuda_graph_plan_free(ggml_backend_t backend, ggml_backend_graph_plan_t plan) {
5121+
(void)backend;
5122+
auto * p = (ggml_cuda_graph_plan *)plan;
5123+
if (!p) return;
5124+
if (p->instance) { CUDA_CHECK(cudaGraphExecDestroy(p->instance)); p->instance = nullptr; }
5125+
if (p->graph) { CUDA_CHECK(cudaGraphDestroy(p->graph)); p->graph = nullptr; }
5126+
delete p;
5127+
}
5128+
5129+
static enum ggml_status ggml_backend_cuda_graph_plan_compute(ggml_backend_t backend, ggml_backend_graph_plan_t plan) {
5130+
ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *)backend->context;
5131+
ggml_cuda_set_device(cuda_ctx->device);
5132+
auto * p = (ggml_cuda_graph_plan *)plan;
5133+
CUDA_CHECK(cudaGraphLaunch(p->instance, cuda_ctx->stream()));
5134+
return GGML_STATUS_SUCCESS;
5135+
}
5136+
5137+
static void ggml_backend_cuda_graph_plan_update(ggml_backend_t backend, ggml_backend_graph_plan_t plan, const struct ggml_cgraph * cgraph) {
5138+
ggml_backend_cuda_context * cuda_ctx = (ggml_backend_cuda_context *)backend->context;
5139+
ggml_cuda_set_device(cuda_ctx->device);
5140+
auto * p = (ggml_cuda_graph_plan *)plan;
5141+
if (!p || !p->instance) return;
5142+
5143+
cudaGraph_t new_graph = nullptr;
5144+
5145+
{
5146+
std::lock_guard<std::mutex> lock(ggml_cuda_lock);
5147+
ggml_cuda_lock_counter.fetch_add(1, std::memory_order_relaxed);
5148+
}
5149+
5150+
CUDA_CHECK(cudaStreamBeginCapture(cuda_ctx->stream(), cudaStreamCaptureModeRelaxed));
5151+
5152+
ggml_cuda_graph_evaluate_and_capture(cuda_ctx, const_cast<ggml_cgraph *>(cgraph), false, false, nullptr);
5153+
5154+
CUDA_CHECK(cudaStreamEndCapture(cuda_ctx->stream(), &new_graph));
5155+
5156+
#if CUDART_VERSION >= 12000
5157+
cudaGraphExecUpdateResultInfo result_info;
5158+
cudaError_t stat = cudaGraphExecUpdate(p->instance, new_graph, &result_info);
5159+
#else
5160+
cudaGraphNode_t errorNode;
5161+
cudaGraphExecUpdateResult result_info;
5162+
cudaError_t stat = cudaGraphExecUpdate(p->instance, new_graph, &errorNode, &result_info);
5163+
#endif
5164+
5165+
if (stat == cudaErrorGraphExecUpdateFailure) {
5166+
(void)cudaGetLastError();
5167+
CUDA_CHECK(cudaGraphExecDestroy(p->instance));
5168+
p->instance = nullptr;
5169+
CUDA_CHECK(cudaGraphInstantiate(&p->instance, new_graph, nullptr, nullptr, 0));
5170+
} else {
5171+
GGML_ASSERT(stat == cudaSuccess);
5172+
}
5173+
5174+
CUDA_CHECK(cudaGraphDestroy(new_graph));
5175+
}
5176+
50945177
static const ggml_backend_i ggml_backend_cuda_interface = {
50955178
/* .get_name = */ ggml_backend_cuda_get_name,
50965179
/* .free = */ ggml_backend_cuda_free,
@@ -5100,10 +5183,10 @@ static const ggml_backend_i ggml_backend_cuda_interface = {
51005183
/* .get_tensor_2d_async = */ ggml_backend_cuda_get_tensor_2d_async,
51015184
/* .cpy_tensor_async = */ ggml_backend_cuda_cpy_tensor_async,
51025185
/* .synchronize = */ ggml_backend_cuda_synchronize,
5103-
/* .graph_plan_create = */ NULL,
5104-
/* .graph_plan_free = */ NULL,
5105-
/* .graph_plan_update = */ NULL,
5106-
/* .graph_plan_compute = */ NULL,
5186+
/* .graph_plan_create = */ ggml_backend_cuda_graph_plan_create,
5187+
/* .graph_plan_free = */ ggml_backend_cuda_graph_plan_free,
5188+
/* .graph_plan_update = */ ggml_backend_cuda_graph_plan_update,
5189+
/* .graph_plan_compute = */ ggml_backend_cuda_graph_plan_compute,
51075190
/* .graph_compute = */ ggml_backend_cuda_graph_compute,
51085191
/* .event_record = */ ggml_backend_cuda_event_record,
51095192
/* .event_wait = */ ggml_backend_cuda_event_wait,

0 commit comments

Comments
 (0)