Skip to content

instrument: ~7.3GB of a prefill's IOAccelerator growth is invisible to both MLX and currentAllocatedSize #163

Description

@penta2himajin

The gap

#150 attributed a long serialize prefill's footprint growth by diffing footprint's per-category output between baseline and peak (35,178 tokens, no code change):

Δ MB Δ regions category
+15,360 +2,151 IOAccelerator (graphics) — 94% of the growth
< 800 combined all MALLOC categories

Of that GPU growth, MLX accounts for ~8.1GB (cache +7.7, active +0.4). The remaining ~7.3GB is reported by neither MLX.Memory nor MTLDevice.currentAllocatedSize — in the fixed arm nonMLXmetal (= currentAllocatedSize − active − cache) actually went down while footprint grew.

So there is GPU memory this codebase currently cannot see. Every memory investigation here (#148, #150) has ended at the same wall: footprint says how much, and nothing says what.

Why it matters beyond curiosity

  • It is ~45% of a long prefill's footprint growth, i.e. the largest single unexplained term.
  • lanes: footprint ratchets to OOM under sustained load (predates Stage B; blocks v0.3.10) #148 needed three wrong verdicts before landing, and both of the instruments that finally cracked it (nonMLXmetal, the category diff) were built during the investigation. The next memory bug will hit this same wall.
  • It bounds what any memory fix can achieve: bounding MLX's pool cannot touch this 7.3GB.

What would settle it

Not a fix — an instrument. Candidates, cheapest first:

  1. vmmap -v <pid> region detail during a prefill, diffed the same way footprint was. IOAccelerator regions may carry enough tagging to distinguish command-buffer backing from texture/buffer allocations. Zero code change; try this before anything else.
  2. Metal allocation counters — whether MTLDevice exposes anything beyond currentAllocatedSize (heaps, MTLHeap allocations, residency sets) that MLX's raw buffers land in.
  3. Command-buffer lifetime: +2,151 regions over ~17 prefill windows × 694 dispatches suggests driver-side per-CB allocations. Test by varying chunk count at fixed token count — if regions scale with CB count rather than tokens, that identifies it.

Kill criterion

If (1) and (3) both fail to separate the 7.3GB into named consumers, close and record the wall explicitly: "footprint growth on this path is ~45% driver-side GPU memory that no available instrument attributes". A recorded dead end is worth more than an open issue nobody can act on.

Refs

#150 (the attribution and its numbers) · #148 (the lane investigation and the nonMLXmetal instrument) · TellRuntime.swift Tell.reportPrefillMemory (QWISP_PREFILL_MEMDBG, mode 1 for attribution — mode 2 perturbs)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions