Files
calculet-npu-research-archive/reports/Calculet-NPU-模型产物与内存映射-20260802.md

12 KiB
Raw Permalink Blame History

Calculet NPU 模型产物与内存映射

日期:2026-08-02
模型:Qwen3-30B-A3B dynamic W8A8/W4AF16,双芯粒,40960 contextFlash Attention

实施下钻:逐文件/逐字段 grammar、跨文件校验、严格拒绝条件和可执行检查器见《Calculet NPU calbin 产物字段字典与静态验收规范》及 calculet_package_validate.rb。本文保留容量和映射分析,字段字典负责新包验收。

1. 路径与范围

本文的模型根目录是:

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 编译:

/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

316f06e7e316b1305486118fa7da65f816b61deb46de09a2f4fec6979530456c

编译版本:

  • calcc575c2d708e306a60f10bc34f5087477073b58caa
  • TVM7aebd1c21fa67d942a1fd93e39e8a67007f91c0c
  • with_codegen=true
  • with_op_case=true
  • with_c_oplib=true
  • use_auto_alloc=true
  • enable_flash_attention=true
  • enable_one_token=true
  • chip 数 2CalCore 数 2/芯粒

has_loaded_onnx=falsehas_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/0xc0028000163840 B
inputs[1] position [1,40960] INT32 ping/pong 0xc0050000/0xc0078000163840 B
outputs[0] logits [1,1,151936] BF16 ping/pong 0x367b21000/0x367b6c000303872 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/0x08e61c004 B
inputs[1] position [1,1] INT32 ping/pong 0xc0000000/0xc00010004 B
outputs[0] logits [1,1,151936] BF16 ping/pong 0xc0002000/0xc004d000303872 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=40959decode cur=1,total=40960

6. 参数映射

文件大小

文件 精确字节 GiB 芯片掩码
param_blk0.bin 9,404,557,312 8.759 0x1chip0
param_blk1.bin 8,782,227,456 8.179 0x2chip1
合计 18,186,784,768 16.938 双芯粒

按 memory reservation 段求和

芯粒 DRAM 映射 SRAM 窗口映射 合计与文件关系
chip0 9,389,477,888 B8.745 GiB 15,079,424 B14.381 MiB param_blk0.bin 精确闭合
chip1 8,767,148,032 B8.165 GiB 15,079,424 B14.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 1K/V 各一份。

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 个,所以每芯粒为:

2,013,265,920 bytes = 1.875 GiB

Decode op 地址图中最大的 activation 连续区间是:

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 第一层:

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 粗略容量:

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. 可复算方法

工作区提供的只读分析脚本:

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/命令文本,计算地址区间并集、命令条数、字节总量和块大小直方图,不修改模型产物。