performance-benchmark.md 9.5 KB

性能基准测试

输入要求

  1. 目标代码路径(必填):被测函数/模块/脚本
  2. 性能指标(必填):耗时 / 内存 / 吞吐量 / QPS / 启动时间,至少其一
  3. 阈值(可选):目标上限,如"单次调用 < 200ms";不提供则仅输出基准数据
  4. 对比基线(可选):优化前的基准数据,用于 A/B 对比

执行流程

第一步:识别性能触发面

扫描代码,定位性能关键路径:

  • 循环体内重计算(正则编译、字符串拼接、重复 I/O)
  • 批量操作(大批次读文件、批量 SQL、批量网络请求)
  • 数据结构选择(list vs set vs dict 查重、字符串拼接 vs join)
  • 缓存缺失(重复调用同一开销大的函数 / 重复查询同一数据)
  • 数据库查询(N+1、缺索引、全表扫描 — 发现后跳转 mysql-database)

自动化扫描档位

当用户提供文件或目录路径时,先执行可复现的静态扫描,再进入人工分析;当用户只粘贴代码片段且没有可访问路径时,跳过工具扫描并明确标注"仅基于片段审查"。

| 扫描档位 | 触发条件 | 扫描范围 | 输出要求 | | - | - | - | - | | 快速扫描 | 单个文件、单个函数、短代码片段 | 当前文件或片段中的循环、I/O、SQL、缓存 | 输出命中位置和疑似反模式 | | 深度扫描 | 目录、模块、项目级性能排查 | 入口、循环、数据库访问、网络调用、缓存、异步任务 | 输出扫描摘要、热点候选和后续验证路径 |

推荐扫描模式:

| 扫描项 | 参考模式 | 风险 | | - | - | - | | 循环内数据库调用 | for / foreach / while 附近出现 query / select / find / where | N+1 查询 | | 循环内外部请求 | 循环附近出现 fetch / axios / requests / http / RestTemplate | N+1 API 调用 | | 同步阻塞 I/O | readFileSync / writeFileSync / 同步文件读写 / 高并发路径阻塞调用 | 阻塞 I/O | | 无上限数据拉取 | .all() / findAll() / SELECT * / 无 LIMIT 的列表查询 | 内存和响应时间失控 | | 缓存无界增长 | 全局 Map/dict/Object/静态集合持续写入且无 TTL/容量限制 | 内存泄漏 | | 索引失效 | DATE(column) / LIKE '%xxx' / 字段隐式类型转换 | 慢查询 |

扫描结果只能作为嫌疑点;交付结论必须继续通过 benchmark、profile、EXPLAIN、日志或人工复核验证。

分层分析深度

根据问题规模选择分析层级,避免简单问题过度分析,也避免复杂问题只给浅层建议:

| 层级 | 触发条件 | 分析内容 | 输出形态 | | - | - | - | - | | L0 轻量分析 | 单条 SQL、单个函数、少于 30 行的小片段 | 直接复杂度、明显 I/O、单点风险 | 简短结论 + 1 到 3 个建议 | | L1 标准分析 | 多函数、循环 + DB、常规重构、30 到 200 行代码 | 复杂度、I/O、边界条件、数据量影响 | 热点表格 + 修复方案 | | L2 深度分析 | 多文件、架构级优化、线上瓶颈、超过 200 行或涉及并发 | L1 全部 + 并发、内存、缓存、扩展性、回滚风险 | 分阶段诊断和验证计划 |

硬性性能反模式

| 反模式 | 典型信号 | 严重度 | 最小修复方向 | | - | - | - | - | | N+1 查询 | 循环内数据库查询或外部 API 调用 | 严重 | 批量查询、预加载、JOIN、聚合、一次性拉取后内存分组 | | 同步阻塞 I/O | 高并发请求路径内同步文件、网络或重 CPU 操作 | 严重 | 异步化、后台任务、连接池、队列、流式处理 | | 内存泄漏风险 | 无界缓存、监听器未清理、静态集合持续增长 | 高 | TTL、容量限制、LRU、生命周期清理 | | 无上限数据拉取 | 列表查询无分页、无最大 limit、全表拉取 | 高 | 强制分页、游标、批处理、最大 page size |

第二步:选择优化策略

识别反模式后,按问题性质选择策略;没有实测基线时只能描述"预期收益"或"假设收益",不得声称已提升。

| 策略 | 适用场景 | 风险控制 | | - | - | - | | 缓存优先 | 高频读取、变更不频繁、可接受短暂不一致 | 明确 TTL、失效时机、穿透/击穿/雪崩防护 | | 异步处理 | 耗时超过用户等待阈值的非核心副作用 | 明确幂等、重试、死信、失败告警和最终一致性 | | 索引优化 | WHERE/JOIN/ORDER BY 慢查询 | 必须提供 EXPLAIN,评估写入成本和回滚方案 |

优化建议输出需包含:问题位置、当前路径、方案、预期收益依据、验证命令、回滚方式。

第三步:选用测量工具

按语言和场景选择:

| 语言 | 工具 | 适用场景 | | - | - | - | | Python | cProfile / timeit / pytest-benchmark | 函数级耗时、逐行热点 | | Node.js | console.time / benchmark.js / clinic | 火焰图、事件循环延迟 | | Go | go test -bench / pprof | CPU/内存 profile | | Java | JMH | 微基准测试 | | PHP | microtime() / Xdebug profiler | 函数耗时 |

首选策略:若项目已有测试框架,优先用其内置 benchmark(如 pytest-benchmark、go test -bench),降低接入成本。

第四步:执行测量并采集数据

  • 跑 3 次取中位数,标注冷/热启动差异
  • 记录环境:CPU 型号/核心数、内存、OS、Python 版本
  • 内存测试记录峰值 RSS(tracemalloc / memory_profiler / process.memory_info())
  • 输出原始数据 + 整理后表格

第五步:生成瓶颈报告

对超出阈值的热点逐条分析:

  • 热点代码位置(文件:行号)
  • 当前耗时 / 内存占用
  • 根因分析(为什么慢)
  • 优化建议(具体方案 + 预期收益)

第六步:优化前后对比(如有基线)

| 指标 | 优化前 | 优化后 | 提升 | | - | - | - | - | | 耗时 | X ms | Y ms | Z% | | 内存 | X MB | Y MB | Z% | | 调用次数 | X | Y | Z% |

第七步:记录到项目记忆

性能基准测试完成后,将以下内容沉淀到项目记忆(参见 project-memory-management.md):

  • 性能基线数据:中位数/P95/P99/峰值内存,作为后续回归对比依据
  • 热点位置与根因:文件:行号 + 耗时占比 + 优化建议
  • 优化前后对比:提升幅度和验证证据
  • benchmark 脚本路径:纳入测试套件持续运行
  • 性能陷阱:本轮发现的性能反模式(如 N+1 查询、O(n²) 循环、不必要的序列化)

输出格式

## 性能基准测试报告

**目标代码**:[函数/模块名]
**测试环境**:[OS / CPU / 内存 / Python 版本]

## 基准数据

| 指标 | 中位数 | P95 | P99 | 峰值内存 |
|------|--------|-----|-----|---------|
| [指标1] | [值] | [值] | [值] | [值] |

## 热点分析

| 位置 | 耗时占比 | 根因 | 优化建议 | 预期收益 |
|------|---------|------|---------|---------|
| [文件:行号] | X% | [原因] | [方案] | ~Y% |

## 优化前后对比(如有基线)

| 指标 | 优化前 | 优化后 | 提升 |
|------|--------|--------|------|

## 测试脚本

```[语言]
[可复现的 benchmark 代码]

质量标准

  • 必须跑 3 次以上取中位数,单次结果不可作为结论
  • 必须标注测试环境(硬件 + 软件版本),否则数据不可复现
  • 热点分析必须有具体代码位置(文件:行号),不得只说"某个循环慢"
  • 优化建议必须给出可操作的方案,不得只说"优化一下"
  • 不得在无基线对比的情况下声称"显著提升"

失败回退机制

步骤 失败条件 回退目标 最大重试 不可恢复时升级路径
第一步:识别触发面 代码量过大无法定位关键路径 按函数分批,标注"仅部分路径" 1 缩小范围到用户指定的入口函数
第二步:选择优化策略 无实测基线或策略不明 先跑基线,标注"预期收益/假设收益" 1 输出候选策略与权衡,由用户决策
第三步:选用测量工具 工具不可用或安装失败 降级到语言内置 time 打点 1 输出手动计时方案,标注精度受限
第四步:执行测量 环境差异导致数据波动 > 20% 增加采样次数到 7 次,输出方差 2 标注"环境不稳定",以区间范围呈现
第五步:生成瓶颈报告 热点根因无法在静态分析中确定 输出热点位置 + 耗时占比,标注"根因待确认" 1 建议用户补充 profiler 火焰图
第六步:优化前后对比 无优化前基线 仅输出当前基准,标注"无基线对比" — 正常输出
第七步:记录到项目记忆 项目记忆系统不可用 输出性能基线数据到本地文件 1 标注"基线未沉淀",提示用户手动保存

关联 reference

  • code-review(代码审查)— 发现潜在性能问题后,用本技能定量验证
  • code-generation(代码生成)— 生成代码后可用本技能跑基准测试验证性能
  • refactoring(重构建议)— 重构前跑基线,重构后跑对比,量化重构收益
  • mysql-database(MySQL数据库)— SQL 性能问题跳转 mysql-database 做 EXPLAIN / 索引分析
  • test-generation(测试用例生成)— benchmark 脚本应纳入测试套件持续跑基准
  • software-project(软件项目总控)— 软件项目上线前性能验收,提交基准数据作为交付物
  • website-project(网站项目总控)— 网站项目的性能指标、部署前压测和上线后监控基准
  • project-memory-management(项目记忆管理)— 记录性能基线数据,作为后续回归对比依据