IOKit-mapped Metal buffer accounting in phys_footprint
Parent: Mac local LLMs: Memory and wired limits · Published reference · snapshot 2026-10-05
↓ Facts as markdownall context files
`alternate_accounting` is "the number of internal dirty pages which are part of IOKit mappings"; they are counted in both internal and iokit_mapped, so they are subtracted from the footprint sum.
These notes link each claim to its source. A source may be a research report hosted on this site rather than the primary document. A published reference means the content is available; it does not certify independent review or accuracy.Read the editorial policy and follow the sources before relying on a claim.
Facts
- `alternate_accounting` is "the number of internal dirty pages which are part of IOKit mappings"; they are counted in both internal and iokit_mapped, so they are subtracted from the footprint sum. [source]
- A map entry gets the IOKit charge only when the entry is created with the iokit_acct flag AND its object is internal (anonymous). The code sets `iokit_acct = TRUE`, `use_pmap = FALSE` and calls `vm_map_iokit_mapped_region` with the entry size. [source]
- Therefore a file-backed (external) object mapped through the same path takes the plain pmap branch and is not charged to `iokit_mapped`. [source]
- Page queries treat non-purgeable internal IOKit memory as present and dirty across its whole virtual range ("phys_footprint includes the entire virtual mapping"). [source]
- Objects flagged `vo_no_footprint` are excluded from the footprint entirely ("does not count in footprint"). [source]
- Measured: a 2 GiB `MTLResourceStorageModeShared` buffer from `newBufferWithLength:` added 0 to `phys_footprint` and `internal` when created, and 2.15 GB to both only after the CPU wrote the pages with memset; `resident_size` tracked the same. [asserted] (measured locally 2026-10-04, Apple M5 Max, macOS 27.2, via TASK_VM_INFO) [source]
- Measured: a 2 GiB anonymous mmap that was touched, then wrapped with `newBufferWithBytesNoCopy:`, added nothing at wrap time (4.30 GB before and after); footprint rose only by the touched pages. Releasing the Metal buffer left the anon pages. [asserted] (same host) [source]
- Measured: a 2 GiB shared file mapping written and msynced, then wrapped with `newBufferWithBytesNoCopy:`, showed `phys_footprint` 0.01 GB, `external` 2.16 GB and `resident_size` 2.16 GB before and after wrapping. [asserted] (same host) [source]
- Measured: wrapping an untouched anonymous 2 GiB region as a no-copy buffer then filling it with a GPU blit raised `phys_footprint` only to 0.12 GB and left `resident_size` at 0.01 GB, so GPU-written pages in that case were not charged to the task as dirty internal pages in the way CPU writes were. [asserted] (same host; one run, cause unexplained) [source]
- Not documented in sources read. [source]
- The vmlx 130 GB footprint at first prefill therefore needs another explanation (touched or GPU-written pages, wired memory, or a different allocation path). The test here cannot show which. [source]
- A `phys_footprint` reading stays small for a file-backed no-copy buffer even when the whole file is resident, so tools reporting footprint hide mmap'd weights; `resident_size` and `external` show them. [source]
- Kernel-source reading (the whole IOKit mapping is charged at map time) versus measurement (Metal shared buffers charged by touched page). Both are shown side by side; the kernel path charges only entries created with iokit_acct on internal objects, and Metal's shared-storage allocation evidently does not use that path in this macOS build. [source]
- Which allocation path (IOSurface, IOGPU, or plain vm_allocate) backs `MTLResourceStorageModeShared` buffers, and whether private-storage buffers are charged by size. [source]
- Why a GPU-written no-copy buffer left the CPU-side footprint near zero. [source]
- Behavior of wired no-copy buffers under `MTLResourceHazardTracking` or `setPurgeableState`. [source]
- The IOKit mapping charge applies only to internal (anonymous) objects in entries created with iokit_acct. [source]
- `alternate_accounting` exists to avoid counting IOKit internal dirty pages twice in phys_footprint. [source]
- `vo_no_footprint` objects are excluded from footprint. [source]
- On M5 Max macOS 27.2 a shared MTLBuffer's footprint grows with touched pages, not at allocation. [source]
- On the same host a no-copy buffer over file-backed pages adds nothing to `phys_footprint` and shows as `external` plus `resident_size`. [source]
Corrections and disagreements
- CONTRADICTS: jangpress-rss-accounting-after-expert-deactivati.md line 21 ("If a runtime wraps mmap pages as no-copy Metal buffers ... `phys_footprint` would be charged the full mapped size at map time"). On macOS 27.2 / M5 Max neither a shared MTLBuffer nor a no-copy wrapper over anonymous or file-backed pages was charged at map time. Footprint followed touched pages (internal) or stayed near zero (file-backed, counted as `external`). [source]
Children
- No children recorded.