Skip to content

llama: improve TENSOR_READ_LAZY handling - #27837

Merged
ngxson merged 3 commits into
masterfrom
xsn/tensor_read_lazy_improve
Aug 30, 2026
Merged

ngxson merged 3 commits into
masterfrom
xsn/tensor_read_lazy_improve

Conversation

@ngxson

@ngxson ngxson commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Overview

Follow-up #27794 #27742

  • Make sure --tensor-read-lazy take full precedence over --load-mode or -ot: If tensor is decided to be "lazy-read", it will be mmap'ed no matter what. This is because some use cases use --load-mode none for faster weight offloading to GPU, but that doesn't mean user want to offload the PLE tensor
  • Context fit pass now correctly exclude the PLE tensor
  • If system doesn't support mmap, print a WARN while loading the whole tensor onto RAM --> not sure if it worth properly fixing this case, I feel like will be too much work to do
  • Logic is now contained inside substruct llama_model_loader::lazy_read

Requirements

@ngxson
ngxson requested review from CISC and ggerganov as code owners August 27, 2026 23:35
@ngxson
ngxson requested a review from ServeurpersoCom August 27, 2026 23:35
@ngxson ngxson changed the title Xsn/tensor read lazy improve llama: improve TENSOR_READ_LAZY handling Aug 27, 2026
@tarruda

tarruda commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

@ngxson can you also implement the flag on llama-bench? Would be useful to compare how it affects tg/pp (see also: #27864)

@ngxson

ngxson commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator Author

hmm ok I thought llama-bench uses the same common/arg, turns out we need to add it manually here

@Kononnable

Copy link
Copy Markdown
Contributor

As --tensor-read-lazy is enabled by default(auto) it might be a good idea to add a warning that -ot on those tensors is ignored (explicitly set -ot will be overridden by implicit --tensor-read-lazy).

@Nekotekina

Copy link
Copy Markdown
Contributor

Maybe add LLAMA_LAZY_MODE_ALL or something to disable prefetching completely.
#27928
I'm at bad timings again...
It can be useful to load any model like this.

sdougbrown added a commit to sdougbrown/r9700-llama-cpp that referenced this pull request Aug 30, 2026
@jintakhan

Copy link
Copy Markdown

Previewing this PR, definitely seeing a --load-mode none prefill speed boost of 15% over --load-mode mmap. Not quite the 2x speed of loading the whole table to RAM, but a boost nonetheless, and the PLE tables stay on disk as intended, so that's a win in my book. Disabling --tensor-read-lazy (which will be renamed --lazy-mode -lzm per #27969) along with --load-mode none shows the expected behavior of loading PLE table to RAM, the old no-mmap behavior incl. the full 2x speed gain and RAM use.

@ServeurpersoCom ServeurpersoCom left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The precedence rule is the right call. Tested on Qwen3.8-Flash-Next: with and without -ot per_layer_token_embd=CPU gives the same numbers, so it lands in auto and the -ot is correctly ignored.

@ngxson

ngxson commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator Author

@Kononnable there should already been a LLAMA_LOG_INFO if the tensor is determined to have lazy read = on (get logged no matter auto or on), that should be enough

@ngxson
ngxson merged commit 2578138 into master Aug 30, 2026
23 of 27 checks passed
@jintakhan

Copy link
Copy Markdown

One more update on performance gains. The mmap bottleneck isn't architectural overhead from memory mapping, it's probably just latency sensitive. I run llama.cpp in a Docker VM and moving the model files from the vdisk to direct storage on PCIe passthrough restores the no-mmap PLE lazy load prefill performance to speeds with the full model+PLE in resident memory.
This patch will let me use these big models while freeing up enough memory to run a second faster MoE model on another GPU with expert offload — and still have enough RAM left over to keep the workstation usable as a general purpose computer. Awesome stuff.

kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Aug 31, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Aug 31, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Aug 31, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
TrevorS added a commit to TrevorS/llama.cpp that referenced this pull request Aug 31, 2026
This reverts upstream 2578138. It costs 73% of prefill on this box.

The commit routes every lazily-read tensor to the generic CPU buffer type
(lazy_read::buft() returns ggml_backend_dev_buffer_type of the CPU device).
Before it, our 28.8 GB per_layer_token_embd lived in CPU_Mapped -- mmap'd host
memory that GB10's GPU reads directly, since the part reports
pageableMemoryAccessUsesHostPageTables=1. Forced into a plain CPU buffer, the
per-layer PLE gathers get scheduled on the CPU backend instead, and the GPU sits
idle waiting on them: an nsys capture of the regressed build shows 31.5% GPU-busy
and 22-38 W board power during prefill, with the SM clock pinned at 2190 MHz and
no throttle reason active. The work is not slower, it is on the wrong device.

Found by bisecting the 21 commits between c589f0e and a7cc83b on pure
upstream, with none of our code in the tree:

  0b5be7e  hip: tune rdna 3 mmq config              741.98 t/s
  f1793c1  CUDA: fast mm_ids_helper for any n_eu    812.70 t/s   +9.5%
  2578138  llama: improve TENSOR_READ_LAZY          222.70 t/s   -72.6%
  a7cc83b  (tip)                                    211.67 t/s
  a7cc83b + this revert                             813.86 t/s

llama-bench pp4096, ub4096, UD-IQ4_XS. The revert restores the number exactly,
which is the evidence that this commit and nothing else in that range is
responsible.

Worth being precise about what this is not: the mm_ids_helper commit immediately
before it is a real +9.5% win here (n_expert_used = 10 was excluded from the fast
path by the old warp_size % n_expert_used == 0 gate), and it survives the revert.
The two are independent.

This is a local deviation, not a claim the upstream change is wrong in general --
it plausibly fixes lazy reads on discrete-GPU systems where a device-buffer lazy
tensor cannot work. It is wrong specifically for a UMA part that can read mmap'd
host pages from the GPU, which is the only configuration we serve.
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 2, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 19, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 19, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 19, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 20, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 20, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 20, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 20, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 20, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 20, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 21, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 21, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 21, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 22, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 22, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 22, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 22, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 22, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 22, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 23, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 23, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 25, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 25, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 25, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 25, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 26, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 27, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 27, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 27, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 27, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
kurochan001 added a commit to kurochan001/llama.cpp that referenced this pull request Sep 27, 2026
… mmap

When a tensor is read lazily (per_layer_token_embd on the CPU) but sits between
tensors that go to the device, the device buffer created from the host pointer
spanned it. On Apple silicon Metal pins every page of a mapped buffer, so the
whole 27 GiB table stayed wired even though nothing on the device reads it.
Split the range around such tensors instead; a file may now map to more than
one buffer, and load_all_data picks the one that holds each tensor.

Rebased onto b10712: lazy tensors now live in their own context (ggml-org#27837), so
the split is skipped for lazy contexts and the ranges come from ml.lazy.for_file().
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants