Repository navigation
llama, ggml : phase-aware and live-context workspace (port of GS #36, #40, #88) - #19
Merged
Merged
Conversation
Port of the ggml part of the phase-aware workspace of GenerelSchwerz/llama.cpp (#36 and GenerelSchwerz#88, by Anbeeld): - ggml_gallocr_set_resizable(galloc, owner): a resizable gallocr takes the size of its last reserve and shrinks on request (ggml_gallocr_request_shrink). With an owner, a second gallocr borrows the buffers of the first: the shared buffers have the larger of the two requirements and shrink after both reserved again. A generation counter tells when graph addresses became invalid (ggml_gallocr_get_resizable_state). - the same on the scheduler: ggml_backend_sched_set_resizable, _get_buffer_state, _request_buffer_shrink - meta buffers: the borrower uses an alias over the same simple buffers with its own tensor mapping (ggml_backend_meta_buffer_alias), since a meta buffer maps the tensors of one graph at a time - ggml_backend_trim_pools(backend) and ggml_backend_trim_pools_t: return the memory that the memory pools of a backend keep (of all simple backends of a meta backend) - tests/test-alloc-resizable.cpp: the allocator tests of the original, with its dummy backend Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ggml_backend_trim_pools for CUDA: unmaps the memory of the VMM pools that hold no allocation, the address range stays reserved and is mapped again on the next allocation. The captured CUDA graphs use addresses in the pools, so they are dropped and captured again. Port of the pool trim of GenerelSchwerz/llama.cpp #40 (by Anbeeld), with the CUDA graphs dropped and only whole idle pools unmapped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port of the phase-aware workspace (#36) and the live-context workspace (#40) of GenerelSchwerz/llama.cpp (by Anbeeld), with the lanes of --split-overlap. Both are off by default. --phase-aware-workspace (llama_context_params.phase_aware_workspace): - reserves only for the generation batches (n_outputs_max, or one token per sequence) while there are no larger ones - an MTP draft context computes in the compute buffers of lane 0 of its target (llama_attach_shared_workspace, called by common_speculative_init_result); each context waits until the other one finished with the buffers before it allocates, sets inputs or computes. Lane 1 keeps its own buffers. --live-context-workspace (llama_context_params.live_context_workspace): - reserves the attention for the KV extent of the batch (llama_memory_i::init_reserve, get_attn_reserve_capacity, llama_memory_context_i::get_attn_reserve_n_kv) in power-of-two steps from 1/8 of the cache: each step allocates the buffers again (~160 ms on two GPUs), a 256-cell start cost 8% of a 10k prompt - KV cache, ISWA, hybrid, hybrid ISWA and hybrid indexer memory (qwen4exp: the indexer cache and its pools follow the attention cache) Both: a smaller reservation only after 64 calls in a row that need less (a prompt after a short generation does not allocate twice), larger at once; the server returns the memory of the device pools when no slot is busy (llama_trim_transient_memory). Lane 1 is reserved again only for batches of at least 64 tokens. docs/compute-workspace.md. Qwen3.8-27B + MTP, two GPUs, --split-overlap -ub 256, 2 slots of 131072: VRAM peak -106 MiB per GPU at 95k with phase-aware, -212 MiB at 1k with both; prompt processing -1 to -2%, outputs identical. Tests: test-llama-archs configs "<GPU> -paw -lcw", "Meta -paw -lcw" and "Meta -so -paw -lcw". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… growth failure Review fixes for the workspace port: - the scheduler that the workspace options keep has the graph size it was created with; backend samplers, LoRA adapters or training set later make the graph larger and the reserve aborted on the hash set size. The context now creates a new scheduler when graph_max_nodes() exceeds it, and a borrower whose owner did that borrows the new buffers at its next reserve (it keeps the old ones until then) - llama_attach_shared_workspace: a borrower that needs more than its owner and fails to get it makes the owner fail as well, documented; the MTP draft never drives the growth Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # common/arg.cpp # ggml/src/ggml-cuda/ggml-cuda.cu # tests/test-llama-archs.cpp
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ports the phase-aware workspace (#36, GenerelSchwerz#88) and the live-context workspace (#40) of GenerelSchwerz/llama.cpp, by Anbeeld, onto main with the lanes of
--split-overlap. Both options are off by default and leave the outputs unchanged:--phase-aware-workspacereserves the compute buffers only for generation batches until a prompt comes. An MTP draft context computes in the compute buffers of its target instead of its own.--live-context-workspacesizes the attention part of the compute buffers for the used part of the KV cache instead of the whole cache.On the 27B + MTP production setup, sharing with the draft lowers the VRAM peak by 106 MiB per GPU at every context length. At short context both options together save 212 MiB. Prompt processing is 1–2% slower. Details:
docs/compute-workspace.md.Change
ggml (
8d9e11b0e), from GSggml_gallocr_set_resizable(galloc, owner).ggml_backend_meta_buffer_alias).ggml_backend_trim_pools: a meta-aware pool trim.tests/test-alloc-resizable.cpp: the original allocator tests, with their dummy backend. 25 pass.CUDA (
ca2a953bb)llama (
3973fec5b)n_ubatch;workspace_acquire): before a context allocates, sets inputs, computes or reserves, it waits for the other one if that one has graphs in flight.synchronize()covers both lanes.qwen4exp.cpp.llama_attach_shared_workspace,llama_contexts_share_workspaceandllama_trim_transient_memoryinllama-ext.h.Results
Qwen3.8-27B UD-Q4_K_S + MTP, RTX 4070 + RTX 3060,
-sm tensor -ts 0.625,0.375 -as 1,3 --split-overlap -ub 256, 2 slots of 131072 tokens, greedy:--phase-aware-workspaceReview (reviewer-xhigh)
59aca16d9): the kept scheduler had the hash-set size it was created with. Backend samplers, LoRA adapters or training set after creation made the graph larger, and the next reserve aborted. The context now creates a new scheduler whengraph_max_nodes()exceeds it. A borrower whose owner did that keeps the old buffers until its next reserve, then borrows the new ones. Verified with the reviewer's reproducer (samplers set after the first decode: abort before, now fine), and with an owner that grows while attached: logits hash equal to the unattached run, llama and qwen35.llama_attach_shared_workspacedocuments it.Merge with main
main(PR 18,--allreduce) is merged into the branch. The README feature list is now a table, with a row for these options.Tests
<GPU> -paw -lcw,Meta -paw -lcwandMeta -so -paw -lcw: everything passes with seed 42. maion-coder MoE fails with some seeds on main as well.🤖 Generated with Claude Code