CPI 与 IPC
这两个基本指标分别代表:
每周期指令数(IPC,Instructions Per Cycle)——平均每个周期退休的指令数量。
其中 INST_RETIRED.ANY 统计已退休指令的数量,CPU_CLK\_UNHALTED.THREAD 统计线程未处于停机状态时的核心周期数。
- 每指令周期数(CPI,Cycles Per Instruction)——平均退休一条指令所花费的周期数。
使用哪个指标取决于个人偏好。我更倾向于使用 IPC,因为它更易于比较。对于 IPC,我们希望每个周期执行尽可能多的指令,因此 IPC 越高越好。对于 CPI,则恰好相反:我们希望每条指令花费的周期数尽可能少,因此 CPI 越低越好。使用"越高越好"的指标进行比较更为简单,因为你不必每次都在脑海中进行反转。在本书的其余部分,我们将主要使用 IPC,当然使用 CPI 也完全没有问题。
IPC 与 CPU 时钟频率之间的关系非常有趣。从广义上讲,性能 = 工作量 / 时间,其中工作量可以用指令数表示,时间以秒为单位。程序运行的秒数可以计算为 总周期数 / 频率:
可以看出,性能与 IPC 和频率成正比。如果提升这两个指标中的任何一个,程序的性能都会提升。
从基准测试的角度来看,IPC 和频率是两个独立的指标。我见过一些工程师错误地将它们混为一谈,认为提高频率就会提高 IPC。但这是不正确的。如果将处理器的时钟从 5 GHz 降低到 1 GHz,对于许多应用程序来说,IPC 仍然相同。1 这听起来可能很令人困惑,尤其是因为 IPC 与 CPU 时钟密切相关。然而,频率只告诉我们单个时钟周期的速度,而 IPC 则统计每个周期完成的工作量。因此,从基准测试的角度来看,IPC 完全取决于处理器的设计,与频率无关。乱序(Out-of-order)核心通常具有比顺序(in-order)核心高得多的 IPC。当你增大 CPU 缓存的大小或改进分支预测时,IPC 通常会提升。
当然,如果你问硬件架构师,他们肯定会告诉你 IPC 和频率之间存在依赖关系。从 CPU 设计的角度来看,可以故意降低处理器的时钟频率,这会使每个周期变长,从而有可能在每个周期内完成更多工作。最终,你会得到更高的 IPC 但更低的频率。不同的硬件厂商对这个性能方程采取了不同的策略。例如,Intel 和 AMD 的芯片通常频率非常高,近期的 Intel 13900KS 处理器开箱即提供 6 GHz 的睿频(Turbo)频率,无需超频。另一方面,Apple M1/M2 芯片频率较低,但通过更高的 IPC 来弥补。较低的频率有助于降低功耗。较高的 IPC 通常需要更复杂的设计、更多的晶体管和更大的芯片面积。这里不深入探讨所有的设计权衡,因为那是另一本书的话题。
IPC 对于评估硬件和软件效率都很有用。硬件工程师使用该指标来比较 CPU 世代和不同厂商的 CPU。由于 IPC 是衡量 CPU 微架构(microarchitecture)性能的指标,工程师和媒体经常用它来表示相对于上一代的改进幅度。但是,要进行公平的比较,需要在相同的频率下运行两个系统。
IPC 也是评估软件的有用指标。它让你直观地了解应用程序中的指令在 CPU 流水线中的推进速度。在本章后续部分,你将看到几个具有不同 IPC 的生产级应用程序。内存密集型(Memory-intensive)应用程序通常具有较低的 IPC(0--1),而计算密集型(computationally intensive)工作负载往往具有较高的 IPC(4--6)。
Linux perf 用户可以通过以下方式测量工作负载的 IPC:
{% math_inline %} perf stat -e cycles,instructions -- a.exe
2369632 cycles
1725916 instructions # 0,73 insn per cycle
# or as simple as:
{% endmath_inline %} perf stat -- ./a.exe
1. 当降低 CPU 频率时,内存速度相对于 CPU 变得更快。这可能会掩盖实际的内存瓶颈,并人为地提高 IPC。 ↩