advanced27 min studyLesson 963 in Engineering

Static shapes and memory planning

Trace tensor lifetimes to reuse arena storage safely, and account for alignment, persistent state, workspace and application buffers beyond the plan.

On this page

What you’ll understand

  • Calculate live-tensor and complete application memory requirements.
  • Identify when buffers may be safely reused across tensor lifetimes.
  • Explain bounded-shape planning and its limits in pinned edge runtimes.

An edge memory plan assigns storage to tensors whose sizes and lifetimes are known or bounded. It can reuse a region after its previous contents are no longer needed, making execution fit with less memory than the sum of every intermediate. The same reuse becomes corruption if an output, asynchronous consumer, or recurrent state still owns those bytes. Treat a plan as a contract about shapes, execution order, lifetimes, and ownership rather than a compression ratio attached to a model file.

Size tensors in bytes and trace simultaneous liveness

For a contiguous tensor, multiply every dimension by the element width, then account for the required alignment and any backend-specific padding or layout. A maximum input shape can propagate into larger intermediate bounds. ExecuTorch 0.7’s memory-planning documentation describes shape specifications, bounded symbolic evaluation, and arena assignment. The bound must cover accepted runtime inputs. Merely tracing one small example does not justify allocating for that example while permitting larger inputs through the application interface.

Draw a timeline showing when each tensor is produced, last read, and released. Reuse requires nonoverlapping lifetimes or an explicitly legal in-place operation, not simply two equal sizes. A producer’s input and output often coexist while its kernel runs. If a delegate or DMA engine consumes a buffer asynchronously, the lifetime ends only after completion under the relevant synchronization contract. External callers retaining an output also extend its lifetime beyond the model’s internal schedule.

bi=wi∏d=1rini,d,b~i=A⌈biA⌉b_i=w_i\prod_{d=1}^{r_i}n_{i,d},\qquad \widetilde b_i=A\left\lceil\frac{b_i}{A}\right\rceil
For a contiguous rank-r_i tensor, integer dimensions n and element width w_i in bytes give b_i bytes. A positive integer alignment A rounds its allocation size upward. Strided storage, packing, padding or backend formats need their actual storage-size rule instead of this simple formula.↔ Scroll wide equations horizontally.

An arena is only part of the complete memory budget

The pinned TFLM arena documentation distinguishes nonpersistent head allocations, scoped temporary allocations, and persistent tail allocations. Its planner reuses tensor storage across known lifetimes, and recording APIs help inspect allocation categories. This is not a claim that application stacks, sensor buffers, all backend allocations, or model constants always live in that arena. Keep a complete device map and identify each owner. Likewise, excluding ExecuTorch method inputs or outputs from a plan moves their storage obligation to the caller.

The maximum sum of simultaneously live tensor sizes is a useful lower bound, but alignment, contiguous-region requirements, fragmentation, scratch workspace, and planner heuristics can require more. Add persistent state and concurrent runtime/application allocations at their actual overlaps rather than blindly adding independent maxima from unrelated phases. Initialization may also need temporary conversion or repacking space. Measure high-water marks on the chosen device and test the largest supported shapes, multiple streams, and failure paths where lifetimes can lengthen.

Marena≥max⁡t∑i: t∈LibiM_{\mathrm{arena}}\ge\max_t\sum_{i:\,t\in\mathcal L_i}b_i
Tensor lifetime sets L_i refer to one declared execution schedule, and b_i uses bytes. This is a storage lower bound for separately live values unless a proven aliasing or in-place rule permits sharing. It excludes persistent allocations and scratch not represented among the tensors, and does not guarantee a contiguous feasible placement.↔ Scroll wide equations horizontally.

Validate boundaries and inspect the real plan

Reject out-of-contract shapes before execution, or select another independently validated plan. Test repeated calls and interleaved sessions because a plan safe for one invocation can fail when two use the same arena concurrently. Use canaries or memory tools appropriate to the target, inspect planned offsets and lifetimes, and compare outputs under stress. MCUNetV2 illustrates how changing inference scheduling can reduce peak memory; that result does not make an arbitrary reused buffer safe or transfer its measured savings to every network.

The cache lab illustrates reuse under a fixed capacity, not lifetime allocation. Reset, set capacity C to 4 and stride s to 4, predict four misses and twelve hits in the initial sixteen requests, then Step: the seventeenth request is another hit. Compare a fresh Reset with both C at 2 and s at 4 before Step: all seventeen miss. This fully associative LRU toy has no tensor graph, arena offsets, scratch space, or asynchronous consumer ownership.

Reuse two nonoverlapping intermediate buffers

Tensor A uses 64 KiB, B uses 96 KiB, and C uses 64 KiB. A and B coexist, then B and C coexist, but A is dead before C is created. All sizes meet alignment. A 32 KiB scratch buffer and 24 KiB persistent state coexist with the tensor peak; stacks and IO add another 24 KiB.

  1. Without reuse, tensor storage sums to 64 + 96 + 64 = 224 KiB. A and C can share one 64 KiB region under the stated disjoint lifetimes.

  2. Keep a separate 96 KiB region for B, giving a feasible tensor plan of 160 KiB for this simple schedule. The live peak is also 160 KiB.

  3. Total simultaneous memory is 160 + 32 + 24 + 24 = 240 KiB. A 256 KiB device budget leaves 16 KiB under these assumptions, before any unlisted allocator or driver requirement.

The result

A valid lifetime argument justifies reuse, while the complete application budget determines device feasibility.

Explore the model

Interactive lab

Interactive lab · cache

Reuse benefits without an arena planner

Reset, set C = 4 and s = 4, predict 4 misses and 12 hits among the initial 16 requests, then Step: 13 hits among 17. Compare a fresh Reset with both C = 2 and s = 4 before Step: 17 misses. This capped fully associative LRU stream illustrates working-set reuse, not tensor lifetimes or memory-plan correctness.

Reuse benefits without an arena plannerA fully associative LRU cache starts empty and requests address (i·s) mod 16. Hits move an address to the newest position; misses evict the oldest when full. Playback starts with 16 requests and adds two per second, capped at 4096 explicitly simulated requests. This toy stream is not a processor-cache benchmark. Current readings: Hits / requests: 0 / 16; Hit rate: 0%; Address-stream period: 16 addresses. All parameters are adjustable with the labeled controls below.Fully associative LRU cache after 16 deterministic requests: 0 hits and 16 misses.Most recent 16 requestsaddress = i × 3 mod 160M3M6M9M12M15M2M5M8M11M14M1M4M7M10M13MCurrent cache order · oldest → newest471013Latest address 13 · miss: inserted as newestToy address stream · period 16 · starts empty
Cached addressMiss / evictionMost recent request
Hits / requests
0 / 16
Hit rate
0%
Address-stream period
16 addresses
t = 0 s

A fully associative LRU cache starts empty and requests address (i·s) mod 16. Hits move an address to the newest position; misses evict the oldest when full. Playback starts with 16 requests and adds two per second, capped at 4096 explicitly simulated requests. This toy stream is not a processor-cache benchmark. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.

Look forMemory reuse needs an ownership argument in addition to capacity accounting.

Check your understanding

Two 64 KiB tensors have equal sizes. When can their storage be shared in a lifetime-based plan?

Try it yourself

A uses 48 KiB, B 80 KiB, and C 48 KiB, with the same A/B then B/C overlap pattern. Add 16 KiB scratch, 20 KiB persistent state, and 12 KiB application memory, all concurrent with the peak. Find a feasible total under a 192 KiB budget.

Take a moment to make a prediction or work it out on paper. Open a hint when you need one.

Give me a hint

Reuse A’s region for C only after A is dead. Treat the stated extra allocations as simultaneous.

Compare with the solution

A and C share 48 KiB while B occupies another 80 KiB, so tensor storage is 128 KiB instead of 176 KiB. Total simultaneous memory is 128 + 16 + 20 + 12 = 176 KiB, leaving 16 KiB against 192 KiB. This is feasible for the declared aligned regions and schedule; an unlisted delegate workspace or retained output would require updating the plan rather than borrowing the margin silently.

Take it with you

  • Reuse storage only after every prior owner has finished.
  • Bounded shapes and aligned tensor sizes determine a specific plan.
  • Arena accounting must be combined with workspace, state and application memory.

Read further

Original sources and deeper explanations to follow at your own pace.

Optional progress, saved in this browser when available. Revisit any lesson at any time.

Lesson not marked complete.