Files
calculet-npu-research-archive/reports/Calculet-NPU-双芯粒双模型独立服务可行性与实施规格-20260802.md

36 KiB
Raw Permalink Blame History

Calculet NPU 双芯粒双模型独立服务可行性与实施规格

日期:2026-08-02
基线:CalRT 0.7.6、llama.cpp fd9bd632、一张 PCIe 板、两个芯粒、每芯粒两个 CalCore
目标:chip0 常驻模型 A,chip1 常驻模型 B;每个模型的 prefill 和 decode 全部在自己的芯粒完成,两个模型同时对外提供服务

0. 执行结论

这个目标需要先澄清“核心”的含义:

“核心”指什么 当前结论 原因 状态
每芯粒内的一个 CalCore/CCU 当前不可直接实现 完整图会为同一芯粒同时生成 ccu0ccu1 程序;公开 API 没有 CalCore affinity、独立配置、内存配额或 reset domain C4(0.7.6 公共能力)/C3(需厂商新能力)
板上的一颗芯粒 架构上可行,当前不能直接上线 calbin 已有单/多芯粒描述和 chip mask,但缺少单芯粒完整模型产物,以及双 session/队列/KV/reset 的正式隔离契约 C3

因此,建议把目标正式定义成:

chip0: Model A = A.prefill + A.decode + A.params + A.KV + A.workspace
chip1: Model B = B.prefill + B.decode + B.params + B.KV + B.workspace

不是:

CalCore0: Model A
CalCore1: Model B

推荐两条实现路径:

  1. 最短硬件验证路径:厂商组合 calbin。 由 compiler 在一个 calbin 内统一放入 A/B 四个子图,A 的所有 section 只带 chip0 maskB 只带 chip1 mask;整个 calbin 只 configure 一次,再按 CalbinModel* 提交。它最贴近 0.7.6 的“单 current calbin”模型,但能否真正双芯粒并行仍需厂商 runner 和 trace 证明,状态 C3。
  2. 正式产品路径:Runtime chip session。 Runtime 显式提供 chip_session/model_handle/job_handle,每颗芯粒独立 load、quota、queue、KV、health、drain、unload 和 reset。服务层再实现两个 ModelWorker 和一个 Router,状态 C3。

当前 Qwen3-30B-A3B 双芯粒产物不能通过删文件、改 mask 或只传 chipId 改成两个单芯粒模型;该产物本身是逐层双芯粒 tensor parallel。第一轮应选择 1B-3B、decoder-only、dense、4K/8K context 的模型,优先选择厂商已有算子覆盖、与现有模型架构接近的模型。

1. 状态和验收口径

状态 本文使用规则
C0 当前源码、产物或样机记录直接证明
C1 0.7.6 头文件/符号存在,但生产未接入或未测
C2 我方能用已确认接口实现,仍需开发和硬件验收
C3 需要厂商 compiler、Runtime、kernel 或新 calbin
C4 当前接口明确不支持,或不应作为产品路径

“两个模型同时服务”再分两层:

等级 定义 本项目目标
S1 服务并存 两个 alias 同时 Ready,能同时接收请求,但板内可能串行执行 中间里程碑
S2 硬件并发 chip0/chip1 的计算区间真实重叠,联合吞吐接近两颗芯粒隔离运行之和 最终目标

只有 Router 同时暴露两个模型不能证明 S2。必须通过 per-chip trace、任务时间线和联合吞吐证明硬件重叠。

2. 当前证据为什么支持这个判断

2.1 板卡是一个 PCIe 设备,不是两个独立设备

保存的 lspci 只看到一项 Calculet 设备 01:00.0,由 calculet 驱动管理。CalRT 0.7.6 的 VirtualDevice 头文件也明确写着“temporary only support one physical device”,内部只有一个 m_phyDevices

这意味着:

  • 两颗芯粒是同一物理设备内部资源。
  • 不能用“两个 PCIe device id + 两个进程”绕过 Runtime 隔离问题。
  • 在厂商确认前,不允许两个进程分别打开同一设备并各自 configure 一个 calbin;全局配置、地址和 reset 可能互相覆盖。

2.2 CalCore 是编译器执行单元,不是应用可分配的模型槽

当前 prefill 和 decode 各包含四个 ELF

ccu0_chip0.elf  ccu1_chip0.elf
ccu0_chip1.elf  ccu1_chip1.elf

根 manifest 对两个子图都声明:

device_cfg:
  chip_nums: 2
  calcore_num: 2

所以一个完整子图在每颗芯粒上会同时使用两个 CalCore。calcore_num: 2 只能证明 codegen 生成了两个执行程序,不能证明应用能把两个 host job 分别绑定到两个 CalCore。

公开 API 的 TASK_PING/TASK_PONG 是 job engine/bank 选择,不是 CalCore0/CalCore1 亲和性。SubmitJob() 也没有 core_id

2.3 calbin 有芯粒描述能力,但不等于多模型隔离已经可用

0.7.6 头文件包含:

  • ModelChipMode_e { SCHIP, MCHIP }
  • CalbinModel::tarChipN
  • 每个 CalbinSection_s::chipMask
  • TaskInfo_s::m_taskChipArchSINGLE_CHIP_TASK/MULTIPLE_CHIP_TASK
  • ReadMem/WriteMem(..., chipId) 和 remote chip memory API。

这些是单芯粒编译和按芯粒部署的有力线索,但不能证明:

  • 两个模型可以同时 configure。
  • 两个 job queue 独立。
  • KV manager 按模型/芯粒隔离。
  • reset 一颗芯粒不会影响另一颗。
  • 两个线程或进程可以同时提交而无全局锁。

2.4 0.7.6 仍是单 current-calbin 设备状态

CalrtDevice 当前只有:

Calbin *pmCurrentCalbin
uint64_t mCurCalbinHash
SetConfigModel(Calbin*)
GetCurrentCalbinOnDevice()

configure(VirtualDevice*, Calbin*) 对整个 calbin 生效,SubmitJob(model, input, output, engine) 虽选择子模型,但没有 chip_sessionmodel_handlememory_quotareset_scope

这正是组合 calbin 可能成为短期路径的原因:A/B 可以由 compiler 放进同一个全局 calbin;也是不能由应用随意加载两个独立 calbin 的原因。

2.5 当前生产适配层只有一个设备、一个 calbin、一个 KV manager

calrt_context 只持有一份:

VirtualDevice
Calbin
KvManager
prefill/decode backing vectors

当前请求路径按第一个 ubatch 选择 prefill/decode,创建 bufferinfer() 后立即 Wait();多个 sequence 仍逐个提交。生产代码没有 model instance、chip worker、独立 KV namespace 或双模型 router。

历史 origin/runtime_replace 分支也只有一个 CalrtEngineConfig.calbin_path 和一个 EngineCore 实例,不能作为双模型已实现的证据。

3. 当前模型为什么不能直接拆开

当前 Qwen3 产物的关键事实:

项目 当前值 含义
参数块 16.938 GiB 合计 chip0 8.759 GiBchip1 8.179 GiB,是张量分片,不是两套完整权重
BF16 KV 3.750 GiB 合计 与 48 层、4 KV heads、40960 context 对应
DRAM reservation 14.075 GiB/芯粒地址计划(推断) 已接近可能的单芯粒本地容量,物理口径仍需厂商确认
图分配 两颗芯粒都覆盖 48 层 attention/MoE 当前是逐层 tensor parallel
通信 每层 gather/reduce/syncprefill 有 dynamic D2D 删除另一芯粒后图不完整
batch 1 不能由服务端聚合自动变成硬件 batch

以下做法全部禁止:

  • param_blk0.bin 当成 chip0 的完整模型,把 param_blk1.bin 当成 chip1 的另一个模型。
  • 删除 chip1 ELF/command 后运行 chip0。
  • 手工把 section 的 mask 从 3 改成 12
  • 把两套模型目录拼到一起并改子图名。
  • 创建两个进程分别 configure 同一物理板。
  • ReadMem(..., chipId) 推断 job 也能按 chip 独立提交。

这些操作会破坏权重、通信、同步、地址和命令流的一致性,轻则配置失败,重则错误输出、DMA 越界或整板 reset。

4. 推荐目标架构

flowchart LR
    C["OpenAI-compatible clients"] --> R["Model Router"]
    R -->|"model=A"| WA["ModelWorker A"]
    R -->|"model=B"| WB["ModelWorker B"]

    WA --> QA["A admission/queues"]
    QA --> KVA["A KV manager"]
    QA --> BFA["A buffer pool"]
    KVA --> SA["chip0 session"]
    BFA --> SA

    WB --> QB["B admission/queues"]
    QB --> KVB["B KV manager"]
    QB --> BFB["B buffer pool"]
    KVB --> SB["chip1 session"]
    BFB --> SB

    SA --> DS["One DeviceSupervisor / one board"]
    SB --> DS
    DS --> NPU["Calculet NPU: chip0 + chip1"]

硬约束:

  • 进程内只有一个 DeviceSupervisor 拥有板卡生命周期。
  • 每个 ModelWorker 只访问自己的 session、KV、buffer、队列和 generation。
  • Router 按稳定 model_alias 路由,不把 chip_id 暴露给普通客户端。
  • 默认模型 A/B 都各自包含 prefill 和 decodesequence 不跨芯粒迁移。
  • 任何提交都带 model/session 身份,不能依赖“当前 calbin”隐式选择。
  • 如果 Runtime 只能组合 calbinDeviceSupervisor 负责唯一 configure;两个 worker 只能借用其中已绑定 chip mask 的子模型。

5. 三条实现路径对比

路径 0.7.6 适配度 改动 优点 主要风险 建议
A. 厂商组合 calbin 最高 compiler 生成 A/B 统一地址计划;我方单 DeviceSupervisor + 双 worker 避开多 current-calbin;最快证明芯粒并发 unload 粒度可能是整包;queue/reset 是否隔离未知 第一优先 PoCC3
B. Runtime chip session 需新版本/API Runtime、driver 和我方适配层共同升级 生命周期清楚,可独立 load/unload/quota/reset 厂商开发量最大,ABI/兼容性风险 正式产品目标,C3
C. 两张物理板各一模型 0.7.6 头文件仍称单物理设备 新多设备选择 API,或两台主机 隔离最强,运维简单 需要第二张板;0.7.6 多板 API 不完整 业务兜底,C3/C4

不采用“同一板两个进程各占一个芯粒”。在芯粒被 Runtime 显式虚拟化成可独占设备之前,这种方案没有安全边界。

6. 路径 A:组合 calbin 的精确要求

6.1 逻辑内容

一个组合包至少包含四个业务子图:

model_a.prefill -> tarChipN=[0], SCHIP
model_a.decode  -> tarChipN=[0], SCHIP
model_b.prefill -> tarChipN=[1], SCHIP
model_b.decode  -> tarChipN=[1], SCHIP

以及每个模型独立的:

  • 参数块和参数映射。
  • KV 地址、容量、sequence id namespace。
  • prefill/decode workspace。
  • input/output/CSR metadata。
  • chip-local ccu0/ccu1 ELF。
  • CPU/PLD ping/pong command。
  • golden input/output、tokenizer、模型配置和 hash。

“A 在 chip0”不代表 A 只使用 ccu0。单芯粒 A 仍可由 compiler 同时使用 chip0 的两个 CalCoreB 同理。

6.2 compiler 必须统一解决的内容

  1. A/B 的虚拟地址允许在不同芯粒使用相同数值,但 mask、DMA route 和 host mapping 必须无歧义。
  2. 同一芯粒内 A.prefill/A.decode 可以按生命周期复用 workspace;A 与 B 不能共享可写状态。
  3. 两模型的 KV base、sync unit、job id 和 completion 信息必须独立。
  4. A 的任何 section 不得带 chip1 maskB 反之。
  5. 不得生成跨模型或跨芯粒 gather/reduce/D2D。
  6. prefill/decode 的 tensor shape、dtype、CSR、batch、context 必须分别写入 manifest。
  7. 组合包必须由 compiler/packer 正式生成,不能由我方脚本拼接。

6.3 建议目录合同

dual-model-calbin/
  manifest.yaml
  model_memory_reserved_info.txt
  model-a/
    prefill/...
    decode/...
    params/...
    golden/...
  model-b/
    prefill/...
    decode/...
    params/...
    golden/...
  tokenizer/model-a/...
  tokenizer/model-b/...
  checksums.sha256
  compatibility.json
  build-provenance.json

实际文件名可沿用厂商 schema,但 manifest 必须能无字符串模糊匹配地确定:alias -> prefill/decode -> chip -> profile

6.4 组合 calbin runner

PoC runner 必须只做以下固定流程:

CreateVDevice(PCIE)
CreateCalbin(combined_path)
validate exact four model names and chip targets
configure(vdev, combined_calbin) exactly once
create A/B independent input/output buffers
run A golden, run B golden
run A+B concurrent submissions with separate buffers
Wait both, verify output and per-chip trace
drain, ResetConfiguration, release

SubmitJob/infer 没有 chip 参数,所以 chip 选择必须完全来自经过签名/校验的 CalbinModel metadata。runner 启动时发现任何模型 mask 越界、跨 chip section 或名字重复,应在 configure 前退出。

7. 路径 BRuntime chip session 的最小 API 契约

建议厂商提供等价于下面的能力;具体命名可以不同,但语义不能缺失:

struct ChipSessionOptions {
    uint32_t chip_id;
    uint64_t dram_quota_bytes;
    uint64_t sram_quota_bytes;
    uint32_t max_inflight;
};

Topology QueryTopology(DeviceHandle);
ChipSessionHandle CreateChipSession(DeviceHandle, ChipSessionOptions);
ModelHandle LoadModel(ChipSessionHandle, const CalbinPath&, LoadOptions);
JobHandle Submit(
    ChipSessionHandle,
    ModelHandle,
    GraphKind,            // prefill | decode
    InputBufferHandle,
    OutputBufferHandle,
    JobOptions);
JobStatus Query(JobHandle);
Status Wait(JobHandle, Deadline);
Status Cancel(JobHandle); // 必须明确是否只取消交付,还是终止设备执行
Status Drain(ChipSessionHandle, Deadline);
Status Unload(ModelHandle);
Status ResetSession(ChipSessionHandle);
MemoryUsage GetMemoryUsage(ChipSessionHandle);
Health GetHealth(ChipSessionHandle);

7.1 必须写进正式契约的语义

契约 必须回答的问题
地址空间 两 session 可否使用相同 vaddrIOMMU/DMA 如何区分;host mapping 生命周期
configure chip0 load 是否会改变 chip1 的 current model、命令表或 sync unit
提交 两线程并发 Submit 是否线程安全;每芯粒最大 in-flight;完成顺序
队列 全板共享队列还是 per-chip queue;是否存在全局 head-of-line blocking
KV key 必须含 (session, model_generation, sequence_id);失败后的 commit/rollback
内存 quota 的硬/软语义;allocation 失败是否只影响本 session
reset CCU/session/chip/device 四种 reset 各影响哪些任务、KV、参数和另一芯粒
unload 只释放目标 model/session;在途 DMA 未完成时必须拒绝或 drain
错误 timeout/crash/invalid calbin 的污染范围和恢复顺序
观测 per-chip 温度、功耗、频率、内存、queue、job、trace 的单位和时钟

若 Runtime 只有 ResetConfiguration() 和整板 Reset(),两个模型可以做到并发服务,但不能宣称具备强故障隔离;任一模型故障可能导致两个 alias 同时摘流。

8. 模型选择和内存预算

8.1 容量不是只看参数文件

每颗芯粒的稳态预算至少为:

M_required = W_compiled
           + KV(batch, context)
           + workspace_peak(prefill, decode)
           + code_and_commands
           + input_output_staging
           + runtime_metadata
           + allocator_fragmentation
           + safety_guard

BF16 KV 的理论下界:

KV_bytes = 2(K,V)
         * n_layers
         * n_kv_heads
         * head_dim
         * context_tokens
         * batch_or_active_sequences
         * bytes_per_element

真实值还受 layout、对齐、batch lane、page/block 和 compiler reservation 影响,最终只能以新 calbin 的 metadata 加设备实测为准。

8.2 推荐安全线

在厂商没有提供可靠 per-chip memory API 前:

  • 不以 GetMemoryUsage() 的总量字段做容量承诺。
  • 静态 M_required 不超过厂商确认的本地 DRAM 的 75%-80%。
  • 至少保留 max(1 GiB, 15% local DRAM) 作为 Runtime、碎片、瞬时 workspace 和恢复余量。
  • 以 prefill 峰值 workspace 而非 decode 常态决定是否可部署。
  • A/B 分别验算,不能拿整板 32 GiB 作为任一芯粒可独占容量。

当前 14.075 GiB/芯粒 reservation 已说明大模型地址计划非常紧;当前 Qwen3 不适合作为单芯粒完整模型候选。

8.3 第一轮模型范围

推荐:

维度 第一轮选择 原因
架构 decoder-only dense 去掉 MoE router/expert 和跨芯粒通信变量
参数规模 1B-3B 为权重、KV、workspace 和并发留余量
context 4K,随后 8K 快速闭环,再扩大 KV
batch B1 先证明双芯粒隔离;B4/B8 是后续独立课题
量化 厂商已有稳定 W8A8;必要时比较 W4 避免模型、量化、双模型同时引入未知量
tokenizer 各模型独立 避免 alias 路由到错误词表

若希望先隔离“不同模型算子覆盖”变量,Phase 2 应先把同一个小模型复制到两颗芯粒;通过后再换成不同模型 A/B。

8.4 容量验收表

每个模型必须提交并实测:

静态来源 运行验证
参数 parameter map/文件区间 load 前后 per-chip memory delta
KV/sequence config 公式和 reservation 1/2/... active sequence 增量
workspace compiler peak report prefill/decode 峰值采样
code/command section 文件和映射 configure delta
allocator 碎片 不可纯静态确定 100 次 load/unload 后回落
guard 项目策略 OOM 前必须 admission reject,不允许设备 crash

9. 每芯粒的 prefill/decode 调度

9.1 同一模型的基本顺序

一个 sequence 永远遵循:

Queued -> PrefillReady -> PrefillRunning -> DecodeReady
       -> DecodeRunning -> DecodeReady ... -> Completed

prefill 成功后才提交第一次 decode;KV 更新使用 reserve -> submit -> commit/rollback。任务失败或取消不能立即复用仍被 DMA 引用的 buffer。

9.2 每个 ModelWorker 的队列

decode_ready_queue       高优先级,降低 TPOT
short_prefill_queue      例如 <=512 token
medium_prefill_queue     例如 <=4096 token
long_prefill_queue       低优先级但必须防饥饿

每个 worker 独立做 admission

  • 最大等待请求数。
  • 最大等待 prompt token 数。
  • KV 可分配量。
  • 请求 deadline。
  • 模型 context/batch profile。
  • 当前 chip health 和 generation。

模型 A 过载只能返回 A 的 429/503,不应阻塞模型 B 的 admission。

9.3 长 prefill 对 decode 的影响

即使 A/B 在不同芯粒,单个模型内部仍可能被长 prefill 阻塞 decode。只有 compiler/Runtime 明确支持 chunked prefill、抢占或安全 ping/pong 时才能切分/重叠。第一版采用:

  • decode 优先。
  • 限制长 prefill 的 admission 和并发数。
  • 不擅自把一个 prompt 拆成多个 prefill 图调用。
  • 每颗芯粒初始 max_inflight=1;完成独立 buffer 和 ping/pong 验证后才升到 2。

9.4 两芯粒并发的四种干扰组合

必须分别测:

chip0 chip1 主要观察
A prefill B prefill DRAM/DMA/功耗峰值、TTFT
A prefill B decode 长任务是否拖慢 B 的 TPOT
A decode B prefill 对称性、共享队列偏置
A decode B decode 稳态吞吐、带宽、温度、频率

两颗芯粒可能共享 PCIe、板级功耗/散热和部分 Runtime 锁,因此即使计算单元独立,也不能假定联合性能等于孤立性能简单相加。

10. 服务层实施规格

10.1 对外接口

保持 OpenAI-compatible model 字段路由:

GET  /v1/models
POST /v1/chat/completions   body.model = "model-a" | "model-b"
POST /v1/completions        body.model = "model-a" | "model-b"
DELETE /internal/requests/{request_id}

GET /v1/models 只在对应 worker 完成 configure、golden 和 warmup 后返回 Ready。普通接口不暴露 chip id、calbin 路径、虚拟地址、寄存器或 reset。

10.2 内部对象

DeviceSupervisor
  board_handle
  topology
  lifecycle mutex
  chip_sessions[2]
  board health/recovery

ModelWorker
  model_alias
  chip_id
  model_generation
  prefill/decode graph handles
  tokenizer/config
  admission controller
  scheduler queues
  KV manager
  buffer pools
  submit/completion workers
  health and metrics

RequestContext
  request_id/model_alias/generation
  sequence_id/deadline/cancel
  prompt/output counters
  KV transaction
  current JobContext

JobContext
  session/model/graph/job handles
  exclusive input/output/backing storage
  CSR snapshot
  submit/deadline/status/timings

10.3 锁和所有权

  • DeviceSupervisor.lifecycle_mutex 只用于 load/unload/reset,不包住正常 Wait()
  • A/B 各有 scheduler mutex;绝不同时持有两个 worker mutex。
  • JobContext 从 prepare 到 completion 独占 host backing memory。
  • KV commit 发生在 OutputBuf 完成且输出有效之后。
  • reset 增加 session/device generation;旧 generation 的 completion 只能被丢弃,不能写入新请求。
  • Router 只保存 worker 的稳定引用,不直接持有 Runtime handle。

10.4 建议配置

schema: calculet-dual-model/v1
device:
  type: pcie
  expected_chips: 2
  combined_calbin: /models/dual-a-b
models:
  - alias: model-a
    chip_id: 0
    prefill_graph: model_a_prefill
    decode_graph: model_a_decode
    context_limit: 4096
    max_inflight: 1
    max_waiting_requests: 64
  - alias: model-b
    chip_id: 1
    prefill_graph: model_b_prefill
    decode_graph: model_b_decode
    context_limit: 4096
    max_inflight: 1
    max_waiting_requests: 64
recovery:
  allow_session_reset: false
  restart_process_on_unknown_dma: true

loader 必须将配置与签名 manifest 交叉验证。chip、graph、context、batch、tensor 或 hash 不一致时启动失败,不能自动猜测或按子字符串匹配。

11. 生命周期和故障状态机

11.1 单 worker 生命周期

stateDiagram-v2
    [*] --> Unloaded
    Unloaded --> Validating: load
    Validating --> Configuring: manifest/hash/compat pass
    Validating --> Failed: reject
    Configuring --> Warming: configure succeeds
    Configuring --> Failed: configure fails
    Warming --> Ready: golden + warmup pass
    Warming --> Failed: mismatch/fault
    Ready --> Draining: unload/replace/session fault
    Draining --> Unloading: in-flight=0
    Draining --> Recovering: deadline/unknown DMA
    Unloading --> Unloaded: memory released
    Recovering --> Warming: scoped reset + reload
    Recovering --> Failed: reset scope unknown/fails

11.2 组合 calbin 的特殊限制

组合 calbin 很可能只能整包 configure/reset。此时 A/B 的逻辑状态虽独立,但物理生命周期如下:

任一模型需要重新 configure
  -> Router 同时停止 A/B admission
  -> drain 两个 worker
  -> 整包 ResetConfiguration
  -> configure 新组合包
  -> 分别 golden/warmup
  -> 两者都 Ready 后恢复接流

不能在没有 Runtime 保证时只释放 A 的 Calbin/buffer 并让 B 继续提交。

11.3 故障范围

故障 默认隔离范围 动作
非法输入/shape/context request 提交前 400,不碰设备
A admission/KV 满 A worker A 有界排队后 429/503B 正常
submit DeviceBusy 对应 queue,待确认 有界 backoff,不立刻 reset
输出数值不符 model generation 摘目标 alias;若共享配置不确定则摘 A/B
Wait timeout/CCU exception session 或全板未知 停止新提交、drain、保存 trace,按厂商契约 reset
chip-scoped reset 失败 device 两个 alias 摘流,进程/设备恢复
板级 reset/驱动异常 device A/B 同时 503,重建全部 generation

在故障注入证明之前,所有 Runtime timeout/crash 按“可能污染整板”处理。

12. 分阶段执行计划

Phase 0:冻结合同和基线

输入:当前 SDK、板卡、服务、模型和性能 harness。
工作:

  1. 固定 driver/firmware/CalRT/compiler/calbin/server 的版本与 hash。
  2. 获取 per-chip DRAM、SRAM、队列、reset topology 的书面口径。
  3. 建立 model_alias -> graph -> chip mask 的版本化 manifest schema。
  4. 对现有单模型跑正确 TTFT/TPOT、功耗、温度、内存和 1h 稳定性基线。

出口:版本可重放,设备健康,旧模型行为可对比。当前可做,C0/C2。

Phase 1:单芯粒单模型

输入:厂商提供一个单芯粒小模型 calbin。
工作:

  1. 静态校验 SCHIP、mask、ELF、command、参数、KV、地址和 hash。
  2. chip0 configurechip1 保持空闲。
  3. 跑 prefill/decode golden、1/16/512/4K prompt 边界和 32/128 token 输出。
  4. 用 trace 证明只在 chip0 执行,无跨芯粒 D2D。
  5. 重复 chip1 版本,验证对称性。

出口:两颗芯粒分别能独立完成同一模型的 prefill+decode。C3 -> 实测后 C0。

Phase 2:同一模型复制到两芯粒

输入:组合 calbin 或两个正式 chip session。
工作:

  1. A0 在 chip0、A1 在 chip1tokenizer和权重版本相同。
  2. 先串行 golden,再同时提交不同 prompt。
  3. 交叉使用不同 sequence id、不同长度和不同取消时机。
  4. 比较两侧输出和 reference,检查 KV、buffer、job completion 无串扰。
  5. 用 trace/时间线证明执行重叠。

出口:先证明资源隔离,不把不同模型算子覆盖混入问题。

Phase 3:两个不同模型

输入:模型 A/B 均已单独通过 Phase 1。
工作:

  1. A/B 各自 tokenizer、sampling config、context、KV 和 buffer pool。
  2. 跑四种 prefill/decode 干扰组合。
  3. open-loop 分别压 A、B 和联合压测,验证各自 backpressure。
  4. A 过载、取消、非法请求时检查 B 的成功率和 P99。
  5. 分别验证 load/warmup/ready;组合 calbin 则验证整包生命周期。

出口:S1 服务并存与 S2 硬件并发都通过。

Phase 4:故障隔离

输入:厂商书面 reset/error 契约。
工作:

  1. 注入 A 的 invalid tensor、KV exhausted、submit busy、Wait timeout、CCU exception。
  2. 注入 A 的 drain deadline 和 unload/reload。
  3. 检查 B 是否继续生成、延迟是否在门槛内、KV 是否不变。
  4. 分别测试 session/chip/config/device reset。
  5. 若任何故障实际影响全板,将产品能力降级为“共享故障域”,并按 A/B 同时摘流设计。

出口:故障域有实测结论,不以 API 名称猜测隔离。

Phase 5:生产化和 24h soak

工作:

  1. 补齐 Router、鉴权、限流、metrics、trace、审计和 health。
  2. 混合流量 1h、8h、24h;记录功耗/温度/频率和内存回落。
  3. 100 次 load/unload;组合 calbin 跑 100 次整包切换。
  4. 灰度、自动降级、旧 generation 回滚和冷启动测试。

出口:满足第 13 节门槛后才对外声明双模型并发。

13. 验收矩阵和建议门槛

下面是第一版工程门槛;业务 SLA 更严格时取更严格值。

13.1 正确性

项目 通过条件
单模型 golden 厂商定义的 logits tolerance/top-k/token 序列全部通过
A/B 并发 至少 1000 请求无跨模型 token、logits、KV、sequence id 串扰
tokenizer alias 与 tokenizer/hash 一一匹配,错配启动失败
context 边界 0、max、max+1 在提交前正确处理,无越界提交
cancel 取消只停止结果交付;在途 buffer 等待完成后回收
generation reload 后旧 completion 不得交付给新 generation

13.2 并发和性能

定义:

T_serial = T(A isolated workload) + T(B isolated workload)
T_joint  = wall time when A and B workloads run together
overlap_ratio = 1 - T_joint / T_serial

throughput_efficiency = joint_successful_tokens_per_s
                      / (A_isolated_tokens_per_s + B_isolated_tokens_per_s)

建议通过条件:

  • per-chip trace 显示 A/B compute 区间真实重叠。
  • overlap_ratio > 0 且置信区间不跨 0;不能只看一次运行。
  • 稳态 throughput_efficiency >= 0.80
  • 联合负载下每个模型 P99 TTFT/TPOT 相比各自隔离基线退化不超过 25%。
  • A 满载时 B 的成功率不低于 99.9%,除非触发明确的板级热/电/故障保护。

若吞吐未达门槛,先区分 compiler、共享 DMA、全局 Runtime 锁、功耗降频和服务调度,不能直接归因于芯粒算力。

13.3 生命周期和稳定性

  • 100 次 load/unload 或整包 reconfigure 无泄漏、无 AlreadyConfigured、无旧 generation 完成。
  • 24h 混合 soak 无 crash、hang、错误 token 或未知状态。
  • 空闲恢复后设备内存回到基线;稳定漂移小于 max(64 MiB, 1% local DRAM)
  • pending/finished/left job counters 最终闭合。
  • timeout 和 reset 后必须重新 golden+warmup 才能 Ready。
  • A 队列/KV 满不使 B 的 queue depth、admission 或错误率同步恶化。

13.4 故障隔离等级

等级 能力
F0 任一 Runtime 故障都需要整板恢复;A/B 同时摘流
F1 请求和资源耗尽隔离,但 CCU/timeout/reset 共享故障域
F2 session/chip reset、unload 和 KV 污染均不影响另一模型

组合 calbin 很可能先达到 F1;只有逐项故障注入通过后才能声明 F2。

14. 指标和日志

每条请求:

request_id, model_alias, model_generation, chip_id(internal only),
prompt_tokens, output_tokens, queue_ms, ttft_ms, tpot_ms, e2e_ms,
finish_reason, error_class

每个 job

job_id, session_id, model_generation, graph(prefill|decode),
engine(auto|ping|pong), submit_ns, done_ns,
h2d_ms, infer_ms, d2h_ms, output_status,
kv_before, kv_after, reset_generation

每颗芯粒:

memory_used/total, queue_depth, in_flight, completed, failed,
temperature, power, frequency, throttle, reset_count

取不到的 per-chip 指标写 null 并列入厂商缺口,不能用 0 或整板值冒充。request_id/job_id 进入 log/trace,不作为 Prometheus 高基数 label。

15. 厂商必须交付的 P0 清单

15.1 compiler/calbin

  1. 一个 1B-3B dense 模型的 chip0 单芯粒 calbin,含 prefill/decode、参数、KV、workspace、golden 和 tokenizer。
  2. 同一模型的 chip1 对称版本。
  3. 同模型双副本组合 calbin,用于先验证隔离。
  4. 两个不同模型 A/B 的组合 calbin。
  5. 每个包的 ONNX/hash、量化配置、compiler 容器/commit、完整命令和 compatibility matrix。
  6. 正式 manifest schema,明确 SCHIP/tarChipN/chipMask/calc_mchip 语义。
  7. 静态/峰值内存报告,分别列权重、KV、workspace、code、command、I/O 和 guard。
  8. 证明单芯粒图无跨芯粒 D2D/gather/reduce 的 compiler report。

15.2 Runtime/driver

  1. CalbinModel 的 chip target 如何驱动 configure 和 SubmitJob。
  2. 一个 calbin 内两个 SCHIP 模型能否同时执行,以及官方最小 runner。
  3. per-chip queue、job id、completion、DMA 和 sync unit 是否隔离。
  4. 两线程同时向不同芯粒 Submit/Wait 的线程安全保证。
  5. per-chip DRAM/SRAM 的真实容量、预留和查询 API。
  6. KV manager 的 model/session namespace 和失败回滚语义。
  7. session/chip/config/device reset 的精确影响范围。
  8. 独立 load/unload 是否支持;若不支持,组合 calbin 整包生命周期的正式流程。
  9. per-chip trace/counter/temperature/power/frequency API 和时钟域。
  10. Runtime/driver/firmware/compiler/calbin 的版本兼容矩阵。

15.3 验收材料

  • 单模型孤立和双模型联合性能原始数据。
  • A/B 并发时间线,能看到 chip0/chip1 overlap。
  • 错误注入与 reset 影响范围报告。
  • 24h soak 报告和内存回落数据。
  • 已知限制:最大并发、context、batch、不可抢占、共享功耗/带宽和恢复限制。

只给两个单芯粒目录、没有组合 runner 和 reset/queue 契约,不足以开始产品接入。

16. 我方代码拆分

厂商 P0 产物到位后建议按以下 PR 推进:

PR 内容 依赖 退出条件
1 exact model manifest 和静态验证 单芯粒/组合样包 坏 mask/hash/shape 启动前拒绝
2 DeviceSupervisor + generation 生命周期 Runtime 契约 单 configure、可 drain/recover
3 ModelWorker 抽象,拆 tokenizer/KV/buffer/queue PR2 A/B 可独立单测
4 Router 按 alias 路由和 per-model admission PR3 A 过载不阻塞 B
5 JobContext、独占 buffer、异步 completion PR3 in-flight=1 无串扰
6 组合 calbin 双 worker 提交 厂商 runner 同模型双副本并发通过
7 不同模型 A/B 和 metrics/trace PR6 S1/S2 验收通过
8 故障注入、灰度、回滚、24h soak reset 契约 F0/F1/F2 等级落定

在厂商产物和 API 到位后,我方纯软件首个 PoC 约需 5-8 个工程日,完整故障/性能/24h 验收再需 5-7 个工程日。厂商 compiler/Runtime 新能力的交付周期目前无法从本地资料可靠估算,应让对方分别给组合 calbin 和 chip session 两条排期。

17. Go/No-Go 决策门

决策点 Go 条件 No-Go/降级动作
G0 单芯粒容量 静态预算和 load 峰值均留足 guard 缩模型/context/batch,禁止硬塞
G1 单芯粒正确性 chip0/chip1 分别 golden 通过 回到 compiler/kernel 调试
G2 双副本隔离 A0/A1 无 buffer/KV/job 串扰 不进入不同模型阶段
G3 S2 并发 trace overlap + 联合性能达标 只声明 S1,调查全局锁/共享瓶颈
G4 故障域 至少 F1,恢复流程确定 两 alias 绑定同一健康状态并同时摘流
G5 生产 24h、100 次生命周期、回滚通过 保留单模型或两板方案

18. 最终建议

  1. 把需求名称改为“双芯粒双模型独立服务”,不要写“每个 CalCore 一个模型”。
  2. 立即向厂商索取“同一小模型双副本组合 calbin + 官方并发 runner”;这是最少变量、最快验证硬件隔离的路径。
  3. 第一轮用 1B-3B dense、B1、4K context;先 chip0/chip1 单独跑,再双副本,最后不同模型。
  4. 产品架构从一开始按两个 ModelWorker 设计,但板卡只由一个 DeviceSupervisor 管理。
  5. 若厂商确认 0.7.6 组合 calbin 能独立 dispatch,则先以它达到 S2/F1;独立 load/unload 和 F2 继续要求 chip session API。
  6. 如果厂商不能提供组合 calbin或芯粒级 queue/dispatch,当前单板方案 No-Go;业务上改用两张板/两台主机,每板一个模型。

19. 证据入口

本文只使用已下载到本地的 SDK、产物、源码和环境记录;本轮没有连接或修改远端测试样机。

20. 完整 Git 历史带来的新增约束

完整 CalRT/llama.cpp 历史没有证明当前 Runtime 已有芯粒级独立 session,但补强了三个实施判断:

  1. CalRT 历史中存在 async/serial、job engine thread-safe、重配其他 calbin、多芯片 configure 和 reset 演进,因此路径 A/B 具备可研究的底层基础,不是从零开始。
  2. 同一历史也记录过 async 空指针、多线程同步、job id 和 release/reset 修复,因此所有并发能力必须在独立 runner 中按 commit 风险回归,不能仅靠 API 签名判定可用。
  3. 当前可读驱动源码是 0.9.0,而运行模块是 1.0.0;在取得上游 driver mirror 和 reset/DMA/lease 差异前,不能把改驱动当作短期生产路径。

llama.cpp 1bec0db 的“2 calbins”只是 benchmark 顺序加载;origin/runtime_replace 只有一个 EngineCore 和一个 calbin_path;两者均不构成 S1/S2 或 F1/F2 证据。三个过期 stash和 calrt: add slice 不可达实验已经恢复,可用于重建 buffer slice、计时和版本输出实验,但必须在当前基线上重新验收。

新增 P0 厂商交付项:驱动 1.0.0 的完整 Git mirror、0.9.0->1.0.0 变更、PR/Issue/CI、Runtime/firmware 兼容矩阵,以及 cal-llm SDK/ABI。详见《源码、Git 历史与驱动证据分析》。