Skip to content

Commit 786f501

Browse files
kmbandyclaude
andcommitted
fix: tiered KV cache warm GPU tier, weight pager stability, and hybrid model support
- Fix warm GPU tier OOM: skip RAM staging buffers when warm_device >= 0 (6900XT); previously allocated both RAM and GPU warm buffers, wasting ~8GB RAM per session - Fix k_bytes/v_bytes computation: use nb[1] (row stride) instead of ne[0]*element_size which returns block size for quantized types like turbo4, causing 557056 MiB warm GPU misreads and silent hipMalloc failures - Fix hybrid model KV wiring: handle llama_memory_hybrid and llama_memory_hybrid_iswa in init_slot so Qwen3-27B and similar hybrid models wire attention KV layers into the tiered cache instead of metadata-only mode - Add tier logging: warm GPU (ROCm device + MiB), cold SSD (slots + path) on init - Weight pager: use ggml_backend_buft_alloc_buffer for pool allocation so tensor->buffer is valid on callback; set tensor->buffer = pool.ggml_buf on page-in - Weight pager: disable async prefetch default (io_uring page-index tracking broken); move fd dup outside prefetch gate so pread always has valid fds - Weight pager: clear O_DIRECT on dup fds; zero padding bytes after hipMemcpy - hipGraph: disable via setenv + remove static from disable_cuda_graphs_due_to_env Tested on AMD Radeon AI PRO R9700 (gfx1201, 32GB) + RX 6900XT (16GB warm tier) with Qwen3.6-27B-Q6_K (tiered KV), Qwen3.6-35B-A3B, Qwen3.5-REAP-97B, and MiniMax-M2.7-229B-IQ3_S (NVMe demand weight paging, 8-slot VRAM pool). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 859507d commit 786f501

9 files changed

Lines changed: 122 additions & 74 deletions

File tree

common/common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ struct common_params {
536536
// weight paging parameters
537537
bool weight_paging_enabled = false; // enable NVMe→VRAM demand paging for model weights
538538
int32_t weight_paging_slots = -1; // number of VRAM slots for weight paging (-1 = auto)
539-
bool weight_paging_prefetch = true; // enable async prefetch of next layer
539+
bool weight_paging_prefetch = false; // enable async prefetch of next layer
540540

541541
bool single_turn = false; // single turn chat conversation
542542

ggml/src/ggml-cuda/common.cuh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1193,7 +1193,7 @@ struct ggml_cuda_graph {
11931193
std::vector<node_properties> node_props;
11941194

11951195
bool is_enabled() const {
1196-
static const bool disable_cuda_graphs_due_to_env = (getenv("GGML_CUDA_DISABLE_GRAPHS") != nullptr);
1196+
const bool disable_cuda_graphs_due_to_env = (getenv("GGML_CUDA_DISABLE_GRAPHS") != nullptr);
11971197
return !(disable_due_to_gpu_arch || disable_cuda_graphs_due_to_env);
11981198
}
11991199
#endif

src/llama-context.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "llama.h"
1414

1515
#include <cinttypes>
16+
#include <cstdlib>
1617
#include <cmath>
1718
#include <cstring>
1819
#include <limits>
@@ -1201,8 +1202,9 @@ llm_graph_result * llama_context::process_ubatch(const llama_ubatch & ubatch, ll
12011202

12021203
// Use weight pager callback if model has weight_pager enabled
12031204
if (model.weight_pager) {
1204-
// The weight pager callback handles paging weights from NVMe to VRAM
1205-
// It takes precedence over the user-provided callback for weight tensors
1205+
// hipGraph bakes tensor->data pointers at capture time; our eval callback
1206+
// changes tensor->data dynamically, so graphs must be disabled.
1207+
setenv("GGML_CUDA_DISABLE_GRAPHS", "1", 1);
12061208
ggml_backend_sched_set_eval_callback(sched.get(), weight_pager_eval_cb, model.weight_pager.get());
12071209
} else {
12081210
ggml_backend_sched_set_eval_callback(sched.get(), cparams.cb_eval, cparams.cb_eval_user_data);

src/llama-kv-cache-tiered.cpp

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,10 @@ bool llama_kv_cache_tiered::init() {
336336
LLAMA_LOG_INFO("%s: warm tier: %u slots reserved (buffers wired after KV layers available)\n",
337337
__func__, config.warm_capacity());
338338
}
339+
if (config.cold_capacity() > 0) {
340+
LLAMA_LOG_INFO("%s: cold tier: %u slots reserved (SSD path: %s)\n",
341+
__func__, config.cold_capacity(), ssd_path.c_str());
342+
}
339343

340344
return true;
341345
}
@@ -651,8 +655,12 @@ void llama_kv_cache_tiered::set_kv_layers_from_cache(llama_kv_cache * cache) {
651655
tl.v = cache->get_layer_v_raw(il);
652656
tl.v_trans = vtrans;
653657
tl.kv_size = kvsz;
654-
if (tl.k) tl.k_bytes = (size_t)tl.k->ne[0] * ggml_element_size(tl.k);
655-
if (tl.v) tl.v_bytes = (size_t)tl.v->ne[0] * ggml_element_size(tl.v);
658+
// Use nb[1] (the actual row stride) for per-token byte size so that
659+
// block-quantized types (turbo4, Q4_K, etc.) are sized correctly.
660+
// ggml_element_size returns the block size, not bytes-per-element, so
661+
// ne[0]*element_size is wildly wrong for quantized caches.
662+
if (tl.k) tl.k_bytes = tl.k->nb[1];
663+
if (tl.v) tl.v_bytes = tl.v->nb[1];
656664
}
657665

658666
// (Re)allocate per-layer warm buffers using already-reserved slot count
@@ -666,8 +674,18 @@ void llama_kv_cache_tiered::set_kv_layers_from_cache(llama_kv_cache * cache) {
666674
delete[] tl.warm_k;
667675
delete[] tl.warm_v;
668676
tl.warm_k = tl.warm_v = nullptr;
677+
// Skip RAM staging buffers when a GPU warm device is configured — the
678+
// GPU VRAM path (warm_k_dev/warm_v_dev) is used instead, so allocating
679+
// n_warm * kv_bytes of RAM here would just trigger OOM for large contexts.
680+
#ifndef GGML_USE_HIP
669681
if (n_warm > 0 && tl.k_bytes > 0) tl.warm_k = new uint8_t[n_warm * tl.k_bytes]();
670682
if (n_warm > 0 && tl.v_bytes > 0) tl.warm_v = new uint8_t[n_warm * tl.v_bytes]();
683+
#else
684+
if (config.warm_device < 0) {
685+
if (n_warm > 0 && tl.k_bytes > 0) tl.warm_k = new uint8_t[n_warm * tl.k_bytes]();
686+
if (n_warm > 0 && tl.v_bytes > 0) tl.warm_v = new uint8_t[n_warm * tl.v_bytes]();
687+
}
688+
#endif
671689

672690
#ifdef GGML_USE_HIP
673691
if (config.warm_device >= 0 && n_warm > 0) {
@@ -686,8 +704,24 @@ void llama_kv_cache_tiered::set_kv_layers_from_cache(llama_kv_cache * cache) {
686704
total_mb += (tl.k_bytes + tl.v_bytes) * n_warm;
687705
total_mb /= (1024*1024);
688706

689-
LLAMA_LOG_INFO("%s: wired %u KV layers (v_trans=%d, kv_size=%lld), warm RAM: ~%zu MB (%u slots x %u layers)\n",
707+
#ifdef GGML_USE_HIP
708+
if (config.warm_device >= 0) {
709+
LLAMA_LOG_INFO("%s: wired %u KV layers (v_trans=%d, kv_size=%lld), warm GPU: ~%zu MiB (%u slots x %u layers)\n",
710+
__func__, n, (int)vtrans, (long long)kvsz, total_mb, n_warm, n);
711+
} else {
712+
LLAMA_LOG_INFO("%s: wired %u KV layers (v_trans=%d, kv_size=%lld), warm RAM: ~%zu MiB (%u slots x %u layers)\n",
713+
__func__, n, (int)vtrans, (long long)kvsz, total_mb, n_warm, n);
714+
}
715+
#else
716+
LLAMA_LOG_INFO("%s: wired %u KV layers (v_trans=%d, kv_size=%lld), warm RAM: ~%zu MiB (%u slots x %u layers)\n",
690717
__func__, n, (int)vtrans, (long long)kvsz, total_mb, n_warm, n);
718+
#endif
719+
#ifdef GGML_USE_HIP
720+
if (config.warm_device >= 0 && n_warm > 0 && !kv_layers.empty() && kv_layers[0].warm_k_dev) {
721+
LLAMA_LOG_INFO("llama_kv_cache_tiered: ROCm%d KV warm buffer size = %6.2f MiB (%u slots x %u layers)\n",
722+
config.warm_device, (float)total_mb, n_warm, n);
723+
}
724+
#endif
691725
}
692726

693727
bool llama_kv_cache_tiered::migrate_tokens(const std::vector<llama_pos>& positions,

src/llama-model.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9146,7 +9146,7 @@ llama_model_params llama_model_default_params() {
91469146
/*.no_alloc =*/ false,
91479147
/*.weight_paging_enabled =*/ false,
91489148
/*.weight_paging_slots =*/ -1,
9149-
/*.weight_paging_prefetch =*/ true,
9149+
/*.weight_paging_prefetch =*/ false,
91509150
};
91519151

91529152
return result;

src/llama-weight-pager.cpp

Lines changed: 33 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#include "llama-weight-pager.h"
2+
#include "ggml-backend.h"
3+
#include "ggml-cuda.h"
24
#include "ggml.h"
35
#include "llama-impl.h"
46

@@ -24,21 +26,17 @@ static int s_last_processed_page = -1;
2426
/// Phase 3: Ensures weight tensors are paged in to VRAM before use.
2527
/// Phase 4: Completes in-flight prefetches and submits prefetch for next layer.
2628
bool weight_pager_eval_cb(struct ggml_tensor * t, bool ask, void * user_data) {
27-
if (ask) {
28-
return true; // yes, we want the callback
29+
// ask=true fires before execution — load weights here so they are ready.
30+
// ask=false fires after execution — nothing to do, just return.
31+
if (!ask) {
32+
return true;
2933
}
3034

3135
auto * pager = (llama_weight_pager *) user_data;
3236
if (!pager) {
3337
return true;
3438
}
3539

36-
// DIAGNOSTIC: Log callback invocation
37-
LLAMA_LOG_INFO("weight_pager_eval_cb: tensor=%s ask=%s\n",
38-
ggml_get_name(t), ask ? "true" : "false");
39-
LLAMA_LOG_INFO("weight_pager_eval_cb: pager=%p pool.base=%p pool.n_slots=%d\n",
40-
pager, pager->pool.base, pager->pool.n_slots);
41-
4240
// Collect page indices for all weight tensors in this tensor's sources.
4341
// Also detect view tensors of tracked weights (ggml_gallocr_alloc_graph initialises
4442
// their data to (char*)1 + view_offs -- garbage -- so we must overwrite it
@@ -49,7 +47,6 @@ bool weight_pager_eval_cb(struct ggml_tensor * t, bool ask, void * user_data) {
4947
if (!src) {
5048
break;
5149
}
52-
5350
// Direct weight tensor match
5451
int page_idx = pager->find_page(ggml_get_name(src));
5552

@@ -96,13 +93,15 @@ bool weight_pager_eval_cb(struct ggml_tensor * t, bool ask, void * user_data) {
9693
}
9794
// Direct weight tensor
9895
if (strcmp(ggml_get_name(src), page.tensor_name.c_str()) == 0) {
99-
src->data = vram;
96+
src->data = vram;
97+
src->buffer = pager->pool.ggml_buf;
10098
}
10199
// View of this weight: gallocr sets data=(char*)sentinel+view_offs;
102100
// overwrite with the real paged-in slot address + offset.
103101
else if (src->view_src != nullptr &&
104102
strcmp(ggml_get_name(src->view_src), page.tensor_name.c_str()) == 0) {
105-
src->data = (char *)vram + src->view_offs;
103+
src->data = (char *)vram + src->view_offs;
104+
src->buffer = pager->pool.ggml_buf;
106105
}
107106
}
108107
}
@@ -180,8 +179,10 @@ llama_weight_pager::~llama_weight_pager() {
180179
if (pool.pinned_staging != nullptr) {
181180
hipHostFree(pool.pinned_staging);
182181
}
183-
if (pool.base != nullptr) {
184-
hipFree(pool.base);
182+
if (pool.ggml_buf != nullptr) {
183+
ggml_backend_buffer_free(pool.ggml_buf);
184+
pool.ggml_buf = nullptr;
185+
pool.base = nullptr;
185186
}
186187
if (transfer_stream != nullptr) {
187188
hipStreamDestroy((hipStream_t)transfer_stream);
@@ -203,13 +204,18 @@ bool llama_weight_pager::init_pool(size_t slot_size, int n_slots) {
203204
LLAMA_LOG_INFO("init_pool: allocating %d slots of %zu bytes each\n", n_slots, slot_size);
204205

205206
#if defined(GGML_USE_CUDA) && defined(__HIP_PLATFORM_AMD__)
206-
// Allocate the VRAM pool using hipMalloc
207-
hipError_t err = hipMalloc(&pool.base, (size_t)n_slots * slot_size);
208-
if (err != hipSuccess) {
209-
LLAMA_LOG_WARN("llama_weight_pager: hipMalloc failed: %s\n", hipGetErrorString(err));
207+
// Allocate the VRAM pool as a proper ggml CUDA buffer so that
208+
// tensor->buffer can be set to a valid CUDA buffer type, which
209+
// ggml_cuda_mul_mat checks on every call.
210+
ggml_backend_buffer_type_t cuda_buft = ggml_backend_cuda_buffer_type(0);
211+
pool.ggml_buf = ggml_backend_buft_alloc_buffer(cuda_buft, (size_t)n_slots * slot_size);
212+
if (!pool.ggml_buf) {
213+
LLAMA_LOG_WARN("llama_weight_pager: ggml_backend_buft_alloc_buffer failed\n");
210214
pool.base = nullptr;
211215
return false;
212216
}
217+
pool.base = ggml_backend_buffer_get_base(pool.ggml_buf);
218+
hipError_t err = hipSuccess; // needed for subsequent hipHostMalloc / hipStreamCreate checks
213219

214220
// Allocate the pinned host staging buffer
215221
err = hipHostMalloc(&pool.pinned_staging, slot_size, hipHostMallocDefault);
@@ -254,10 +260,6 @@ void* llama_weight_pager::ensure(const std::string & name) {
254260

255261
llama_weight_page & page = pages[page_idx];
256262

257-
// DIAGNOSTIC: Log ensure call
258-
LLAMA_LOG_INFO("ensure: tensor=%s page_idx=%d slot_idx=%d vram_ptr=%p\n",
259-
name.c_str(), page_idx, page.slot_idx, page.vram_ptr);
260-
261263
// If already in VRAM, update tick and return pointer
262264
if (page.slot_idx >= 0 && page.vram_ptr != nullptr) {
263265
// Update LRU tick for this page
@@ -269,13 +271,8 @@ void* llama_weight_pager::ensure(const std::string & name) {
269271
return page.vram_ptr;
270272
}
271273

272-
// Not in VRAM - need to page in
273-
// Phase 1 stub: page_in() returns nullptr, so we return nullptr
274-
// In Phase 2, this will actually load from NVMe
275-
LLAMA_LOG_INFO("ensure: calling page_in for tensor %s\n", name.c_str());
274+
// Not in VRAM — page in from NVMe.
276275
page_in(page);
277-
LLAMA_LOG_INFO("ensure: page_in returned, page.slot_idx=%d page.vram_ptr=%p\n",
278-
page.slot_idx, page.vram_ptr);
279276

280277
if (page.vram_ptr != nullptr) {
281278
page.last_used = ++tick;
@@ -335,9 +332,6 @@ int llama_weight_pager::find_page(const std::string & name) const {
335332
}
336333

337334
void llama_weight_pager::page_in(llama_weight_page & page) {
338-
LLAMA_LOG_INFO("page_in: loading tensor %s (file_idx=%u, offset=%zu, size=%zu)\n",
339-
page.tensor_name.c_str(), (unsigned)page.file_idx, page.file_offset, page.size);
340-
// Phase 3: two-step path with async stream - NVMe → pinned staging → VRAM
341335
// Check if we have a valid pool and file descriptor
342336
if (!pool.is_valid() || pool.pinned_staging == nullptr || fds.empty() || fds[0] < 0) {
343337
LLAMA_LOG_WARN("page_in: no valid pool or fd (pool.valid=%s pool.pinned_staging=%p fds.empty=%s fds[0]=%d)\n",
@@ -350,10 +344,7 @@ void llama_weight_pager::page_in(llama_weight_page & page) {
350344

351345
// Step 1: Read from NVMe into pinned host staging buffer
352346
int read_fd = (page.file_idx < (uint16_t)fds.size()) ? fds[page.file_idx] : (fds.empty() ? -1 : fds[0]);
353-
LLAMA_LOG_INFO("page_in: pread fd=%d pinned_staging=%p size=%zu offset=%zu\n",
354-
read_fd, pool.pinned_staging, page.size, page.file_offset);
355347
ssize_t n = pread(read_fd, pool.pinned_staging, page.size, page.file_offset);
356-
LLAMA_LOG_INFO("page_in: pread returned %zd (errno=%d)\n", n, errno);
357348
if (n != (ssize_t)page.size) {
358349
LLAMA_LOG_WARN("page_in: failed to read tensor (read %zd/%zu bytes)\n", n, page.size);
359350
return;
@@ -364,24 +355,21 @@ void llama_weight_pager::page_in(llama_weight_page & page) {
364355
pager_invalidate_slot(this, slot);
365356
void * dst = pool.slot_ptr(slot);
366357

367-
// Step 3: Copy from pinned staging to VRAM slot using hipMemcpyAsync on transfer_stream
358+
// Step 3: Synchronous copy: pinned staging -> VRAM.
368359
#if defined(GGML_USE_CUDA) && defined(__HIP_PLATFORM_AMD__)
369-
LLAMA_LOG_INFO("page_in: hipMemcpyAsync dst=%p pinned_staging=%p size=%zu stream=%p\n",
370-
dst, pool.pinned_staging, page.size, transfer_stream);
371-
hipError_t err = hipMemcpyAsync(dst, pool.pinned_staging, page.size, hipMemcpyHostToDevice, (hipStream_t)transfer_stream);
360+
LLAMA_LOG_INFO("weight_pager: loading %s (%.1f MiB) -> slot %d\n",
361+
page.tensor_name.c_str(), page.size / 1048576.0f, slot);
362+
hipError_t err = hipMemcpy(dst, pool.pinned_staging, page.size, hipMemcpyHostToDevice);
372363
if (err != hipSuccess) {
373-
LLAMA_LOG_WARN("page_in: hipMemcpyAsync failed: %s\n", hipGetErrorString(err));
364+
LLAMA_LOG_WARN("page_in: hipMemcpy failed: %s\n", hipGetErrorString(err));
374365
pool.free_slot(slot);
375366
return;
376367
}
377-
378-
// Synchronize to ensure transfer completes before returning (synchronous case)
379-
err = hipStreamSynchronize((hipStream_t)transfer_stream);
380-
if (err != hipSuccess) {
381-
LLAMA_LOG_WARN("page_in: hipStreamSynchronize failed: %s\n", hipGetErrorString(err));
382-
pool.free_slot(slot);
383-
return;
368+
// Zero padding bytes so quantized kernel reads past tensor data are safe.
369+
if (pool.slot_size > page.size) {
370+
hipMemset((char*)dst + page.size, 0, pool.slot_size - page.size);
384371
}
372+
385373
#endif
386374

387375
// Update page state

src/llama-weight-pager.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <unistd.h>
88

99
struct ggml_tensor;
10+
struct ggml_backend_buffer;
11+
typedef struct ggml_backend_buffer * ggml_backend_buffer_t;
1012

1113
#ifdef LLAMA_HAVE_IO_URING
1214
struct io_uring;
@@ -37,14 +39,15 @@ struct llama_weight_page {
3739

3840
/// VRAM slot pool for managing contiguous weight allocations
3941
struct llama_vram_pool {
40-
void *base; // hipMalloc'd contiguous VRAM block
42+
void *base; // device base pointer for the pool
43+
ggml_backend_buffer_t ggml_buf; // ggml CUDA buffer wrapping the pool
4144
void *pinned_staging; // pinned host staging buffer
4245
size_t slot_size; // bytes per slot (= max single-layer weight size)
4346
int n_slots; // total slots = floor(pool_bytes / slot_size)
4447
std::vector<bool> used;
4548
std::vector<uint64_t> lru_tick; // per-slot last-used tick
4649

47-
llama_vram_pool() : base(nullptr), pinned_staging(nullptr), slot_size(0), n_slots(0) {}
50+
llama_vram_pool() : base(nullptr), ggml_buf(nullptr), pinned_staging(nullptr), slot_size(0), n_slots(0) {}
4851

4952
/// Allocate a slot, evicting LRU if necessary. Returns slot index.
5053
int alloc_slot();
@@ -73,7 +76,7 @@ struct llama_weight_pager {
7376
// Async io_uring reader for prefetch
7477
struct llama_io_uring * io_reader = nullptr;
7578
std::unordered_map<int, prefetch_req> in_flight; // page_idx -> in-flight request
76-
bool async_prefetch = true; // enabled by default when io_uring available
79+
bool async_prefetch = false; // TODO: re-enable after fixing page-index tracking in complete_prefetch
7780
#endif
7881

7982
// Async GPU transfer stream for overlapping data transfer with compute

src/llama.cpp

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "llama.h"
2+
#include <fcntl.h>
23

34
#include "llama-impl.h"
45

@@ -145,24 +146,32 @@ static bool init_weight_pager(llama_model & model, llama_model_loader & ml, cons
145146
__func__, model.weight_pager->weight_tensor_ptrs.size());
146147
}
147148

149+
// Always dup model file descriptors — page_in uses pread regardless of prefetch.
150+
// Clear O_DIRECT on the dup'd fds: GGUF tensor offsets are not sector-aligned,
151+
// so O_DIRECT would silently read from a rounded-down offset on some filesystems.
152+
if (!ml.files.empty()) {
153+
for (const auto & f : ml.files) {
154+
int fd = dup(f->file_id());
155+
#ifdef O_DIRECT
156+
int fl = fcntl(fd, F_GETFL);
157+
if (fl != -1 && (fl & O_DIRECT)) fcntl(fd, F_SETFL, fl & ~O_DIRECT);
158+
#endif
159+
model.weight_pager->fds.push_back(fd);
160+
}
161+
}
162+
148163
#ifdef LLAMA_HAVE_IO_URING
149-
// Enable async prefetch if requested and io_uring is available
164+
// Enable async prefetch via io_uring only when explicitly requested.
150165
model.weight_pager->async_prefetch = params.weight_paging_prefetch;
151166

152-
if (params.weight_paging_prefetch) {
153-
// Open the model file for io_uring reads
154-
if (!ml.files.empty()) {
155-
for (const auto & f : ml.files) {
156-
model.weight_pager->fds.push_back(dup(f->file_id()));
157-
}
158-
int fd = model.weight_pager->fds.empty() ? -1 : model.weight_pager->fds[0];
159-
if (fd >= 0) {
160-
if (model.weight_pager->init_io_uring(64)) {
161-
LLAMA_LOG_INFO("%s: io_uring initialized for async prefetch\n", __func__);
162-
} else {
163-
LLAMA_LOG_WARN("%s: failed to initialize io_uring, disabling async prefetch\n", __func__);
164-
model.weight_pager->async_prefetch = false;
165-
}
167+
if (params.weight_paging_prefetch && !model.weight_pager->fds.empty()) {
168+
int fd = model.weight_pager->fds[0];
169+
if (fd >= 0) {
170+
if (model.weight_pager->init_io_uring(64)) {
171+
LLAMA_LOG_INFO("%s: io_uring initialized for async prefetch\n", __func__);
172+
} else {
173+
LLAMA_LOG_WARN("%s: failed to initialize io_uring, disabling async prefetch\n", __func__);
174+
model.weight_pager->async_prefetch = false;
166175
}
167176
}
168177
}

0 commit comments

Comments
 (0)