---
description: "如何在 Mac 上获得准确的 LLM 基准测试结果：温控管理、后台应用、运行次数和可重现性技巧。"
---

# 基准测试最佳实践

> **版本**: 0.3.2
> **状态**: 持续更新文档——随方法论演进而更新
> **参考**: MLPerf Inference、SPEC CPU 2017、NVIDIA GenAI-Perf

## 概述

`asiai bench` 遵循既定的基准测试标准，在 Apple Silicon 推理引擎间产出**可靠、可重现、可比较**的结果。本文档追踪哪些最佳实践已实现、计划中或有意排除。

## 合规性总结

| 类别 | 实践 | 状态 | 起始版本 |
|------|------|------|---------|
| **指标** | TTFT 与 tok/s 分离 | 已实现 | v0.3.1 |
| | 确定性采样（temperature=0） | 已实现 | v0.3.2 |
| | Token 计数来自服务器 API（非 SSE chunk） | 已实现 | v0.3.1 |
| | 按引擎功耗监控 | 已实现 | v0.3.1 |
| | generation_duration_ms 显式字段 | 已实现 | v0.3.1 |
| **预热** | 每引擎 1 次预热生成（不计时） | 已实现 | v0.3.2 |
| **运行** | 默认 3 次运行（SPEC 最低要求） | 已实现 | v0.3.2 |
| | 中位数作为主要指标（SPEC 标准） | 已实现 | v0.3.2 |
| | 均值 + 标准差作为次要指标 | 已实现 | v0.3.0 |
| **方差** | Pooled 提示词内标准差 | 已实现 | v0.3.1 |
| | 基于 CV 的稳定性分类 | 已实现 | v0.3.0 |
| **环境** | 引擎顺序执行（内存隔离） | 已实现 | v0.1 |
| | 温控降频检测 + 告警 | 已实现 | v0.3.2 |
| | 温控级别 + speed_limit 记录 | 已实现 | v0.1 |
| **可重现性** | 引擎版本按基准测试存储 | 已实现 | v0.3.2 |
| | 模型格式 + 量化存储 | 已实现 | v0.3.2 |
| | 硬件芯片 + macOS 版本存储 | 已实现 | v0.3.2 |
| | 开源基准测试代码 | 已实现 | v0.1 |
| **回归** | 历史基线比较（SQLite） | 已实现 | v0.3.0 |
| | 按（引擎、模型、提示词类型）比较 | 已实现 | v0.3.1 |
| | metrics_version 过滤 | 已实现 | v0.3.1 |
| **提示词** | 4 种多样化提示词类型 + 上下文填充 | 已实现 | v0.1 |
| | 每提示词固定 max_tokens | 已实现 | v0.1 |

## 计划改进

### P1 — 统计严谨性

| 实践 | 描述 | 标准 |
|------|------|------|
| **95% 置信区间** | CI = mean +/- 2*SE。比 +/- stddev 更有信息量。 | 学术 |
| **百分位数（P50/P90/P99）** | 特别是 TTFT——尾部延迟很重要。 | NVIDIA GenAI-Perf |
| **异常值检测（IQR）** | 标记 [Q1 - 1.5*IQR, Q3 + 1.5*IQR] 范围外的运行。 | 统计标准 |
| **趋势检测** | 检测跨运行的单调性能下降（温控漂移）。 | 学术 |

### P2 — 可重现性

| 实践 | 描述 | 标准 |
|------|------|------|
| **引擎间冷却** | 引擎间暂停 3-5 秒让温度稳定。 | GPU 基准测试 |
| **Token 比率验证** | 当 tokens_generated < 90% max_tokens 时告警。 | MLPerf |
| **导出格式** | `asiai bench --export` JSON 用于社区提交。 | MLPerf 提交 |

### P3 — 高级

| 实践 | 描述 | 标准 |
|------|------|------|
| **`ignore_eos` 选项** | 强制生成到 max_tokens 用于吞吐量基准测试。 | NVIDIA |
| **并发请求测试** | 测试批处理吞吐量（适用于 vllm-mlx）。 | NVIDIA |
| **后台进程审计** | 基准测试期间有重度进程运行时告警。 | SPEC |

## 有意偏差

| 实践 | 偏差原因 |
|------|---------|
| **MLPerf 最少 600s 时长** | 设计用于数据中心 GPU。Apple Silicon 上 3 次运行 + 4 个提示词已需 2-5 分钟。结果已足够稳定。 |
| **SPEC 2 次非计时预热工作负载** | 我们使用 1 次预热生成（非 2 个完整工作负载）。单次预热对 JIT 预热最小的本地推理引擎已足够。 |
| **总体标准差 vs 样本标准差** | 我们使用总体标准差（N 除数）而非样本标准差（N-1 除数）。小 N（3-5 次运行）时差异很小，总体方式更保守。 |
| **频率缩放控制** | Apple Silicon 不暴露 CPU governor 控制。我们记录 thermal_speed_limit 来检测降频。 |

## Apple Silicon 特定注意事项

### 统一内存架构

Apple Silicon 在 CPU 和 GPU 间共享内存。两个关键影响：

1. **永远不要同时对两个引擎做基准测试** — 它们竞争同一个内存池。`asiai bench` 设计为顺序运行引擎。
2. **VRAM 报告** — Ollama 和 LM Studio 原生报告 `size_vram`。其他引擎（llama.cpp、mlx-lm、oMLX、vLLM-MLX、Exo），asiai 通过 `ri_phys_footprint`（libproc 的 macOS 物理占用指标，与活动监视器显示相同）作为后备估算。估算值在 UI 中标记为"(est.)"。

### 温控降频

- **MacBook Air**（无风扇）：持续负载下严重降频。5-10 分钟后结果下降。
- **MacBook Pro**（有风扇）：降频轻微，通常通过风扇加速处理。
- **Mac Mini/Studio/Pro**：主动散热，降频极小。

`asiai bench` 按结果记录 `thermal_speed_limit`，在任何运行期间检测到降频（speed_limit < 100%）时发出告警。

### KV Cache 和上下文长度

大上下文（32k+）可能在模型加载时预分配 KV cache 的引擎上导致性能不稳定。例如：LM Studio 默认 `loaded_context_length: 262144`（256k），对 35B 模型分配约 15-25 GB KV cache，可能使 64 GB 统一内存饱和。

**建议**：
- 测试大上下文时，将引擎上下文长度设为实际测试大小（如 64k 测试用 `lms load model --context-length 65536`）。
- 使用等效上下文长度设置比较引擎以获得公平结果。

## 每次基准测试存储的元数据

SQLite 中每个基准测试结果包含：

| 字段 | 示例 | 用途 |
|------|------|------|
| `engine` | "ollama" | 引擎识别 |
| `engine_version` | "0.17.4" | 检测跨更新的性能变化 |
| `model` | "qwen3.5:35b-a3b" | 模型识别 |
| `model_format` | "gguf" | 区分格式变体 |
| `model_quantization` | "Q4_K_M" | 区分量化级别 |
| `hw_chip` | "Apple M4 Pro" | 硬件识别 |
| `os_version` | "15.3" | macOS 版本追踪 |
| `thermal_level` | "nominal" | 环境条件 |
| `thermal_speed_limit` | 100 | 降频检测 |
| `metrics_version` | 2 | 公式版本（防止跨版本回归） |

这些元数据支持：
- **公平回归比较**：仅比较元数据匹配的结果
- **跨机器基准测试**：识别硬件差异
- **社区数据共享**：自描述结果（v1.x 计划）
