# 性能基准测试 ## 输入要求 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**(项目记忆管理)— 记录性能基线数据,作为后续回归对比依据