目标
建立一套先证明问题、再允许实现的性能改进流程。这个跟踪项不预设任何优化一定值得做,也不把“代码看起来有 allocation / timer / scan / atomic / copy / 大方法”当成性能缺陷。
执行基线必须以实际工作分支 dev 的当前 HEAD 为准;开始任何测量或实现前都记录:
git rev-parse HEAD
dotnet --info
uname -a
不得使用历史 main@201b162... 或某个旧 dev SHA 作为当前实现事实。历史 baseline 只能用于决定“值得重新测什么”,不能代替当前 Go/No-Go。
第一性原理
任何性能优化必须依次回答以下问题:
- 用户真正付出的成本是什么? CPU、managed allocation、GC、tail latency、吞吐、memory bandwidth、scheduler wakeup、lock/cache contention、JIT/instruction footprint,必须至少有一个可观测量。
- 成本发生在目标 workload 吗? synthetic benchmark 中存在不等于真实 RPC 会频繁发生。
- 成本能否归因到具体机制? 不能只看到总 QPS 下降就猜原因;需要 profiler、allocation stack、事件计数、对照组或隔离 benchmark。
- 候选方案减少的是总成本还是移动成本? 少一个 allocation 但多一个 lock、少一次 scan 但每请求多维护 scheduler node、少一次 copy 但多很多 syscall,都可能是负优化。
- 正确性是否比性能更重要? frame 顺序、deadline 不提前、single terminal、capacity hard bound、shutdown、flow-control、trace/context、用户 interceptor/context 可观察语义都不能为了数字放宽。
- 结果是否可复现? base/head 必须同机交替,多轮运行;小于噪声的变化不得宣称收益。
- 能否独立回退? 测量、candidate、correctness hardening 分 commit;失败时撤回 candidate,保留有价值的测量基础设施。
- 是否已经有别的 issue 拥有这个状态/成本? 先检查 Runtime Architecture、现有 perf issue 和正在合并的 PR;不能重复重构即将被删除的状态。
因此每个调查只有两类合法结果:
No-Go: 证据不足 / 收益不足 / 风险过高 -> 记录结论并停止
Go: 成本已证明且候选达到预先门槛 -> 另开独立实现 issue/PR
测量 issue 本身不以产生 production optimization 为完成条件。得出可信的 No-Go 同样算完成。
#129–#134 的正文为了让低能力实现者不在 Go 后重新猜设计,提前包含了 candidate、correctness、rollback 实施手册;这些 candidate 章节是条件式手册,不是实施授权。调查达到 Go 后,仍按本总跟踪规则创建具体 implementation issue,并把已经命中的 candidate 章节复制/收敛过去;No-Go 时不得因为手册已经写好就修改 production。
依赖规则
正式性能数据硬前置:#122
#122 是其他调查做正式 macro Go/No-Go 判断的硬前置。
原因:旧 LoadTest 的共享 latency histogram 会在每个成功请求上执行多个原子操作,并且正式 histogram 与 realtime histogram 同时记录。若 recorder 本身对 c128/c512 有明显干扰,后续 1%-5% 的差异没有决策价值。
所有调查在 #122 完成前可以提前完成:
- correctness inventory;
- instrumentation 设计;
- microbenchmark;
- profiler/allocation stack;
- IL/native disassembly;
- test-only evidence runner;
- throwaway prototype 的局部验证。
但最终正式 macro gate 必须使用 #122 的 formal recording 模式和新 baseline。
架构依赖
部分性能问题必须等架构 owner 稳定后才能实施最终 candidate:
依赖图
#122 可信性能工具与基线
├──> #124 CallContext / Metrics / Tracing 正式 Go/No-Go
├──> #125 SendPump timed batching 正式 Go/No-Go
├──> #126 Deadline Scheduler 正式 Go/No-Go
├──> #129 Default Unary baseline cost 正式 Go/No-Go
├──> #130 Server immediate admission 正式 Go/No-Go
├──> #131 Client retry/admission/breaker attempt-state 正式 Go/No-Go
├──> #132 Client/Server interceptor pipeline 正式 Go/No-Go
├──> #133 outbound frame staging copy 正式 Go/No-Go
└──> #134 Server dispatch hot/cold layout 正式 Go/No-Go
#81 counter/terminal ownership
├──> #129 production candidate re-audit
├──> #130 production candidate re-audit
├──> #131 production candidate re-audit
└──> #134 final hot-path rebaseline
#124 CallContext/Telemetry
└──> #132 必须排除/避免重复归因 AsyncLocal/Telemetry 成本
#125 SendPump timer coordination
└──> #133 必须把 timer/batching coordination 与 memcpy 成本分开
#84 engine/public surface
├──> #132(仅当 candidate 触及 generated/runtime boundary)
├──> #133 public transport capability(若 Go)
└──> #134 final layout rebaseline
#84 -> #133(public SPI only, if Go) -> #86
#129 / #130 / #132 若先产生已验证 production 改动
└──> #134 必须在它们合并后的 dev 上重新采集 native layout
任一调查 Go
└──> 新建该具体机制的 implementation issue
任一调查 No-Go
└──> 记录证据并关闭,不创建实现 issue
与现有性能 issue 的关系
现有:
它们与 #124–#134 不重复。
当 #122 落地后,#90–#93 如需真实 workload macro 证据,应优先使用新的 formal recording 模式;不要求为此重写它们已经正确的第一性原理或 correctness 门禁。
#92 已经证明“减少 copied bytes”本身不是合并理由:更激进 growth policy 即使局部更快,只要造成不可接受的 capacity waste,也应拒绝。这个判例同样适用于 #133 的 zero-copy/gather 实验:总 CPU/latency/memory/syscall 才是最终目标。
当前明确不立项的方向
Endpoint Selection
当前 dev 已有 EndpointSelectionKernel 和 endpoint-count/strategy benchmark,既有 evidence 未显示 endpoint 数量产生稳定的整体性能方向性退化。因此现在不创建 Endpoint Selection / atomic reservation 优化 issue。
只有未来 profiler/hardware counters 证明 selection 或 exact global counter 占目标 workload 总 CPU至少约 3%-5%,才重新立项;不能因为存在 Interlocked 就进行 reservation/LongAdder 类实验。
Heartbeat shared scheduler
当前不创建共享 heartbeat scheduler / timer-wheel 类性能 issue。连接与 cluster 资源已有明确 hard bound,目前没有证据证明 per-connection heartbeat timer/task 是目标 workload 的瓶颈。只有未来大量 MultiCluster × idle connection 场景的 profiler/resource evidence 命中,再独立立项。
调查 issue
性能测量基础
已有重点调查
新增:默认与可选能力固定成本
新增:数据搬运与代码布局
通用测量纪律
基线与 candidate
正式比较必须:
- 固定同一自托管机器;
- 固定 CPU governor / runtime / SDK;
- base/head 同机交替至少 5 轮;
- alternating order,避免温度/JIT/后台负载方向性偏差;
- 记录 exact SHA;
- 记录 raw samples,不只保留平均值;
- 同时看 throughput、P50/P99/P99.9、CPU/op、allocated B/op、failure count;
- 热点归因需要 profiler/allocation/hardware counter 中至少一种适合该假设的证据。
不得:
- base 在一台机器、head 在另一台机器;
- 用一次 QPS 结果判定;
- 只看 mean 不看 tail;
- 为让 candidate 获胜而改变 payload、concurrency、transport 或 recorder 模式;
- 把 warmup/JIT/first-call 计入 steady-state(除非 issue 专门测 startup);
- 把 diagnostic instrumentation 留在正式 timing path 后仍宣称 production performance;
- 因为 candidate 代码已经写好就降低 Go/merge 门槛。
正确性优先
任何 candidate 出现以下任一情况立即 No-Go / revert:
- wire bytes / frame ordering 改变;
- deadline 提前触发或遗漏;
- single terminal 被破坏;
- hard capacity overshoot;
- shutdown/task/timer 泄漏;
- flow-control credit 泄漏;
- stale callback 命中新 lifecycle;
- buffer/pooled owner early return、double return 或 use-after-return;
- trace/context/interceptor 可观察语义在未明确设计的情况下改变;
- retry/admission/breaker outcome/report exactly-once 被破坏;
- NativeAOT 或支持 transport 出现 correctness regression。
实现 issue 创建规则
测量 issue 达到 Go 条件后,不要直接在同一个 PR 顺手改 production。先在测量 issue 中固定:
- baseline SHA;
- profiler/evidence;
- candidate 假设;
- 预期收益;
- correctness invariants;
- 预先定义的 merge/revert gate。
然后另开实现 issue,标题描述具体机制,而不是笼统“optimize X”。
#129–#134 中已经写好的 candidate 手册应作为实现 issue 的输入,但只复制被证据选中的那一部分;不要把所有候选一次实现。
如果测量 No-Go,则关闭调查,不创建实现 issue。
总完成定义
目标
建立一套先证明问题、再允许实现的性能改进流程。这个跟踪项不预设任何优化一定值得做,也不把“代码看起来有 allocation / timer / scan / atomic / copy / 大方法”当成性能缺陷。
执行基线必须以实际工作分支
dev的当前 HEAD 为准;开始任何测量或实现前都记录:不得使用历史
main@201b162...或某个旧devSHA 作为当前实现事实。历史 baseline 只能用于决定“值得重新测什么”,不能代替当前 Go/No-Go。第一性原理
任何性能优化必须依次回答以下问题:
因此每个调查只有两类合法结果:
测量 issue 本身不以产生 production optimization 为完成条件。得出可信的 No-Go 同样算完成。
#129–#134 的正文为了让低能力实现者不在 Go 后重新猜设计,提前包含了 candidate、correctness、rollback 实施手册;这些 candidate 章节是条件式手册,不是实施授权。调查达到 Go 后,仍按本总跟踪规则创建具体 implementation issue,并把已经命中的 candidate 章节复制/收敛过去;No-Go 时不得因为手册已经写好就修改 production。
依赖规则
正式性能数据硬前置:#122
#122 是其他调查做正式 macro Go/No-Go 判断的硬前置。
原因:旧 LoadTest 的共享 latency histogram 会在每个成功请求上执行多个原子操作,并且正式 histogram 与 realtime histogram 同时记录。若 recorder 本身对 c128/c512 有明显干扰,后续 1%-5% 的差异没有决策价值。
所有调查在 #122 完成前可以提前完成:
但最终正式 macro gate 必须使用 #122 的 formal recording 模式和新 baseline。
架构依赖
部分性能问题必须等架构 owner 稳定后才能实施最终 candidate:
依赖图
与现有性能 issue 的关系
现有:
MoveNextAsyncConcurrentStackallocation/contentionPooledByteBufferWritergrowth copies它们与 #124–#134 不重复。
当 #122 落地后,#90–#93 如需真实 workload macro 证据,应优先使用新的 formal recording 模式;不要求为此重写它们已经正确的第一性原理或 correctness 门禁。
#92 已经证明“减少 copied bytes”本身不是合并理由:更激进 growth policy 即使局部更快,只要造成不可接受的 capacity waste,也应拒绝。这个判例同样适用于 #133 的 zero-copy/gather 实验:总 CPU/latency/memory/syscall 才是最终目标。
当前明确不立项的方向
Endpoint Selection
当前
dev已有EndpointSelectionKernel和 endpoint-count/strategy benchmark,既有 evidence 未显示 endpoint 数量产生稳定的整体性能方向性退化。因此现在不创建 Endpoint Selection / atomic reservation 优化 issue。只有未来 profiler/hardware counters 证明 selection 或 exact global counter 占目标 workload 总 CPU至少约 3%-5%,才重新立项;不能因为存在
Interlocked就进行 reservation/LongAdder 类实验。Heartbeat shared scheduler
当前不创建共享 heartbeat scheduler / timer-wheel 类性能 issue。连接与 cluster 资源已有明确 hard bound,目前没有证据证明 per-connection heartbeat timer/task 是目标 workload 的瓶颈。只有未来大量 MultiCluster × idle connection 场景的 profiler/resource evidence 命中,再独立立项。
调查 issue
性能测量基础
[perf][tooling] 修复负载测试延迟记录干扰并建立可信性能基线dev建立新 baseline。已有重点调查
[perf][telemetry] 归因 CallContext、Metrics 与 Tracing 的每调用成本 #124 —
[perf][telemetry] 归因 CallContext、Metrics 与 Tracing 的每调用成本None与PropagationDatasampling semantics。[perf][sendpump] 证明 timed batching 的 timer coordination 是否值得优化 #125 —
[perf][sendpump] 证明 timed batching 的 timer coordination 是否值得优化[perf][deadline] 证明 Deadline Scheduler 扫描成本是否值得更复杂的数据结构 #126 —
[perf][deadline] 证明 Deadline Scheduler 扫描成本是否值得更复杂的数据结构新增:默认与可选能力固定成本
[perf][unary] 归因默认 Unary RPC 基线成本并消除可证明的固定税 #129 —
[perf][unary] 归因默认 Unary RPC 基线成本并消除可证明的固定税[perf][admission] 降低 Server immediate admission 的每请求固定成本 #130 —
[perf][admission] 降低 Server immediate admission 的每请求固定成本SharpLinkAdmissionContext、健康 immediate path 的 slot/request representation;不默认重写 BCL RateLimiter。[perf][client-attempt] 归因并降低 Retry / Endpoint Admission / Circuit Breaker attempt-state 成本 #131 —
[perf][client-attempt] 归因并降低 Retry / Endpoint Admission / Circuit Breaker attempt-state 成本[perf][interceptor] 归因 Client/Server Interceptor pipeline 的固定成本 #132 —
[perf][interceptor] 归因 Client/Server Interceptor pipeline 的固定成本新增:数据搬运与代码布局
[perf][transport] 量化 outbound frame staging copy 并验证 transport-owned write #133 —
[perf][transport] 量化 outbound frame staging copy 并验证 transport-owned writeOwnedFrame -> PipeWriter的Span.CopyTo在不同 transport/payload 的真实 CPU/memory-bandwidth占比。#84 -> #133 -> #86。[perf][dispatch] 验证 Server dispatch hot/cold layout 是否降低 JIT 与指令缓存成本 #134 —
[perf][dispatch] 验证 Server dispatch hot/cold layout 是否降低 JIT 与指令缓存成本通用测量纪律
基线与 candidate
正式比较必须:
不得:
正确性优先
任何 candidate 出现以下任一情况立即 No-Go / revert:
实现 issue 创建规则
测量 issue 达到 Go 条件后,不要直接在同一个 PR 顺手改 production。先在测量 issue 中固定:
然后另开实现 issue,标题描述具体机制,而不是笼统“optimize X”。
#129–#134 中已经写好的 candidate 手册应作为实现 issue 的输入,但只复制被证据选中的那一部分;不要把所有候选一次实现。
如果测量 No-Go,则关闭调查,不创建实现 issue。
总完成定义