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.
2628bool 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
337334void 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
0 commit comments