Commit 3e41ae69d for llama.cpp

commit 3e41ae69dba547d27d37a9bdad8b087a85c792c1
Author: Yuri Khrustalev <ykhrustalev@users.noreply.github.com>
Date:   Sat Nov 14 17:37:46 2026 -0500

    llama : allocate the tensor staging buffer from the CPU buffer type (#31438)

    * llama : allocate the tensor staging buffer from the CPU buffer type

    * llama : drop the staging buffer test, reword the comment

diff --git a/src/llama-model-loader.cpp b/src/llama-model-loader.cpp
index 2cbee61d4..548ade101 100644
--- a/src/llama-model-loader.cpp
+++ b/src/llama-model-loader.cpp
@@ -1776,7 +1776,8 @@ bool llama_model_loader::load_all_data(
     }

     // staging buffer for non-host buffers without async uploads, reused because a fresh allocation per tensor page faults on every load
-    std::vector<no_init<uint8_t>> read_buf;
+    // allocated from the CPU buffer type, which uses vm_allocate on Apple platforms, so freeing it returns its pages to the OS right away
+    ggml_backend_buffer_ptr read_buf;
     for (struct ggml_tensor * cur : tensors) {
         const auto * weight = get_weight(ggml_get_name(cur));
         if (weight == nullptr) {
@@ -1904,12 +1905,16 @@ bool llama_model_loader::load_all_data(
                     const size_t buf_size       = read_size + align - 1;

                     // tensors come biggest-first: shrink the buffer when it gets too large, so peak memory stays close to one tensor
-                    if (read_buf.size() < buf_size || read_buf.size() > 2*buf_size) {
-                        // free the old buffer first, `read_buf = {}` would keep its capacity
-                        read_buf = std::vector<no_init<uint8_t>>();
-                        read_buf.resize(buf_size);
+                    const size_t read_buf_size = read_buf ? ggml_backend_buffer_get_size(read_buf.get()) : 0;
+                    if (!read_buf || read_buf_size < buf_size || read_buf_size > 2*buf_size) {
+                        // free the old buffer first, so only one is alive
+                        read_buf.reset();
+                        read_buf.reset(ggml_backend_buft_alloc_buffer(ggml_backend_cpu_buffer_type(), buf_size));
+                        if (!read_buf) {
+                            throw std::runtime_error(format("failed to allocate a %zu-byte staging buffer", buf_size));
+                        }
                     }
-                    uint8_t * read_dst = (uint8_t *) GGML_PAD((uintptr_t) read_buf.data(), align);
+                    uint8_t * read_dst = (uint8_t *) GGML_PAD((uintptr_t) ggml_backend_buffer_get_base(read_buf.get()), align);
                     file->seek(aligned_offset, SEEK_SET);
                     file->read_raw_unsafe(read_dst, read_size);