Performance 指令级评测:指令指针的含义?
在汇编指令级评测代码时,如果现代CPU不按顺序或顺序执行指令,那么指令指针的位置真正意味着什么?例如,假设以下x64部件代码: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
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.
指令指针将大部分时间花在哪条指令上?我能为他们所有人想出好的理由:
可能需要100秒的周期,因为它是缓存未命中mov-RAX,[RBX]
也需要100秒的周期,但可能与前面的指令并行执行。指令指针位于其中一个或另一个上意味着什么mov RSI,[RBX+RCX]
- 异或R8,R8可能执行无序,并在内存加载完成之前完成,但指令指针可能会留在这里,直到所有以前的指令也完成
生成一个管道暂停,因为它是在缓慢缓存未命中加载到指令中后实际使用add RDX,RAX
值的指令RAX
也会暂停,因为它取决于加载到add RDI,RSI
RSI
例如,可能中断指示
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,以便操作系统可以在该指令处恢复进程的执行。