前阵子帮某项目组做性能选型两个方案连吵了三天一个押高频一个押低功耗。我把几行公式搬出来算了一轮结论让两边都愣住——高频方案并没有想象中快功耗账一摊开反而更难看。那一刻我真切感觉体系结构里最值钱的往往不是灵光一现而是那些被反复验证的规则与公式。这是体系结构系列里的一篇专门聊聊规则与公式它们怎么来的、怎么用、又藏了哪些坑。1. 从一道性能题说起CPU时间公式到底在算什么1.1 核心公式拆解为什么是三条边相乘所有性能讨论基本都绕不开这个式子CPU时间 指令数(IC) × 每条指令平均时钟周期(CPI) × 时钟周期时间(CT)其中时钟周期时间 CT 是主频的倒数。主频 2GHz一个周期就是 0.5ns。很多资料也把公式改写成CPU时间 指令数 × CPI / 主频道理完全一样只是写法更顺手。我第一次接触时觉得这公式太朴素后来才意识到它把所有性能优化手段都归置到了三个变量上减少指令数、降低每条指令的周期数、缩短周期时间。怎么理解三个量相乘你就想成盖章一摞文件是“指令数”每份文件需要盖多少个章是“CPI”盖一个章花多少秒是“时钟周期时间”。总工作量就是三个数乘起来。任何优化手段最终都要落到其中至少一个数上没有第四种出路。也正因为如此这个公式成了整篇内容的地基。后文所有定律和指标本质上都是在对这三个数再做细分或加权。1.2 三个变量互相拉扯每次改动都是一次权衡公式本身是静态的真实设计里三个变量却会互相咬合。你改其中一个另外两个往往跟着变而且方向不一定有利。提高主频通常要加深流水线或收紧时序。代价是分支预测失败、缓存未命中时浪费的周期更多CPI会上升。主频提升 20%CPI 从 1.5 升到 1.9总时间反而变成原来的 1.9/(1.5×1.2) ≈ 1.06 倍越优化越慢。降低 CPI比如上乱序执行、加大缓存芯片面积和功耗会明显上涨。对短任务来说启动和唤醒的固定开销可能直接把收益吃光。减少指令数则更多要指望编译器优化和指令集设计。但一条复杂指令虽然能替换掉几条简单指令这条指令在微架构里的 CPI 可能高得多算下来未必划算。这就是体系结构设计最反直觉的地方你以为在解一元方程实际上在解联立方程组。项目组里经常出现“优化了一项整体反而变慢”的情况多半就是只盯住单个变量忽略了公式里其他两个变量的连锁反应。2. Amdahl定律为什么加速是有上限的2.1 公式与生活直觉不可加速的部分是硬天花板Amdahl定律是体系结构里最著名的规则之一。假设程序中有比例 f 的部分能被优化优化后这部分加速为 s比如原来要 10 秒优化后要 1 秒则 s10那么整体加速比为加速比 1 / ((1 - f) f / s)式子里的 (1-f) 是没被优化的部分它始终按原速跑不管你优化得多猛这部分的耗时都会留在总时间里。生活里例子到处都是。你早上上班半小时坐高铁高铁速度提到多快都有意义但最后还有十分钟必须步行步行你怎么优化都只能走到那么快。把高铁优化成瞬移总路程时间也只是从 40 分钟变成 10 分钟不可能到 0。所以当 f0.9s 无限大整体加速比最多只有 1/(1-0.9)10 倍。90% 的部分无限加速总时间只缩短到原来的十分之一剩下那 10% 串行成了绝对天花板。这句话在并行计算、缓存优化、指令集扩展里通吃。2.2 真实项目里的“并行比例”应该怎么测理论公式不复杂真正坑人的是 f 怎么取值。很多开发者的习惯是打开代码数行数代码里 90% 的循环都能并行OKf0.9。这种估算几乎都会翻车。f 应该是“经过优化的那部分代码在基准测试总执行时间里实际占用的比例”而不是代码行数比例。同步等待、负载不均、串行初始化、I/O 空隙这些都不好从源码行数上看出来但 profiling 一测全暴露。我曾见过一个项目负责人拍着胸脯说算法 95% 并行实际开到 16 核只快了 5 倍。用 Amdahl 反推加速比 5极限条件下 f 至少要到 0.8也就是说这台机器上实际可并行比例只有八成左右剩下两成时间都耗在同步、任务分发和局部串行段里。外推到 64 核理论加速上限也只有 5 倍多继续加核基本没有回报。这个反推也很有工程价值如果你希望整体加速达到目标 S那么必须满足 (1-f) ≤ 1/S也就是说串行比例必须小到一定程度。想清楚这一点再决定要不要投钱做并行化能省下不少无用功。2.3 换个视角Gustafson法则与可扩展问题Amdahl定律看多了容易让人悲观。另一条规则我愿意一起拎出来讲Gustafson法则。Amdahl 假设问题规模固定所以并行部分计算到一定程度后串行部分占比会越来越大加速比封顶。Gustafson 换了一个假设随着处理器数量增加问题规模也可以扩大。大规模科学计算、图像渲染、数据分析都是这种场景。此时加速比可以写成加速比 (1 - f) N × f其中 N 是处理器数。同样 f0.95、N64Gustafson 给出约 61.85 倍远高于 Amdahl 的极限 20 倍。两条规则没有谁对谁错只是适用前提不同。搞工程时先问一句我的问题规模是钉死的还是可以跟着硬件长大问题钉死用 Amdahl 冷静问题可以放大Gustafson 会给你合理得多预期。3. MIPS、MFLOPS与功耗公式那些容易被误用的指标3.1 MIPS指标的三重陷阱MIPS 全称是每秒百万条指令计算式为MIPS 主频 / (CPI × 10^6)看起来比执行时间公式更直观主频越高、CPI 越低MIPS 越大。但用这个指标跨处理器比较几乎每一步都在踩坑。第一重坑不同指令集的指令“含金量”不同。某简单指令集处理器跑一个任务可能要用 200 条指令另一个复杂指令集处理器只需 50 条。前者 MIPS 可能是后者的三倍总执行时间却可能更长。举极端例子有些微指令能做“乘加”一条搞定有些指令集要先乘后加两条MIPS 高不代表程序跑得快。第二重坑CPI 是平均值而且依赖指令混合比例。同一颗处理器跑整数密集和浮点密集程序CPI 能差出好几倍。厂商宣传里常用的峰值 MIPS往往是选了一组最有利指令序列跑出来的真实应用根本到不了。第三重坑MIPS 没法衡量访存瓶颈。程序一旦卡在内存带宽上处理器再算得快也白搭而 MIPS 公式里完全没有内存。所以现在行业里正经对比性能基本都靠标准基准测试套装没人再拿裸 MIPS 说事。MIPS 保留下来更多是教学活动里的分析工具帮理解 CPI 与主频的关系。3.2 峰值算力与实际算力MFLOPS的另一个坑科学计算领域更常用 MFLOPS即每秒百万次浮点运算。它避开指令集差异因为在数值计算里“浮点运算次数”比“指令条数”更有可比性。但 MFLOPS 也有自己的问题峰值和实测之间隔着一条大鸿沟。硬件理论峰值大致是峰值FLOPS 处理器核数 × 主频 × 每周期浮点运算次数注意这里假设每个周期都打满浮点单元而且数据都在寄存器里排队等着算。真实程序还有访存、同步、分支、通信能达到峰值十分之一已经算很好的应用。做高性能计算的人经常挂在嘴边一句话峰值是宣传用的实测才是自己用的。想评估系统最好直接用代表目标负载的基准程序跑而不是拿厂商的峰值数字做外推。3.3 动态功耗公式里藏着最反直觉的节能逻辑处理器功耗往细了拆有很多项动态功耗、短路功耗、漏电功耗。第一项在常规分析里最受关注公式也很简单动态功耗 ≈ C × V² × fC 是负载电容V 是工作电压f 是时钟频率。很多功耗优化方案上来就盯着频率但看公式就知道电压是平方项杠杆大得多。同一颗片电压从 1.2V 降到 1.0V单独看功耗差约 30%频率从 2GHz 降到 1.8GHz只差 10%。所以现代处理器普遍在频率下降时连电压一起降这就是 DVFS动态电压频率调节的思路。更反直觉的点在能耗层面。能耗是功耗乘时间能耗 功耗 × 时间如果只降频率、不降电压功耗线性下降但跑同一段程序的时间几乎反比拉长两者一乘能耗基本没变。真正省能耗的是降电压频率降为原来的 α 倍电压降为原来的 β 倍执行时间拉长约 1/α动态功耗约变为 αβ² 倍总能耗约变为 β² 倍实打实往下掉。这就是为什么“降频不降压等于白忙活”。我也见过不少数据中心运维的误区一看负载低了就想着把节点主频降下来省电。结果只降频率没动电压任务时间拉长总能耗只是平移客户体验还变差。更合理的做法是评估后直接合并任务、关闭部分节点让剩下的节点在高能效点运行。这些判断靠的就是功耗公式加执行时间公式一起算。3.4 为什么这些“过时”指标还在被引用MIPS 和 MFLOPS 经常被嘲笑不靠谱但都没消失。原因之一是指标简单适合教学和快速估算原因是历史惯性老文档、老论文大量使用读的时候必须知道它水在哪。规则和公式本就不是用来替代实测的而是帮你建立数量级直觉。真正到做方案决策时回到执行时间公式、Amdahl 定律和功耗公式把账算到具体数值比嘴上争到底谁快有意义得多。4. 隐藏在规则背后的设计权衡几条值得记住的经验法则4.1 局部性原理性能优化的第一性规则如果说体系结构里只能记住一条经验法则我会推荐局部性原理。它由两部分组成时间局部性刚访问过的数据不久之后很可能再次访问。空间局部性访问了一个地址附近的数据相邻地址的数据也大概率会被访问。这条法则解释了缓存为什么有效也指导我们怎么写代码。经典的例子是遍历二维数组。大多数语言里数组按行存储// 按行优先遍历访问 arr[i][j] 时同一行的元素都在临近地址 for (int i 0; i N; i) { for (int j 0; j N; j) { sum arr[i][j]; } }如果内层循环改成按列遍历每次访问都要跨过一整行、跳到很远的内存地址缓存命中率会断崖式下降程序慢好几倍一点也不奇怪。另一个常见的 90/10 规则也属于这一类经验程序 90% 的执行时间通常花在 10% 的代码上。所以做性能剖析一定要先抓热点而不是均匀地优化每一行代码。4.2 存储层级间的“10倍法则”计算机体系结构里的存储层级可以看成一条延迟瀑布。寄存器最快往后是 L1、L2、L3 缓存、内存、硬盘。工程上常用数量级来建立直觉下表只是经验量级不同硬件差异不小层级访问延迟量级容量量级寄存器约 1 个时钟周期几十到几百字节L1 缓存约 2-4 个时钟周期几十 KBL2 缓存约 10-20 个时钟周期几百 KBL3 缓存约 30-60 个时钟周期几 MB 到几十 MB内存约 100-300 个时钟周期十几 GB 到几百 GBSSD约百微秒级几百 GB 到几 TB每往下一层延迟大约差一个数量级。这个经验法则的最大价值是提醒你缓存命中率永远是优化清单里最优先被检查的项目。很多算法看似复杂度低实际跑起来卡在内存访问上原因就是数据访问模式太差缓存帮不上忙。分析性能时我习惯先估算核心数据集能不能塞进 L2不行再看带宽而不是一头扎进微指令细节。4.3 核心微架构权衡乱序、深度流水线与大小核处理器设计本身也有一堆经验法则。最典型的是流水线深度流水线越深单级延迟越小主频可以拉高但分支预测失败时要清空更多级流水线惩罚也越大。所以主流高性能核的流水线深度通常压在一个十几到二十几级的区间不会无限加深再往上边际收益会被惩罚吞掉。乱序执行能提升 CPI尤其适合单线程重负载代价是功耗大、面积贵。低功耗场景更倾向于顺序核加简单分支预测牺牲峰值性能换能效。这也是为什么近几年的移动端和服务器端都不约而同走向“大小核”组合大核负责突发和高负载任务小核处理后台与轻量任务调度器按任务特性分配让整体落在能效最优的区间。这套设计思路背后没有新公式只是把功耗公式、执行时间公式和统计规律绑在一起做权衡。5. 把公式变成直觉一个完整对比分析的例子5.1 设定两个候选处理器备选方案前面讲了那么多规则与公式不如把它放到一个完整例子里跑一遍。假设某嵌入式产品要在两个候选处理器挑一个跑同一段基准程序指令数相同都是 10 亿条。候选方案主频平均CPI峰值功耗A2.6 GHz1.95 WB2.0 GHz1.38 W只看主频A 明显更高常识会告诉你 A 快。但我们用 CPU 时间公式算一下。5.2 用CPU时间公式和Amdahl定律逐层算账A 的执行时间TA 1e9 × 1.9 / 2.6e9 ≈ 0.731sB 的执行时间TB 1e9 × 1.3 / 2.0e9 0.65s结论很直接B 虽然主频低了 23%但因为平均 CPI 明显更好总执行时间反而比 A 快约 11%。如果当初只看主频做选型选 A 就等于选了一个更慢的方案。这一步已经足够说明主频只是除法式里的一个分母CPI 同样能决定结局。再算能耗用峰值功耗近似简化处理EA 5W × 0.731s ≈ 3.66J EB 8W × 0.65s ≈ 5.2JB 快但能耗高。如果你的设备是电池供电长期跑这种负载A 反而更耐用。性能选型永远要和具体目标绑定。接下来加一点 Amdahl 的味道假设 B 的快并不是全线生效而是只在 40% 的代码段上比 A 快 20%剩下 60% 两者表现相同。A 的总时间是 0.731s其中 40% 约为 0.292sB 在这部分只需 0.233s剩下 60% 是 0.439s。于是 B 整体时间变成 0.672s加速比只有 1.09明显小于直接用平均 CPI 估算的 0.65s 所对应的 1.12。更扎心的是上限即便 B 在那一部分做到无限快总体时间最多降到 0.439s加速比上限也只有 1.67 倍。局部优化的天花板一眼就看穿了。5.3 做这类分析时最常踩的几个坑第一只看主频。前面这个例子已经演示了高频和快之间没有必然关系。第二把峰值功耗当平均功耗。处理器负载是非平稳的DVFS 会让功耗随时间大幅波动。严谨做法是跑负载采集功耗曲线再对时间积分而不是拿一个标称峰值去乘总时间。第三Amdahl 里的 f 拍脑袋填。一定要基于 profiling 数据。f 填错加速比计算结果能差出好几倍整个决策跟着跑偏。第四跨指令集比较 MIPS。MIPS 在 ISA 不同时没有可比性连“谁每秒执行的指令更多”都说明不了更别说执行效率。第五忽略编译器差异。同一份源码同一颗处理器不同编译优化等级可能带来数倍性能差。做对比实验时务必固定工具链版本和优化选项否则得出的结论没法复现。5.4 随手可用的公式速查表最后把这些规则与公式汇成一张表方便以后做方案时快速查询。公式/规则形式主要用途常见误区CPU时间时间 指令数 × CPI × 周期时间处理器/编译器性能分析只看主频忽略CPIAmdahl定律加速比 1 / ((1-f) f/s)评估局部优化整体收益上限f凭感觉填不测profilingGustafson法则加速比 (1-f) N×f可扩展问题并行收益评估把可扩展问题误当固定问题MIPS主频 / (CPI × 10^6)教学、数量级估算跨ISA比较动态功耗P ≈ C × V² × f功耗/能效分析只降频不降压能耗没变能耗E P × t节能策略比较忽略时间维度这张表贴在我工位旁边已经很长时间了。每次有人拿着新方案来找我做性能评估我都会先把问题写成公式再填数最后才谈结论。规则和公式不会替你做决定但它们能逼你把分歧点精确到某一个变量上。团队里争吵不休的时候谁先把问题写成了式子谁通常就离正确答案更近一步。