Skip to content

Commit 859507d

Browse files
committed
Offloading work
1 parent d215ace commit 859507d

16 files changed

Lines changed: 1826 additions & 54 deletions

common/arg.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2431,9 +2431,9 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
24312431
}
24322432
).set_env("LLAMA_ARG_N_GPU_LAYERS"));
24332433
add_opt(common_arg(
2434-
{"--weight-paging"}, "",
2434+
{"--weight-paging"},
24352435
"enable NVMe→VRAM demand paging for model weights (allows models larger than VRAM)",
2436-
[](common_params & params, const std::string & value) {
2436+
[](common_params & params) {
24372437
params.weight_paging_enabled = true;
24382438
}
24392439
).set_examples({LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_CLI}).set_env("LLAMA_ARG_WEIGHT_PAGING"));
@@ -2445,9 +2445,9 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
24452445
}
24462446
).set_examples({LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_CLI}).set_env("LLAMA_ARG_WEIGHT_PAGING_SLOTS"));
24472447
add_opt(common_arg(
2448-
{"--weight-paging-prefetch"}, "",
2448+
{"--weight-paging-prefetch"},
24492449
"enable async prefetch of next layer (default: enabled)",
2450-
[](common_params & params, const std::string & value) {
2450+
[](common_params & params) {
24512451
params.weight_paging_prefetch = true;
24522452
}
24532453
).set_examples({LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_CLI}).set_env("LLAMA_ARG_WEIGHT_PAGING_PREFETCH"));

common/common.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1343,7 +1343,7 @@ common_init_result_ptr common_init_from_params(common_params & params) {
13431343
common_set_adapter_lora(lctx, params.lora_adapters);
13441344
}
13451345

1346-
if (params.warmup) {
1346+
if (params.warmup && !params.weight_paging_enabled) {
13471347
LOG_WRN("%s: warming up the model with an empty run - please wait ... (--no-warmup to disable)\n", __func__);
13481348

13491349
llama_set_warmup(lctx, true);
@@ -1488,6 +1488,11 @@ struct llama_model_params common_model_params_to_llama(common_params & params) {
14881488
mparams.progress_callback_user_data = params.load_progress_callback_user_data;
14891489
mparams.no_alloc = params.no_alloc;
14901490

1491+
// Weight paging parameters
1492+
mparams.weight_paging_enabled = params.weight_paging_enabled;
1493+
mparams.weight_paging_slots = params.weight_paging_slots;
1494+
mparams.weight_paging_prefetch = params.weight_paging_prefetch;
1495+
14911496
return mparams;
14921497
}
14931498

include/llama.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,11 @@ extern "C" {
321321
bool use_extra_bufts; // use extra buffer types (used for weight repacking)
322322
bool no_host; // bypass host buffer allowing extra buffers to be used
323323
bool no_alloc; // only load metadata and simulate memory allocations
324+
325+
// Weight paging parameters (NVMe→VRAM demand paging)
326+
bool weight_paging_enabled; // enable NVMe→VRAM demand paging for model weights
327+
int32_t weight_paging_slots; // number of VRAM slots for weight paging (-1 = auto)
328+
bool weight_paging_prefetch; // enable async prefetch of next layer
324329
};
325330

326331
struct llama_sampler_seq_config {

plans/errors/command.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
Here is what I use to start the server:
2+
3+
llama-server-feature \
4+
--model ~/models/MiniMax-M2.7-UD-IQ3_S-00001-of-00003.gguf \
5+
-ngl 999 \
6+
--device ROCm0 \
7+
--ctx-size 196608 \
8+
--cache-type-k turbo4 \
9+
--cache-type-v turbo4 \
10+
--flash-attn on \
11+
--metrics \
12+
--port 8080 \
13+
--host 0.0.0.0 \
14+
--no-mmap \
15+
--kv-tiered 12.5,50,37.5 \
16+
--tier-ssd-path ~/kv-cold \
17+
--tier-eviction-policy 3 \
18+
--parallel 1 \
19+
--kv-semantic-index ~/models/bge-small-en-v1.5-q8_0.gguf \
20+
--kv-semantic-threshold 0.65 \
21+
--kv-semantic-topk 5 \
22+
--alias default \
23+
--direct-io \
24+
--kv-warm-device 1 \
25+
--weight-paging \
26+
--fit off \
27+
--weight-paging-slots 8 \
28+
--jinja

plans/errors/output.md

Lines changed: 332 additions & 0 deletions
Large diffs are not rendered by default.

plans/pool-allocation-switch.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
Phase 1 — Switch pool allocation + add pinned staging buffer
3+
4+
In llama-weight-pager.h, add a void* pinned_staging member to llama_weight_pager. Update the destructor to also call hipFree(pool.base) and
5+
hipHostFree(pinned_staging).
6+
7+
In llama-weight-pager.cpp, init_pool: replace hipExtMallocWithFlags(&pool.base, size, hipDeviceMallocFinegrained) and its fallback with a
8+
single hipMalloc(&pool.base, size). After successful pool allocation, allocate the pinned staging buffer: hipHostMalloc(&pinned_staging,
9+
slot_size, hipHostMallocDefault). Return false if either allocation fails.
10+
11+
Remove _mm_sfence() and the <immintrin.h> include — no longer needed.
12+
13+
---
14+
Phase 2 — Rewrite page_in to use pinned staging + hipMemcpy
15+
16+
In page_in in llama-weight-pager.cpp, replace the pread-directly-to-VRAM path with:
17+
1. pread(fd, pinned_staging, size, offset) — read from NVMe into pinned host buffer
18+
2. Check return value as before
19+
3. hipMemcpy(dst, pinned_staging, size, hipMemcpyHostToDevice) — DMA from pinned RAM to VRAM slot
20+
4. Keep all existing diagnostic logging, just update the log message to note the two-step path
21+
22+
This phase should get end-to-end inference working. Rebuild and test before moving to Phase 3.
23+
24+
---
25+
Phase 3 — Async pipeline with N+1 prefetch
26+
27+
Add a hipStream_t transfer_stream member to llama_weight_pager, created in init_pool with hipStreamCreate and destroyed in the destructor.
28+
29+
Change hipMemcpy in page_in to hipMemcpyAsync(..., transfer_stream) followed by hipStreamSynchronize(transfer_stream) for the synchronous
30+
case.
31+
32+
Then wire the existing io_uring N+1 prefetch (already in the eval callback's Phase 4 block) to also kick off the GPU transfer leg: when
33+
complete_prefetch finishes the NVMe read into the pinned buffer, immediately issue hipMemcpyAsync to the pre-reserved next slot on
34+
transfer_stream. This way the GPU transfer overlaps with GPU compute on the current tensor, and by the time the eval callback needs N+1,
35+
it's already in VRAM.

0 commit comments

Comments
 (0)