# 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 \ /*_op_io_buf_ptr.yaml \ /*prefill*/pld_cpu_chip0_runtime_cmds_ping.txt \ /*prefill*/pld_cpu_chip1_runtime_cmds_ping.txt ``` 脚本只读取 YAML/命令文本,计算地址区间并集、命令条数、字节总量和块大小直方图,不修改模型产物。