Home > EulerNPU > Tutorials > 04. npu_sim — Cycle / Memory Simulation

04. npu_sim — Cycle / Memory Simulation

If cpu_ref answers "is the result correct?", npu_sim answers "how long does it take and how much does it use?". This is where cycles / memory / bandwidth get predicted before silicon bring-up.

It is the key tool for keeping the Measured design policy — no PL offload decision without measurement.

What's in it

The cycle model is locked against P06 silicon measurement: test_matmul_systolic_matches_p06_silicon fails CI if the formula drifts more than ±10 %.

Running

eulernpu compile --spec ... --backend npu_sim --out /tmp/sim
eulernpu run     --artifact /tmp/sim --input ... --out /tmp/sim.out.npz \
                 --profile /tmp/sim.profile.json

--profile emits the timeline JSON.

Reading the Profile

eulernpu profile show /tmp/sim.profile.json
Total cycles      : 2,164,512  (≈ 3.25 ms @ 666 MHz)
Bottleneck op     : conv2d_3 (980,224 cyc, 45.3%)
Bandwidth peak    : 412 MB/s @ depthwise_conv2d_5
Memory breakdown  :
  weights         : 132 KB / 140 KB BRAM (94%)
  activations     :  18 KB
  KV cache        :   0 KB
  scratch         :   4 KB

Board Profile Comparison

eulernpu profile --all-boards /tmp/sim.profile.json

See in one table how the same graph behaves on XC7Z020 / XC7Z045 / XCZU7EV / XCZU9EG — which board it first fits, where BRAM/DSP breaks.

Sweep — Board × systolic_size Pareto

eulernpu sweep \
    --spec    examples/industrial_kws/spec.yaml \
    --boards  xc7z020,xc7z045,xczu7ev,xczu9eg \
    --systolic 8,16,32,64 \
    --out     /tmp/kws_sweep.json

Each (board, systolic) combination produces latency / area / power, and the Pareto frontier is highlighted. Which trade-offs matter becomes visible in one view.

Trace — Per-op Latency

eulernpu trace /tmp/sim.profile.json --top 10
op                  cycles    %     bandwidth     mem
─────────────────────────────────────────────────────
conv2d_3           980,224   45.3   312 MB/s     BRAM
depthwise_conv2d_5 412,800   19.1   189 MB/s     BRAM
linear_7           198,432    9.2    24 MB/s     BRAM
gru_cell_0         156,224    7.2    12 MB/s     BRAM
...

Where the bottleneck lives, which ops are bandwidth-bound (memory hierarchy) vs compute-bound (DSP).

Roofline — Bandwidth-bound vs Compute-bound

eulernpu profile --roofline /tmp/sim.profile.json --board xc7z020

Each op's placement on the roofline (peak compute vs measured throughput). Left of the ridge point = bandwidth-bound, right = compute-bound. The basis for choosing which optimization to invest in.

Comparison with Measured Silicon

The cycle model is calibrated against P06:

kernelmodel predictsilicon measurederror
matmul_systolic (M=32 K=48 N=8)456 cyc460 cyc+0.9%
kws_npu_top (full graph)230 K cyc2.11 M cyc (DMA-included wall)bandwidth-bound regime

tests/hls/test_cycle_model_hls.py::test_matmul_systolic_matches_p06_silicon is the lock-test. CI fails if the formula drifts beyond ±10 %.

Next

To shrink weight/activation cost with INT8 quantization → 05. quantize.