Why
analyze reports # peak-footprint=<level>:<bytes> and refuses a program whose
peak exceeds the capacity a target states (src/tilefoundry/analysis/memory.py:391-395).
The name says "peak", but what is computed is the sum of the bytes live at the worst
point of the program (memory.py:363-380) — a lower bound on what an allocator
would need, because it accounts for neither placement nor fragmentation.
Nothing in this repository allocates buffers: grep -rn 'lifetime\|liveness\|reuse\|binpack' src/tilefoundry/codegen/
returns nothing, and codegen/cuda/tir/memory/alloc_tensor.py emits a declaration.
So the number is a self-standing estimate that no later stage is obliged to meet.
That is sound in one direction and silent in the other:
- A refusal is trustworthy. If even the optimistic sum exceeds capacity, the program
cannot fit, whatever the allocator does. No false refusals come from fragmentation.
- An acceptance is not. A program that fits only under a packing nobody performs is
accepted, and a program whose fragmentation pushes it over capacity is accepted too.
What
Decide what peak-footprint claims, and make the claim true.
Either:
- Keep the lower bound and say so. Rename the reported quantity and the refusal
so a reader knows it is a necessary, not a sufficient, condition, and state in
docs/spec/cli.md that acceptance means "not provably too large".
- Make it the allocated peak. Assign every buffer a lifetime, solve the packing
(a CP-SAT bin-pack, as buffer schedulers such as nncase's do), and report the
peak that solution reaches. This is only meaningful if codegen then allocates
under the same policy: an allocated peak that codegen does not follow is a second
account of the same quantity, and the two will disagree.
Contract
docs/spec/cli.md currently states neither what the number means nor which of the
two readings the refusal carries. Whichever way this is settled, that section is the
place it gets written down.
Risk
The second option is the larger one and it does not stand alone: it needs a codegen
allocation contract to be worth reporting. Filing this separately from the
lifetime-accounting fix below, which is a bug under the current reading and is being
fixed on its own.
Related: the lifetimes feeding today's number are built on a flattened value list
(memory.py:250-276, fed by memory.py:307) that carries no loop nesting, so a
loop-carried value's residency is under-counted. That is a defect under either
reading and is being fixed separately.
Why
analyzereports# peak-footprint=<level>:<bytes>and refuses a program whosepeak exceeds the capacity a target states (
src/tilefoundry/analysis/memory.py:391-395).The name says "peak", but what is computed is the sum of the bytes live at the worst
point of the program (
memory.py:363-380) — a lower bound on what an allocatorwould need, because it accounts for neither placement nor fragmentation.
Nothing in this repository allocates buffers:
grep -rn 'lifetime\|liveness\|reuse\|binpack' src/tilefoundry/codegen/returns nothing, and
codegen/cuda/tir/memory/alloc_tensor.pyemits a declaration.So the number is a self-standing estimate that no later stage is obliged to meet.
That is sound in one direction and silent in the other:
cannot fit, whatever the allocator does. No false refusals come from fragmentation.
accepted, and a program whose fragmentation pushes it over capacity is accepted too.
What
Decide what
peak-footprintclaims, and make the claim true.Either:
so a reader knows it is a necessary, not a sufficient, condition, and state in
docs/spec/cli.mdthat acceptance means "not provably too large".(a CP-SAT bin-pack, as buffer schedulers such as nncase's do), and report the
peak that solution reaches. This is only meaningful if codegen then allocates
under the same policy: an allocated peak that codegen does not follow is a second
account of the same quantity, and the two will disagree.
Contract
docs/spec/cli.mdcurrently states neither what the number means nor which of thetwo readings the refusal carries. Whichever way this is settled, that section is the
place it gets written down.
Risk
The second option is the larger one and it does not stand alone: it needs a codegen
allocation contract to be worth reporting. Filing this separately from the
lifetime-accounting fix below, which is a bug under the current reading and is being
fixed on its own.
Related: the lifetimes feeding today's number are built on a flattened value list
(
memory.py:250-276, fed bymemory.py:307) that carries no loop nesting, so aloop-carried value's residency is under-counted. That is a defect under either
reading and is being fixed separately.