1

我想彻底测量和调整我的 C/C++ 代码,以便在 x86_64 系统上更好地使用缓存。我知道如何用计数器测量时间(我的 Windows 机器上的 QueryPerformanceCounter),但我想知道如何测量每个周期的指令或每个周期的读/写相对于工作集。

我应该如何继续测量这些值?

4

3 回答 3

4

现代处理器(即那些不到 20 年的不受限制的处理器)是超标量的,即它们一次执行多条指令(给定正确的指令顺序)。最新的 x86 处理器将 CISC 指令转换为内部 RISC 指令,对它们重新排序并执行结果,甚至具有多个寄存器组,因此可以并行执行使用“相同寄存器”的指令。今天没有任何合理的方法来定义“指令执行所需的时间”。

当前的 CPU比内存快得多(几百条指令是访问内存的典型成本),它们都严重依赖缓存的性能。然后你会得到各种有趣的内核共享(或不共享)缓存部分的效果,......

调优代码以获得最大性能从软件架构开始,然后是程序组织、算法和数据结构选择(这里有一点缓存/虚拟内存意识也很有用)、仔细的编程和(作为最极端的措施来挤出最后 2% 的性能)考虑因素,比如你提到的那些(以及另一个最喜欢的,“在汇编中重写”)。排序是这样的,因为第一级以相同的成本提供了更多的性能。在挖掘之前先测量,程序员是出了名的发现瓶颈不可靠。并考虑重组代码以提高性能的成本,无论是在工作本身,还是在说服自己这个复杂的代码是正确的,以及维护方面。考虑到计算机和人员的相对成本,极端的性能调整几乎没有任何意义(也许对于流行操作系统中经过大量旅行的代码路径,编译器生成的常见代码路径,但几乎没有其他地方)。

于 2013-03-10T15:00:52.343 回答
1

如果你真的对你的代码在哪里访问缓存以及它在哪里访问内存感兴趣,并且处理器在其设计中的使用时间不到 10-15 年,那么处理器中有性能计数器。您需要驱动级软件来访问这些寄存器,因此您可能不想为此编写自己的工具。幸运的是,您不必这样做。

有来自 Intel 的 VTune、来自 AMD 的 CodeAnalyst 和用于 Linux 的 oprofile 等工具(适用于 AMD 和 Intel 处理器)。

有一系列不同的寄存器可以计算实际完成的指令数,处理器等待的周期数。您还可以获得诸如“内存读取次数”、“缓存未命中数”、“TLB 未命中数”、“FPU 指令数”之类的计数。

下一个更棘手的部分当然是尝试解决这些问题中的任何一个,正如另一个答案中提到的那样,程序员并不总是擅长调整这些事情 - 而且这肯定很耗时,更不用说在 X 型处理器上运行良好的东西不一定在 Y 型上运行得很快(早期的 Pentium 4 有一些调整技巧在 AMD 处理器上工作得非常糟糕 - 另一方面,如果你为那个时代的 AMD 处理器调整代码,你得到的代码也能在同代英特尔处理器上运行良好!)

于 2013-03-10T16:26:53.097 回答
0

您可能对读取相对数量的周期的 rdtsc x86 指令感兴趣。

有关在许多编译器中读取计数器的实现,请参见http://www.fftw.org/cycle.h 。

但是,我建议简单地使用 QueryPerformanceCounter 进行测量。实际的周期数很少很重要,要调整代码,您通常只需要能够比较相对时间测量值,并且 rdtsc 有很多陷阱(尽管可能不适用于您描述的情况):

  • 在多处理器系统上,没有一个一致的周期计数器值。
  • 现代处理器经常调整频率,改变相对于周期变化率的时间变化率。
于 2013-03-10T13:30:35.367 回答