Files
calculet-npu-research-archive/reports/Calculet-NPU-性能压测故障注入与验收规范-20260802.md
T

337 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Calculet NPU 性能压测、故障注入与验收规范
日期:2026-08-02
适用:当前 batch=1 基线、异步执行器、后续 batch calbin/新模型
## 1. 为什么必须重建基线
历史 CSV 有 163 行,可保留作趋势参考,但不能作为正式结论:脚本把 `model` 固定写为 `deepseek`TTFT 又被算成 `predicted_ms + prompt_ms`,不是客户端收到首 token 的真实时间。
新基线必须从客户端单调时钟采集首字节/首 token,同时由服务和 Runtime 用 request/job id 对齐队列、H2D、infer、D2H、后处理。任何无法对齐的时间单独标 `unattributed`,不得塞进 TTFT。
## 2. 时钟和事件定义
### 2.1 客户端事件
```text
t0 request_start 客户端准备发请求前
t1 request_headers_sent HTTP headers/body 已写完
t2 response_headers 收到响应 headers
t3 first_event 收到第一个有效 SSE/JSON event
t4 first_token 收到第一个非空生成 token
t5 last_token 收到最后生成 token
t6 response_end 流/连接正常结束
```
所有本进程间隔用 `CLOCK_MONOTONIC`/steady clock。UTC wall clock 只用于跨进程关联,需记录 NTP offset,不用于精确 duration。
### 2.2 指标公式
```text
TTFH = t2 - t0 # time to response headers
TTFE = t3 - t0 # time to first stream event
TTFT = t4 - t0 # 真实 time to first generated token
E2E = t6 - t0
decode_duration = t5 - t4 # output_tokens > 1
TPOT = decode_duration/(output_tokens-1)
output_tokens_per_s = (output_tokens-1)/decode_duration
```
若接口在第一个 event 同时返回多个 token,要记录 chunk token count,不能用 event 数当 token 数。`output_tokens<=1` 时 TPOT 为 null。
### 2.3 服务事件
```text
accepted -> slot_assigned -> admitted -> job_prepared -> submit_start
-> submit_ok -> wait_done -> logits_ready -> sampled -> token_flushed
```
Prefill/decode 分开,每 token step 有 `step_index`。Runtime 时长:`input_transfer_ms``wait_ms``output_transfer_ms`;服务还要测 input prepare、BF16 conversion、sampling。
## 3. 原始请求 schema
每个请求一行 JSONL,不直接把复杂数组塞 CSV:
```json
{
"schema":"calculet-perf-request/v1",
"run_id":"...",
"request_id":"...",
"model_alias":"qwen3",
"model_generation":42,
"calbin_sha256":"...",
"software":{"server_commit":"...","image_digest":"...","calrt":"0.7.6","driver":"...","firmware":"..."},
"hardware":{"board_serial_hash":"...","chips":2,"power_mode":"..."},
"workload":{"prompt_tokens":128,"requested_output_tokens":256,"actual_output_tokens":256,"concurrency":4,"stream":true,"seed":1234},
"client_ns":{"request_start":0,"headers_sent":0,"response_headers":0,"first_event":0,"first_token":0,"last_token":0,"response_end":0},
"durations_ms":{"ttfh":0,"ttfe":0,"ttft":0,"tpot":0,"e2e":0},
"server_ms":{"queue":0,"prefill":0,"decode_total":0,"postprocess":0,"sampling":0},
"runtime_ms":{"h2d_prefill":0,"infer_prefill":0,"d2h_prefill":0,"h2d_decode":0,"infer_decode":0,"d2h_decode":0},
"result":{"http_status":200,"finish_reason":"stop","token_hash":"...","error_code":null},
"quality":{"clock_complete":true,"server_trace_joined":true,"warmup":false,"throttled":false}
}
```
原始 prompt 内容默认不落性能日志;记录 corpus sample id 和 token hash,避免隐私泄露。
## 4. step 和设备 schema
高粒度数据单独写 `steps.jsonl`
```json
{"request_id":"...","job_id":123,"seq_id":7,"kind":"decode","step":12,
"queue_ms":0.2,"prepare_ms":0.1,"h2d_ms":0.1,"device_wait_ms":15.4,
"d2h_ms":0.3,"bf16_ms":0.2,"sampling_ms":0.1,"engine":"auto",
"kv_before":139,"kv_after":140,"output_status":"done"}
```
设备采样 `device.jsonl`wall timestamp、monotonic offset、per-chip temperature/power/frequency/memory、pending/finished/left jobs、reset counter。每项带单位;取不到的字段为 null,不用 0 代替。
## 5. run manifest
```yaml
schema: calculet-perf-run/v1
run_id: 20260802-qwen3-baseline-001
purpose: baseline
model:
alias: qwen3
generation: 42
calbin_sha256: REQUIRED
software:
server_commit: REQUIRED
image_digest: REQUIRED
calrt: 0.7.6
driver: REQUIRED
firmware: REQUIRED
hardware:
board: REQUIRED
chips: 2
power_mode: REQUIRED
environment:
ambient_c: REQUIRED
vpn_in_path: false
client:
host: REQUIRED
transport: http-sse
matrix: configs/baseline.yaml
warmup_requests: 10
measured_requests: 100
timeout_s: 900
```
NPU 性能客户端应与服务处在稳定低抖动 LAN;VPN 只用于管理,不应位于性能数据路径。若无法避免,记录 RTT/jitter 并把 Runtime 设备指标与客户端指标分开解释。
## 6. 基线矩阵
### 6.1 单请求
| 维度 | 值 |
| --- | --- |
| prompt tokens | 1, 16, 17, 128, 512, 1024, 2048, 4096, 8192, 16384, 32768, 40959 |
| output tokens | 1, 32, 256 |
| concurrency | 1 |
| sampling | greedy(数值基线),固定 seed 的业务 sampling |
| stream | true/false |
`prompt=40959, output>1` 是边界拒绝/截断策略测试,不是成功生成 256 token 的性能 case。
### 6.2 并发
| concurrency | arrival | 目的 |
| ---: | --- | --- |
| 1 | closed-loop | 单请求下界 |
| 2,4,8,16 | closed-loop | 饱和吞吐/排队 |
| 目标 QPS 0.25/0.5/1/2... | open-loop Poisson | 真实排队和 overload |
| burst 2/4/8/16 | 同时到达 | admission/backpressure |
closed-loop 每个 worker 收到结果后再发请求,会隐藏 overload;容量和 P99 必须用 open-loop 复测。
### 6.3 混合流量
- 70% 短 prompt(128)/短 output(32)20% 中(2K/128)10% 长(16K/256)。
- decode-heavy:已有 KV 的长生成。
- prefill-heavy:长 prompt/短输出。
- 长 prefill 与短 decode 同时到达,观察 head-of-line blocking。
## 7. batch calbin 矩阵
对 B4/B8/B16 每个产物分别测 active lanes `1..B`,不满 lane 的 mask/填充策略必须由厂商说明。
```text
fill_ratio = active_lanes / compiled_batch
effective_tokens_s = successful_generated_tokens / wall_time
lane_waste = 1 - useful_lane_steps / total_lane_steps
```
同时报告单请求 TPOT P99 和 aggregate tokens/s。若 B16 aggregate 更高但低负载 TPOT/P99 不满足 SLA,可采用多 profile 或调度阈值,不能笼统宣称“B16 最优”。
## 8. 测量执行顺序
1. 校验 release manifest、hash 和设备版本。
2. 空闲采样 5 分钟,确认温度/功耗/频率稳定。
3. 跑固定 golden,失败立即终止性能测试。
4. 每个新模型/shape 10 次 warmup,不计入测量。
5. case 顺序随机化或 baseline/candidate 交错,降低温漂偏差。
6. 每 case 至少 30 次;短 case 100 次。
7. 每轮记录 idle gap、温度和 throttle;触发 throttle 的结果分层报告。
8. 测后再跑 golden,并检查资源回落。
## 9. 统计和比较
每个 cell 输出 count、success/error、P50/P90/P95/P99/max、mean/std、MAD、95% bootstrap CI。吞吐使用整个稳态窗口而非逐请求 tokens/s 的简单平均。
baseline/candidate 同一 case 计算配对差值:
```text
delta_abs = candidate - baseline
delta_pct = (candidate/baseline - 1)*100
```
延迟负值改善,吞吐正值改善。报告应明确方向,避免表格误读。
异常值不随意删除。只有客户端 clock 缺失、进程启动 warmup、明确网络断链等预注册条件可排除,并报告排除数量/理由。
## 10. 正式指标面板
### 10.1 请求
- request rate、success、4xx/5xx/timeout/cancel。
- TTFT、TPOT、E2E 按 model/prompt/output/concurrency 分桶。
- generated tokens/s、prompt tokens/s、active sequences。
- queue time、admission wait、slot wait。
### 10.2 Runtime
- jobs in-flight、pending/finished/left。
- H2D/infer/D2H、OutputBuf status。
- buffer pool total/free/leased/quarantine/wait。
- KV allocated/free/wait/reject、sequence length histogram。
- CCU exception、timeout、busy、reset、generation change。
### 10.3 系统/设备
- process RSS/CPU/thread count/open FDs。
- device DRAM/SRAM usage(单位经确认后)。
- per-chip temp/power/frequency/throttle。
- D2D/DDR/PCIe bytes/cycles(厂商 trace)。
## 11. 故障注入架构
不要通过真的破坏样机文件或任意写寄存器做日常注入。优先在我方 wrapper 注入返回码/延迟/状态;设备级 reset 只在维护窗口和厂商契约下测试。
```cpp
struct CalrtFaultInjector {
virtual CalrtError_e before_submit(const JobContext &) = 0;
virtual std::optional<CalrtError_e> override_wait(const JobContext &) = 0;
virtual std::optional<OutputStatus> override_status(const JobContext &) = 0;
virtual void corrupt_output(JobContext &) = 0;
};
```
生产编译默认注入器 disabled;启用需要 test build 或受控 admin flag,普通请求不能设置。
## 12. 故障场景清单
### 12.1 请求/资源
| 场景 | 注入 | 预期 |
| --- | --- | --- |
| 非法长度/溢出 | 0、max+1、uint 边界 | 提交前 400,不影响设备 |
| KV 满 | `canAllocate=false` | 有界等待后 429/503CPU 不忙等 |
| buffer pool 满 | 占满 lease | 排队/timeout,无共享复用 |
| cancel waiting | 等待队列中取消 | 立即移除并释放 reservation |
| cancel submitted | infer 后取消 | 仍 drain Wait,不交付结果 |
### 12.2 Runtime
| 场景 | 注入 | 预期 |
| --- | --- | --- |
| submit DeviceBusy | wrapper rc=17 | 有界 backoff/失败,不 reset |
| submit DeviceUnavailable | rc=18 | 停 admission,进入恢复 |
| Wait Timeout | rc=13 | buffer/KV quarantine |
| CCU exception | output status | 不交付 logitsgeneration 恢复 |
| invalid shape/dtype | rc=21/22 | 隔离 artifact,不反复 reset |
| stale completion | 延迟旧 job 到 reset 后 | generation check 阻断写入 |
| output NaN/Inf | corrupt hook | 数值检查失败、golden 复测 |
### 12.3 生命周期
| 场景 | 操作 | 预期 |
| --- | --- | --- |
| shutdown with queue | queued+submitted | queued 取消,submitted drain |
| load while ready | 新 generation | 先 drain,原子切换 |
| configure failure | 错 calbin | 旧 generation 保持或可回滚 |
| reset failure | mock soft reset fail | 实例 Failed,由 supervisor 重启 |
| repeated fault | 连续 timeout/crash | 指数退避和 reset 限频 |
### 12.4 硬件维护窗口
可在明确授权下测试 PCIe/driver/device reset,但不清理审计日志掩盖实验。每次记录操作者、时间、在途 job、前后版本/health、影响用户和恢复结果。
## 13. 稳定性阶段
| 阶段 | 时长 | 负载 | 通过条件 |
| --- | ---: | --- | --- |
| smoke | 10 min | C1、短请求 | golden、零错误 |
| dev soak | 1 h | 70% 目标负载 | 无 leak/hang/abort |
| candidate | 8 h | 混合+burst | SLA、恢复、资源稳定 |
| release | 24 h | 目标稳态+周期 burst | 零未恢复 device fault |
| endurance | 72 h 可选 | 生产模拟 | 观察热/长期碎片 |
资源泄漏判定:warmup 后对 RSS、device memory、leased buffer、KV allocated、FD/thread 做 Theil-Sen slope 或至少起止/周期趋势;不能仅看最终值。每个 sequence 完成后 KV 和 lease 最终回到预期基线。
## 14. 验收阈值
### 14.1 正确性和可靠性是硬门槛
- 固定 golden 100% 通过;无请求间 logits/KV 串扰。
- 24h 无 `abort()`、无限等待、use-after-free、未处理 exception。
- 所有 fault scenario 状态转换符合设计,恢复后 golden 通过。
- success response 中 NaN/Inf=0;错误响应不含未初始化输出。
### 14.2 性能门槛
基线重构(in-flight=1):TTFT/TPOT P50 退化 <=3%P99 <=5%。
优化候选:目标 cell 至少改善 8% 或端到端关键指标改善 5%;非目标 workload P99 退化 <=5%;功耗/温度不突破设备/产品上限。
ping/pongaggregate tokens/s 提升 >=10%,单请求 TPOT P99 退化 <=5%24h 稳定。
batch calbin:在目标并发下 aggregate tokens/s 相对 B1 提升必须给出明确目标;在数据到位前不预设倍数。低填充率必须仍满足交互 SLA。
### 14.3 容量门槛
在目标 arrival rate 下,P99 queue time、reject rate 和利用率同时满足 SLA。稳定最大 QPS 定义为 30 分钟窗口内错误率/延迟合格且队列不持续增长的最高点,不是短时峰值。
## 15. 自动化 pass/fail
```text
validate manifests/hashes
-> golden before
-> warmup
-> execute randomized matrix
-> join client/server/device records
-> quality filters
-> summarize + confidence intervals
-> fault matrix
-> golden after
-> resource leak analysis
-> acceptance rules
-> signed report
```
程序退出码:0 pass1 correctness/reliability fail2 artifact/config invalid3 infrastructure invalid(例如客户端时钟或网络断链);4 performance regression。基础设施失败不算产品 pass 或 fail,需重跑。
## 16. 报告必须呈现的反例
- 最慢的 20 个请求及其 queue/device/postprocess 分解。
- 发生过的所有 Runtime 非 success,即使最终请求重试成功。
- 每次 reset/reconfigure 和恢复时长。
- 被排除样本及理由。
- candidate 赢/输的 workload,不只展示最佳 case。
- 长 context TPOT 曲线;当前历史趋势约在 33K/40K 明显下降,必须用新 harness 重测。
## 17. 厂商数据接口要求
正式归因仍需要:per-op/per-chip cycles、D2D/DDR/PCIe bytes、队列 counters 语义、温度/功耗/频率 API、trace schema/时钟/开销。没有这些字段时仍可完成端到端 A/B,但结论只到图/服务级,不虚构 kernel 瓶颈。