指令级分析:指令指针的含义?

时间:2013-06-09 13:35:50

标签: performance assembly profiling x86-64 low-level

在汇编指令级别分析代码时,如果现代CPU不按顺序或按顺序执行指令,那么指令指针的位置到底意味着什么呢?例如,假设以下x64汇编代码:

mov RAX, [RBX];         // Assume a cache miss here.
mov RSI, [RBX + RCX];   // Another cache miss.             
xor R8, R8;        
add RDX, RAX;           // Dependent on the load into RAX.
add RDI, RSI;           // Dependent on the load into RSI.

指令指针大部分时间花在哪条指令上?我可以为所有人想出好的论据:

  • mov RAX, [RBX]大概需要100个周期,因为它是缓存缺失。
  • mov RSI, [RBX + RCX]也需要100个周期,但可能与前一个指令并行执行。它甚至意味着指令指针位于其中一个或另一个上?
  • xor R8, R8可能在内存加载完成之前执行乱序并完成,但指令指针可能会保留在此处,直到所有先前的指令都完成为止。
  • add RDX, RAX生成一个管道停顿,因为它是指示RAX的值实际上是在缓慢的缓存未命中加载后实际使用的。
  • add RDI, RSI也会停滞,因为它依赖于RSI的负载。

2 个答案:

答案 0 :(得分:8)

CPU保持虚构,即只有架构寄存器(RAX,RBX等),并且有一个特定的指令指针(IP)。程序员和编译器以这个虚构为目标。

然而正如您所指出的那样,现代CPU不能按顺序执行或按顺序执行。在程序员/用户请求IP之前,它就像量子物理学,IP是一波正在执行的指令;所有这些都使处理器能够尽快运行程序。当您请求当前IP(例如,通过调试器断点或探查器中断)时,处理器必须重新创建您期望的虚构,以便它折叠此波形(全部"在飞行中"指令),收集寄存器值返回到体系结构名称,并构建用于执行调试器例程的上下文等。

在此上下文中,有一个IP指示处理器应该恢复执行的指令。在无序执行期间,该指令是尚未完成的最早的指令,即使在中断时处理器可能正好在该点之后获取指令。

例如,中断可能表示mov RSI, [RBX + RCX];为IP,但xor已经执行并完成;但是,当处理器在中断后恢复执行时,它将重新执行xor。

答案 1 :(得分:1)

这是一个很好的问题,但是在the kind of performance tuning I do中,没关系。 这并不重要,因为您要查找的是速度错误。 代码正在做的这些事情需要花费时间,并且可能做得更好或者根本不做。例子:
-花费I / O时间在DLL中寻找实际上不需要寻找的资源。
-将时间花在创建和释放可以简单重用的对象的内存分配例程中。
-重新计算可以记忆化的功能中的内容。
...这只是我头顶上的一些

您最大的敌人是一种自我祝贺的倾向,他会说“我不会有意识地编写任何错误。为什么会这样?”当然,您知道这就是测试软件的原因。但是速度错误也是如此,如果您不知道如何找到这些,则认为没有错误,这是一种说法,“我的代码没有可能的加速,除非探查器可以告诉我如何剃除几个周期。”

在我半个世纪的经验中,没有没有代码,它最初编写时没有任何速度错误。此外,还有巨大的乘数效应,您删除的每个速度错误都会使其余错误更加明显。作为一个人为的示例,假设错误A占时钟时间的90%,错误B占时钟时间的9%。如果只修复B,那就没关系了-代码快了11%。如果只修复A,那很好-快10倍。但是,如果同时解决这两个问题,那真的很好-快100倍。固定A使B大。

因此,在性能调优中最需要做的就是查找速度错误,不要错过任何一个。完成所有这些操作后,就可以开始进行循环剃须了。