Skip to content

feat(analytic): add a stacked 3D DRAM memory model and memory-aware latency estimate - #121

Merged
GeorgeWu1204 merged 2 commits into
mainfrom
feat/mzw-stacked-dram
Oct 25, 2026
Merged

GeorgeWu1204 merged 2 commits into
mainfrom
feat/mzw-stacked-dram

Conversation

@Hamerlate

@Hamerlate Hamerlate commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Adds analytic_models/stacked_dram: a 3D-stacked DRAM memory model and a memory-aware TTFT/TPS estimate for one PLENA chip.

PerfModel charges H_PREFETCH_* a single cycle, so the TTFT and TPS of llama_model.py assume the memory system always keeps up. This adds the missing memory term. A memory is either a fixed-bandwidth baseline (for example a datasheet HBM number) or a DRAM stack whose usable bandwidth follows from its height, vertical connectivity, buffering and thermal limits, so the same decoder can be compared across stack designs.

The memory mechanisms are ported from DeepStack (Mo et al., MICRO 2026, arXiv:2604.04750), and every module names the DeepStack source it follows (tile-ai/DeepStack@8509061). The package has no runtime or test dependency on DeepStack. No hardware values ship with it: a design is a JSON profile, and the two example profiles are deliberately fictional.

Mechanisms

mechanism model DeepStack source
peak bandwidth connected layers × channels × bytes per transfer × transfers per clock × memory clock, or a direct per-layer peak src/deepstack/mosaic/arch/custom_profile.py
connectivity efficiency 1 while at most half the layers are connected, then linear down to the fully connected efficiency same
fully connected efficiency row read cycles / (row read + recharge cycles) from bank timing, or given directly same
buffering cap (Little's law) bytes in flight per requester = bandwidth / requesters × round-trip latency × buffering factor; a smaller buffer scales the usable bandwidth down src/deepstack/mosaic/dse_space/case_study_dram_layer/dram_layer_config.py
thermal derating junction resistance grows with each layer; the dynamic power left sets the compute clock scale same
wave quantisation each transfer rounds up to transaction bytes × channels src/tilesight/tilesight/fused_op_dtype_wave/matmul_fused_op_new_api_wave.py
capacity, energy layers × capacity per layer; read and write bits × pJ/bit src/deepstack/mosaic/arch/custom_profile.py, src/deepstack/mosaic/cost/energy.py

GPU-only fields (L2 multiplier, uncached utilisation, the bank-oracle clock) are dropped, the memory clock moves into the DRAM configuration, and DeepStack's per-SM quantities become per-requester (DMA stream) quantities.

Estimate

Each stage, meaning the embedding lookup and every transformer block, takes max(cycles / f, bytes / usable bandwidth) (stage-roofline, the default, which is how DeepStack prices an operator) or their sum (serial). The compute term is llama_model.py's PerfModel calls, including its ×2 decode issue factor. Traffic per block:

  • weights are read once per forward pass;
  • decode reads the layer's whole KV cache and writes one new K/V row;
  • prefill re-reads K/V once per MLEN-row query tile (the H_PREFETCH_M loop of flash_attention);
  • activations reach DRAM only where PerfModel spills them past Vector SRAM (both RMSNorms, the projection, the residual);
  • storage precisions come from [ANALYTIC.PRECISION] in plena_settings.toml (MXFP8 by default).

The result reports TTFT, TPS, per-phase compute and memory time with the memory-bound share, DRAM bytes and energy, weights + KV against capacity, and warnings (buffering cap, thermal derating, head_dim × heads ≠ hidden_size). MoE decoders are rejected here; the multi-chip follow-up handles them.

just stacked-dram-describe analytic_models/stacked_dram/examples/fictional_stacked_dram.json --total-layers 4,8,12
just stacked-dram-estimate llama-3.1-8b analytic_models/stacked_dram/examples/fictional_stacked_dram.json
just test-stacked-dram

Validation

  • 75 unit tests: configuration rules, each mechanism, profiles (strict keys, JSON booleans rejected as numbers), the estimate and the CLI.
  • With unbounded bandwidth the estimate reproduces llama_model.py's TTFT and TPS (relative error ≤ 1e-12).
  • Outside the repository, the mechanisms were checked against DeepStack@8509061 on 153 values (largest relative error 1.7e-16).
  • ruff format --check . and ruff check . pass with the locked ruff.

Also in this PR

093de4ea makes analytic_models importable and installable: main's analytic_models/__init__.py imports memory and utilisation, which do not exist, and pyproject.toml does not include analytic_models*. #103 and #118 carry the same fix. Whichever lands first, the others resolve the conflict by keeping the union of imports.

Follow-ups

analytic_models/__init__.py still imported the memory and utilisation
packages that c4d0907 removed, so `import analytic_models` failed. Import
only performance, and list analytic_models* in the setuptools packages (the
same line #103 adds) so `uv sync` installs the package.
…atency estimate

PerfModel charges HBM prefetch/store instructions one cycle, so llama_model.py
assumes the memory system always keeps up. analytic_models/stacked_dram adds
the missing memory term and a 3D-stacked DRAM model to price it:

- StackedDramConfig/DramTimingConfig: peak bandwidth from the connected
  layers, vertical-connectivity efficiency (a given endpoint or bank row
  timing), capacity, and DRAM-wave quantisation of transfers.
- BufferingPolicy (Little's-law bandwidth cap), ThermalPolicy (compute-clock
  derating with stack height) and DramEnergyConfig (pJ/bit).
- FixedBandwidthMemory for baselines; JSON profiles with strict keys and
  SHA-256 provenance.
- estimate_decoder_latency: PerfModel compute exactly as in llama_model.py plus
  per-stage DRAM traffic (weights, KV cache, activation spills), combined by a
  stage-roofline or serial overlap. Reports TTFT/TPS, memory-bound time, DRAM
  bytes and energy, and the footprint against capacity.
- python -m analytic_models.stacked_dram describe|estimate, and the just
  recipes stacked-dram-describe, stacked-dram-estimate and test-stacked-dram.

The memory mechanisms are ported from DeepStack (arXiv:2604.04750,
tile-ai/DeepStack@8509061) and each module names its source. PLENA does not
depend on DeepStack, and no hardware values ship with the package: every
parameter comes from the caller and the example profiles are fictional.

Verified: 75 unit tests pass; with unbounded bandwidth the estimate matches
llama_model.py's TTFT/TPS to 1e-12; the ported equations match DeepStack on
153 reference values to 2e-16 (checked outside the repository); ruff clean.
@GeorgeWu1204
GeorgeWu1204 merged commit f7f1e99 into main Oct 25, 2026
5 checks passed
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.

2 participants