Performance 指令级评测:指令指针的含义?

Performance 指令级评测:指令指针的含义?,performance,assembly,profiling,x86-64,low-level,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

在汇编指令级评测代码时,如果现代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秒的周期,但可能与前面的指令并行执行。指令指针位于其中一个或另一个上意味着什么
  • 异或R8,R8可能执行无序,并在内存加载完成之前完成,但指令指针可能会留在这里,直到所有以前的指令也完成
  • add RDX,RAX
    生成一个管道暂停,因为它是在缓慢缓存未命中加载到指令中后实际使用
    RAX
    值的指令
  • add RDI,RSI
    也会暂停,因为它取决于加载到
    RSI

CPU认为只有架构寄存器(RAX、RBX等)和特定的指令指针(IP)是虚构的。程序员和编译器的目标就是这种虚构

然而,正如您所指出的,现代CPU并不是串行或按顺序执行的。在程序员/用户请求IP之前,就像量子物理一样,IP是正在执行的指令波;这样处理器就可以尽可能快地运行程序。当您请求当前IP(例如,通过调试器断点或探查器中断)时,处理器必须重新创建您期望的虚构,以便折叠此波形(所有“正在运行”的指令),将寄存器值收集回架构名称,并为执行调试器例程构建上下文,等等

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


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

这是一个好问题,但在中,这并不重要。 这其实并不重要,因为你要找的是速度缺陷。 这些都是代码正在做的事情,需要时钟时间,可以做得更好,也可以根本不做。示例:
-花费I/O时间在DLL中查找实际上不需要查找的资源。
-在内存分配例程中花费时间创建和释放可以简单重复使用的对象。
-在可以被记忆的函数中重新计算事物。
... 这只是我脑子里的一小部分

你最大的敌人是一种自鸣得意的倾向,说“我不会有意识地写任何bug。为什么我会写呢?”当然,你知道这就是你测试软件的原因。但同样的情况也适用于速度错误,如果你不知道如何找到那些错误,你会认为没有,这是一种说“我的代码没有可能的加速,除了可能一个分析器可以告诉我如何减少几个周期。”

在我半个世纪的经验中,没有一个代码像第一次写的那样不包含速度错误。更重要的是,还有一个巨大的倍增效应,你移除的每一个速度错误都会使剩下的错误更加明显。作为一个人为的例子,假设bug a占时钟时间的90%,bug B占9%。如果你只修复了B,那没什么大不了的——代码快了11%。如果你只修了一个,那很好-它快了10倍。但是如果你把两者都修好,那真的很好——速度快了100倍。修理A使B变大


因此,在性能调整中,您最需要的是找到速度错误,而不是遗漏任何错误。完成所有这些之后,您就可以开始循环剃须了。

您能解释一下硬件性能监控计数器在这种情况下是如何工作的吗?例如,Linux具有
perf
子系统,该子系统提供基于PMC的统计分析。内核是否只是生成一个高频中断,然后根据你的很好的类比,该中断将折叠IP波函数并读取PMC,然后将该PMC的当前值分配给当前找到的IP(在波函数折叠之后)?然后重置PMCs并从中断中恢复?那么当上下文切换发生时,同样的情况会发生吗?操作系统将存储最早的未完成指令的上下文,并且必须重新执行无序执行的指令?是。上下文切换(通常)依赖于计时器中断。在任何中断时,硬件都会为操作系统提供下一条指令的IP,以便操作系统可以在该指令处恢复进程的执行。