290 lines
12 KiB
Markdown
290 lines
12 KiB
Markdown
# Calculet NPU 模型产物与内存映射
|
||
|
||
日期:2026-08-02
|
||
模型:Qwen3-30B-A3B dynamic W8A8/W4AF16,双芯粒,40960 context,Flash Attention
|
||
|
||
实施下钻:逐文件/逐字段 grammar、跨文件校验、严格拒绝条件和可执行检查器见《Calculet NPU calbin 产物字段字典与静态验收规范》及 `calculet_package_validate.rb`。本文保留容量和映射分析,字段字典负责新包验收。
|
||
|
||
## 1. 路径与范围
|
||
|
||
本文的模型根目录是:
|
||
|
||
```text
|
||
outputs/Calculet-NPU-analysis-bundle-20260801/remote-export/extracted/models-complete/models
|
||
```
|
||
|
||
该目录下只有一套完整模型。`models` 树共 68 个文件:模型目录内 67 个文件,外加一份重复放置的 `Qwen3-30B-A3B.vocab.gguf`。不能把这些文件解释为 68 个模型。
|
||
|
||
模型目录内文件总量为 17.456 GiB;加外层 vocab GGUF 后约 17.462 GiB。
|
||
|
||
## 2. 产物分类
|
||
|
||
| 分类 | 数量 | 大小 | 作用 |
|
||
| --- | ---: | ---: | --- |
|
||
| 参数分片 | 2 | 16.938 GiB | chip0/chip1 的权重和常量块 |
|
||
| Runtime 命令文本 | 16 | 402.541 MiB | prefill/decode、chip0/1、CPU/PLD、ping/pong 的可读命令 |
|
||
| Runtime 命令二进制 | 16 | 81.549 MiB | 与上述命令对应的可部署二进制 |
|
||
| CCU ELF | 8 | 23.225 MiB | prefill/decode x chip0/1 x ccu0/1 |
|
||
| CPU helper SO | 2 | 0.250 MiB | prefill 动态 D2D 的 x86/RISC-V helper |
|
||
| profile parts | 4 | 0.122 MiB | prefill/decode 在两个芯粒的算子列表 |
|
||
| op 地址映射 | 2 | 1.003 MiB | 每个 op 的输入、常量、输出地址/shape/dtype |
|
||
| tokenizer | 9 | 22.426 MiB | tokenizer、vocab、merges、config、GGUF |
|
||
| 其他 metadata | 8 | 0.051 MiB | 编译配置、内存保留、hparam、版本 |
|
||
|
||
参数之外的文件不是可丢弃的“日志”:它们共同描述了芯粒分配、地址计划、命令流、编译配置、golden hash 和可复现性。
|
||
|
||
## 3. 目录语义
|
||
|
||
### 模型根目录
|
||
|
||
| 文件 | 含义 |
|
||
| --- | --- |
|
||
| `param_blk0.bin` | chip mask 1,对应 chip0 参数分片 |
|
||
| `param_blk1.bin` | chip mask 2,对应 chip1 参数分片 |
|
||
| `model_memory_reserved_info.txt` | 全模型 DRAM/SRAM/sync 保留和参数映射 |
|
||
| `hparam.yaml` | golden/冒烟推理时的 prefill/decode CSR |
|
||
| `*_2_chips_40960_fa.yaml` | 原 ONNX 路径/hash、shape、模型/设备/编译配置、golden hash |
|
||
| `*_op_io_buf_ptr.yaml` | op 级地址、shape、dtype 和生产者关系 |
|
||
| `*.profparts` | 每芯粒执行的 op 顺序 |
|
||
| `version.py` | 产物版本辅助信息 |
|
||
| `__Tokenizer/` | tokenizer 和模型结构配置;不含 safetensors 权重本体 |
|
||
|
||
### Prefill/Decode 子目录
|
||
|
||
| 文件模式 | 含义 |
|
||
| --- | --- |
|
||
| `submodel_memory_reserved_info.txt` | 子模型类型、batch、芯片模式、I/O、CSR、文件芯片掩码 |
|
||
| `cpu_chip{0,1}_{ping,pong}.bin` | CPU 侧任务命令 |
|
||
| `pld_cpu_chip{0,1}_{ping,pong}.bin` | PLD/CPU 数据移动命令 |
|
||
| `*_runtime_cmds_*.txt` | 上述二进制的文本表示 |
|
||
| `ccu{0,1}_chip{0,1}.elf` | 每芯粒两个 CalCore/CCU 程序 |
|
||
| `libcpu_x86.so` | prefill 动态命令 helper,导出 `Process` |
|
||
| `libcpu_riscv.so` | 同一 helper 的设备侧/目标架构版本 |
|
||
|
||
Decode 没有 `libcpu_*.so`,与编译配置 `dynamic_d2d=false` 一致;Prefill 为 `dynamic_d2d=true`。
|
||
|
||
## 4. 编译输入与配置还原
|
||
|
||
模型 YAML 记录了同一原始 ONNX 用两组 shape 编译:
|
||
|
||
```text
|
||
/st_scratch/STG/calq_export_models/llm/Qwen3-30B-A3B/Dynamic/Merge_full_layers/
|
||
Qwen3-30B-A3B-dynamic-W8A8-W4AF16-full_layers_merged.onnx
|
||
```
|
||
|
||
ONNX SHA-256:
|
||
|
||
```text
|
||
316f06e7e316b1305486118fa7da65f816b61deb46de09a2f4fec6979530456c
|
||
```
|
||
|
||
编译版本:
|
||
|
||
- calcc:`575c2d708e306a60f10bc34f5087477073b58caa`
|
||
- TVM:`7aebd1c21fa67d942a1fd93e39e8a67007f91c0c`
|
||
- `with_codegen=true`
|
||
- `with_op_case=true`
|
||
- `with_c_oplib=true`
|
||
- `use_auto_alloc=true`
|
||
- `enable_flash_attention=true`
|
||
- `enable_one_token=true`
|
||
- chip 数 2,CalCore 数 2/芯粒
|
||
|
||
`has_loaded_onnx=false`、`has_optimized_graph=false` 是本次编译配置状态,不代表产物未经图优化;结合最终融合 op,应理解为编译入口没有复用预加载/预优化中间对象。
|
||
|
||
当前归档中没有 ONNX 文件、calcc 可执行文件、pass 源码、oplib、kernel 源码或 compiler container。因此可以反推配置,不能重放编译。
|
||
|
||
## 5. 子模型 I/O 与 CSR
|
||
|
||
### Prefill
|
||
|
||
| 对象 | Shape | Dtype | 地址/大小 |
|
||
| --- | --- | --- | --- |
|
||
| `inputs[0]` token | `[1,40960]` | INT32 | ping/pong `0xc0000000/0xc0028000`,163840 B |
|
||
| `inputs[1]` position | `[1,40960]` | INT32 | ping/pong `0xc0050000/0xc0078000`,163840 B |
|
||
| `outputs[0]` logits | `[1,1,151936]` | BF16 | ping/pong `0x367b21000/0x367b6c000`,303872 B |
|
||
| `cur_seq_len[0]` | CSR | UINT32 | offset `0x1104` |
|
||
| `past_kv_cur_seq_len[0]` | CSR | UINT32 | offset `0x1144` |
|
||
|
||
Prefill 虽按 40960 最大输入分配,llama 端通过 `SliceTensor()` 只传实际 token/position,并只回传末 token 的 logits tile。
|
||
|
||
### Decode
|
||
|
||
| 对象 | Shape | Dtype | 地址/大小 |
|
||
| --- | --- | --- | --- |
|
||
| `inputs[0]` token | `[1,1]` | INT32 | ping/pong 同址 `0x08e61800/0x08e61c00`,4 B |
|
||
| `inputs[1]` position | `[1,1]` | INT32 | ping/pong `0xc0000000/0xc0001000`,4 B |
|
||
| `outputs[0]` logits | `[1,1,151936]` | BF16 | ping/pong `0xc0002000/0xc004d000`,303872 B |
|
||
| `cur_seq_len[0]` | CSR | UINT32 | offset `0x1104` |
|
||
| `past_kv_cur_seq_len[0]` | CSR | UINT32 | offset `0x1144` |
|
||
|
||
`hparam.yaml` 的上限测试设置为:prefill `cur=40959,total=40959`,decode `cur=1,total=40960`。
|
||
|
||
## 6. 参数映射
|
||
|
||
### 文件大小
|
||
|
||
| 文件 | 精确字节 | GiB | 芯片掩码 |
|
||
| --- | ---: | ---: | --- |
|
||
| `param_blk0.bin` | 9,404,557,312 | 8.759 | `0x1`,chip0 |
|
||
| `param_blk1.bin` | 8,782,227,456 | 8.179 | `0x2`,chip1 |
|
||
| 合计 | 18,186,784,768 | 16.938 | 双芯粒 |
|
||
|
||
### 按 memory reservation 段求和
|
||
|
||
| 芯粒 | DRAM 映射 | SRAM 窗口映射 | 合计与文件关系 |
|
||
| --- | ---: | ---: | --- |
|
||
| chip0 | 9,389,477,888 B,8.745 GiB | 15,079,424 B,14.381 MiB | 与 `param_blk0.bin` 精确闭合 |
|
||
| chip1 | 8,767,148,032 B,8.165 GiB | 15,079,424 B,14.381 MiB | 与 `param_blk1.bin` 精确闭合 |
|
||
|
||
SRAM 常量不是额外文件;它们是参数分片中的指定 offset,在 configure 时放入 SRAM 地址窗口。
|
||
|
||
## 7. 全局保留区
|
||
|
||
`model_memory_reserved_info.txt` 给出的逻辑地址计划:
|
||
|
||
| 类型 | 起始地址 | 大小 | 换算 |
|
||
| --- | --- | ---: | ---: |
|
||
| DRAM reserved | `0xc0000000` | 15,113,064,448 B | 14.075 GiB |
|
||
| SRAM reserved | `0x08000000` | 17,662,336 B | 16.844 MiB |
|
||
| sync reserved | `0x0a080000` | 20 B | 20 B |
|
||
|
||
这些地址在参数段中按 chip mask 1/2 分别出现,因此最合理的解释是同一虚拟地址计划应用于每颗芯粒。若成立,双芯粒逻辑 reservation 约为 28.150 GiB DRAM + 33.688 MiB SRAM。该点应让厂商书面确认。
|
||
|
||
`device_memory_required: 16777216 MB` 的单位明显错误。若数值实际是 KiB,则为 16 GiB/芯粒;若按字段 MB 解释则完全不可能。
|
||
|
||
## 8. KV Cache
|
||
|
||
模型配置:48 层、4 KV heads、head dim 128、BF16、最大 40960、batch 1,K/V 各一份。
|
||
|
||
```text
|
||
KV bytes
|
||
= layers x KV_heads x (K + V) x head_dim x context x BF16_bytes
|
||
= 48 x 4 x 2 x 128 x 40960 x 2
|
||
= 4,026,531,840 bytes
|
||
= 3.750 GiB
|
||
```
|
||
|
||
当前 tensor parallel 将 4 个 KV heads 分成每芯粒 2 个,所以每芯粒为:
|
||
|
||
```text
|
||
2,013,265,920 bytes = 1.875 GiB
|
||
```
|
||
|
||
Decode op 地址图中最大的 activation 连续区间是:
|
||
|
||
```text
|
||
0xc00a0000 .. 0x1380a0000 = 2,013,265,920 bytes
|
||
```
|
||
|
||
它与每芯粒 KV 公式精确相等,是 KV 区间的直接产物证据。
|
||
|
||
CalRT 0.7.6 的 KV 数据结构支持 BF16 K-cache、BF16/S8 V-cache 和 batch>1 的不同 K/V layout,但当前 calbin 是 BF16、batch 1。不能仅通过 Runtime 开关把现有模型变成 S8 V-cache。
|
||
|
||
## 9. Tensor 地址并集
|
||
|
||
对 `*_op_io_buf_ptr.yaml` 的所有输入/输出区间去重并合并后:
|
||
|
||
| 图 | 常量覆盖 | activation 覆盖 | input 覆盖 | 全部地址并集 |
|
||
| --- | ---: | ---: | ---: | ---: |
|
||
| Decode | 8.758 GiB | 1.875 GiB | 8 B | 10.634 GiB |
|
||
| Prefill | 8.758 GiB | 5.332 GiB | 0.000305 GiB | 14.091 GiB |
|
||
|
||
解释规则:
|
||
|
||
- “覆盖”是地址区间并集,不是同时活跃的峰值内存。
|
||
- 常量、activation 可能在边界处相邻或复用,不可直接相加。
|
||
- Decode activation 基本就是 1.875 GiB KV 加少量 I/O/workspace。
|
||
- Prefill 除 KV 外还有约 3.456 GiB 的长序列 activation/workspace 地址区。
|
||
- Prefill 全部并集 14.091 GiB 与 14.075 GiB DRAM + 16.844 MiB SRAM 基本闭合,说明地址解析口径正确。
|
||
|
||
上述值来自 `work/analyze_calculet_artifacts.rb`,原始计算输出在 `work/calculet-artifact-analysis.tsv`。
|
||
|
||
## 10. 双芯粒算子分配
|
||
|
||
| 图 | chip0 profile 行 | chip1 profile 行 | 差异 |
|
||
| --- | ---: | ---: | --- |
|
||
| Decode | 1254 | 1253 | embedding 只在 chip0 |
|
||
| Prefill | 1352 | 1351 | embedding 只在 chip0 |
|
||
|
||
两边都有:
|
||
|
||
- 193 个 fused RMSNorm。
|
||
- 193 个 quantized fused matmul/add。
|
||
- 144 个 MoE grouped dense。
|
||
- 96 个 KV scatter、RoPE、residual。
|
||
- 48 个 Flash Attention、router pre/post、SiLU、multiply、reduce。
|
||
|
||
MoE grouped dense 的权重 shape 包含 128 experts,例如 decode 第一层:
|
||
|
||
```text
|
||
gate/up weight: (128, 24, 128, 16, 8) U8
|
||
down weight: (128, 128, 24, 16, 8) U8
|
||
active input: (8, 2048) BF16
|
||
```
|
||
|
||
两芯粒都保留 128 experts 的矩阵分片,当前不是 expert parallel。
|
||
|
||
## 11. Prefill 动态 D2D
|
||
|
||
静态 ping 命令文本统计:
|
||
|
||
| 芯粒 | `dataSize` 项 | 总描述量 | 64 KiB | 32 KiB | 1 KiB |
|
||
| --- | ---: | ---: | ---: | ---: | ---: |
|
||
| chip0 | 444,610 | 18.979 GiB | 245,760 | 122,880 | 75,968 |
|
||
| chip1 | 444,608 | 18.822 GiB | 245,760 | 122,880 | 75,968 |
|
||
|
||
chip0 另有一次 160 MiB 和一次 160 KiB 描述。Prefill helper `libcpu_x86.so` 的唯一业务导出是 `Process`;结合 `dynamic_d2d=true`,实际运行会按当前序列长度生成或裁剪任务。
|
||
|
||
因此后续优化应测:
|
||
|
||
- 实际 prompt 长度与 D2D 命令数/字节的关系。
|
||
- 每层 gather/reduce 中哪类数据占主导。
|
||
- 64 KiB/32 KiB 块的有效带宽和同步空洞。
|
||
- 动态 helper 的 CPU 时间是否计入 `framework unknown`。
|
||
|
||
## 12. Metadata 质量问题
|
||
|
||
| 问题 | 当前证据 | 风险 |
|
||
| --- | --- | --- |
|
||
| Prefill `smodel_type=llm_decode` | prefill submodel memory 文件 | 不能可靠按类型调度 |
|
||
| tokenizer 131072 vs model 40960 | tokenizer_config 与 config/calbin | API 可能接受超上限请求 |
|
||
| `device_memory_required` 单位错误 | model memory 文件 | 自动 admission control 不可信 |
|
||
| `tarChipN` 为空 | CalRT 解析实测 | 拓扑自检不足 |
|
||
| workload 曾报告为 0/不一致 | parser 输出与文件字段 | 调度成本模型不可用 |
|
||
| 仅靠名称子串选模型 | llama-calrt.cpp | 多变体时可能选错 |
|
||
| tile `D0=16` 在 C++ 硬编码 | llama-calrt.cpp | 新编译器/layout 易回归 |
|
||
|
||
建议新增版本化 manifest,至少包含:schema version、model role、I/O 语义名、shape bucket、dtype/layout/tile、batch、context、KV layout、chip topology、compiler/runtime/driver compatibility、calbin hash、golden hash、量化方案和采样输出模式。
|
||
|
||
## 13. 容量推导与部署含义
|
||
|
||
在当前双芯粒大模型上:
|
||
|
||
- 参数和最大 KV 已占据大部分 32 GiB 板级 DRAM。
|
||
- Prefill 地址计划接近每芯粒 reservation 上限。
|
||
- 第二个同规模模型不可能同时常驻。
|
||
- 小型 embedding/reranker 是否可与主模型共存,必须基于 per-chip 可用 DRAM/SRAM 和 Runtime 是否支持多个已配置 calbin 实测。
|
||
- 动态卸载/加载的核心成本不是文件读取,而是参数 H2D、configure、ELF/命令部署、KV 清理和服务停顿。
|
||
|
||
对 batch N 的 KV 粗略容量:
|
||
|
||
```text
|
||
BF16 KV = 3.75 GiB x N (40960 context,全槽满载)
|
||
```
|
||
|
||
因此 batch 4 的最大上下文 BF16 KV 理论上需 15 GiB/板,仅 KV 就会挤压参数和 workspace。真正 batch 设计必须使用共享总 token budget、较短 slot context、paged/block KV 或 V-cache 量化,不能简单复制 batch=1 的 40960 全容量。
|
||
|
||
## 14. 可复算方法
|
||
|
||
工作区提供的只读分析脚本:
|
||
|
||
```bash
|
||
ruby work/analyze_calculet_artifacts.rb \
|
||
<model-dir>/*_op_io_buf_ptr.yaml \
|
||
<model-dir>/*prefill*/pld_cpu_chip0_runtime_cmds_ping.txt \
|
||
<model-dir>/*prefill*/pld_cpu_chip1_runtime_cmds_ping.txt
|
||
```
|
||
|
||
脚本只读取 YAML/命令文本,计算地址区间并集、命令条数、字节总量和块大小直方图,不修改模型产物。
|