.gitignore添加.idea目录和.vscode目录
cdpidan authored at 2023-10-08 14:15:46
6.06 KiB
GitSync
--- applyTo: "**/Benchmark/**" --- # 性能测试指令 适用于性能测试、压力测试、基准测试、BenchmarkDotNet 相关任务。 --- ## 1. 项目结构 - 基准测试统一放在 `Benchmark/` 项目,按主题分子目录(如 `PacketBenchmarks/`、`CacheBenchmarks/`) - 入口 `Program.cs` 使用 `BenchmarkSwitcher` 模式,**不要修改** - TFM 使用最新稳定版,`<LangVersion>latest</LangVersion>` ## 2. 代码规范 遵循主指令全部编码规范(类型名用 `String`/`Int32` 等、file-scoped namespace),另有以下补充: - **命名空间**:`Benchmark.{主题}Benchmarks` - **类名**:`{被测类型}Benchmark` 或 `{被测主题}Benchmark` - **必须标注** `[MemoryDiagnoser]` 和 `[SimpleJob]`(需调整迭代次数时用 `[SimpleJob(iterationCount: N)]`) - **方法描述**:`[Benchmark(Description = "中文描述")]`,方便报告阅读 - **参数化**:用 `[Params]` 或 `[ParamsSource]` 控制数据规模 - **初始化 / 清理**:分别放 `[GlobalSetup]` 和 `[GlobalCleanup]` - **分组**:同类测试用 `#region` 分组 - **多线程并发**:动态线程数包含 CPU 核心数,推荐模板: ```csharp public static IEnumerable<Int32> ThreadCounts { get { var cores = Environment.ProcessorCount; var set = new SortedSet<Int32> { 1, 4, 8, 32 }; set.Add(cores); return set; } } [ParamsSource(nameof(ThreadCounts))] public Int32 ThreadCount { get; set; } ``` ## 3. 运行要求 - 必须以 **Release 模式**运行,获取有代表性的峰值数据 - 运行全部:`dotnet run -c Release` - 运行指定类:`dotnet run -c Release -- --filter *ClassName*` - ❌ 禁止在 Debug 模式下采集数据写入报告 ## 4. 测试维度 - **并发维度**:单线程 + 多线程(多线程含与当前 CPU 核心数相同的并发数) - **操作维度**:单一操作 + 批量操作 ## 5. 常见错误 - ❌ 在 `[Benchmark]` 方法内做初始化(应放 `[GlobalSetup]`) - ❌ 忽略返回值导致 JIT 死码消除(确保返回或赋值给字段) - ❌ 手动 `Stopwatch` 计时(BDN 自动处理) - ❌ `using` 的 `Dispose` 开销混入测量(仅在测试 Dispose 本身时才包含) ## 6. 报告存放 `Doc/Benchmark/{测试主题}性能测试.md`(UTF-8 无 BOM) ## 7. 报告结构(顺序固定) 1. **性能概览**(放最前:一句话点明被测功能用途 + 简单语言总结核心发现) 2. 测试环境 → 测试方法 → 测试结果(BDN 原始表格,保留 Mean/Error/StdDev/Allocated) 3. 核心指标(换算 msg/s、QPS 等业务指标) 4. **对比分析** - 纵向:同场景不同并发趋势,找出最优并发点 - 横向:不同方案同并发差异百分比 5. 性能瓶颈定位(按重要程度排序)→ 优化建议(含预期收益与内存节省预估) ## 8. 性能瓶颈定位规范 性能瓶颈定位章节是报告的核心价值输出,必须遵循以下规范: ### 8.1 瓶颈点结构(每个瓶颈必须包含) 每个瓶颈点必须包含以下要素,缺一不可: | 要素 | 说明 | 示例 | |------|------|------| | **优先级标签** | P0/P1/P2/P3,按影响程度降序 | P0 | | **瓶颈名称** | 一句话准确描述瓶颈 | VisitTime 写入触发 MESI 缓存行争用 | | **优化收益占比** | 该瓶颈在总体可优化空间中的占比 | ~35% | | **现象与数据** | 用 BDN 实测数据量化问题严重程度 | 4T→8T 扩展仅 1.3x,低于预期 2.0x | | **根因分析** | 从代码执行路径分析到底层硬件行为 | Get 每次写 VisitTime → 缓存行 Modified → 多核 MESI 失效 | | **开销占比估算** | 在单次操作总耗时中的占比 | 占 Get 总耗时 30%~40% | | **内存影响** | 每次操作的额外内存分配或 GC 压力 | 48 B/次装箱分配,32 线程累计 3 MB | | **优化方向** | 具体可落地的优化方案 | 时间窗口内跳过更新(如 1s 内不重复写) | | **预期收益** | 速度提升倍数 + 内存节省比例 | 多线程吞吐 +20-30%,消除缓存行争用 | ### 8.2 瓶颈分级标准 | 级别 | 定义 | 优化收益占比 | 行动 | |------|------|------------|------| | **P0** | 影响核心吞吐或造成 >30% 性能损失 | ≥25% | 必须优化 | | **P1** | 影响多线程扩展性或造成显著内存压力 | 15%~25% | 建议优化 | | **P2** | 特定场景下的次要瓶颈 | 5%~15% | 可选优化 | | **P3** | 微小开销,仅在极端场景有影响 | <5% | 记录备查 | ### 8.3 瓶颈定位表格模板 性能瓶颈定位章节使用以下统一表格格式: ```markdown ### 核心瓶颈点总览 | 优先级 | 瓶颈 | 优化收益占比 | 当前开销 | 优化后预估 | 内存节省 | |--------|------|------------|---------|-----------|---------| | P0 | {瓶颈名称} | ~{X}% | {耗时/分配} | {目标值} | {节省比例} | | P1 | {瓶颈名称} | ~{X}% | {耗时/分配} | {目标值} | {节省比例} | | ... | ... | ... | ... | ... | ... | ``` ### 8.4 内存优化方向表格模板 紧跟瓶颈总览表之后,补充内存优化方向: ```markdown ### 关键内存优化方向 | 优先级 | 优化方向 | 当前分配 | 优化后预估 | 节省比例 | 实施方案 | |--------|---------|---------|-----------|---------|---------| | P0 | {方向} | {X} B/op | {Y} B/op | {Z}% | {方案} | | ... | ... | ... | ... | ... | ... | ``` ### 8.5 开销拆解要求 对每个核心操作,必须给出开销来源拆解表: ```markdown | 开销来源 | 占比估算 | 耗时估算 | 说明 | |---------|---------|---------|------| | {来源1} | ~{X}% | ~{N} ns | {原因} | | {来源2} | ~{X}% | ~{N} ns | {原因} | ``` ### 8.6 撰写原则 - **数据驱动**:所有结论必须有 BDN 实测数据支撑,禁止无数据臆测 - **量化优先**:用"快 X 倍"、"省 Y%"、"降 Z B/op"表达,避免"显著"、"明显"等模糊词 - **根因到底**:从应用层代码 → 运行时机制 → CPU 微架构逐层分析 - **可操作**:每个优化建议必须指明具体修改位置和实施方案,而非泛泛建议 - **排序严格**:P0 在前,P3 在后,同级按收益占比降序