我已经反汇编了一个用MSVC v140编译的小型C++程序,并试图估计每条指令的周期,以便更好地理解代码设计如何影响性能。我一直在关注Mike Acton关于"Data-Oriented Design and C++"的CppCon 2014演讲,特别是我链接到的部分。
在这本书中,他指出了这些线条:
movss 8(%rbx), %xmm1
movss 12(%rbx), %xmm0
然后,他声称这些2 x 32位读取可能在同一缓存行上,因此花费大约200个周期。
Intel 64 and IA-32 Architectures Optimization Reference Manual一直是一个很好的资源,特别是 “附录C -指令延迟和吞吐量”。然而,在第C-15页的 “表C-16.流SIMD扩展单精度浮点指令” 中,指出movss只有1个周期(除非我理解这里的延迟是什么意思错了...如果是这样,我怎么读这个东西?)
我知道theoretical prediction of execution time永远不会是正确的,但无论如何,这是很重要的学习。这两个命令是如何200个周期的,以及我如何才能学习在这个片段之外的执行时间?
我已经开始读一些关于CPU流水线的东西……也许大部分的周期都是在那里被拾取的?
我对实际测量硬件性能计数器并不感兴趣,我只是想学习如何合理地读取ASM和周期。
1条答案
按热度按时间kulphzqa1#
正如您已经指出的,MOVSS指令的理论吞吐量和延迟为1个周期。您正在查看正确的文档(Intel Optimization Manual)。Agner Fog(在评论中提到)在他的Intruction Tables中测量了相同的数字(AMD具有更高的延迟)。
这就引出了第一个问题:您正在研究哪种特定的微体系结构?这可能会产生很大的差异,即使是同一个供应商。Agner Fog报告称,MOVSS在AMD Bulldozer上的延迟为2-6cy,具体取决于源和目标(寄存器与内存)。在研究计算机体系结构的性能时,请务必记住这一点。
200 cy最有可能是高速缓存未命中,正如已经指出的那样,在注解中。您从优化手册中获得的任何内存访问指令的数字都是假设数据驻留在第一级高速缓存中(L1)。现在,如果您以前的指令从未接触过数据该高速缓存行(对于Intel和AMD x86为64字节)将需要从存储器加载到最后一级高速缓存中,从那里加载到第二级高速缓存中,然后进入L1,最后进入XMM寄存器L3-L2和L2-L1之间的传输具有吞吐量在当前的Intel微体系结构上,每个高速缓存线的两个周期(而不是延迟!)。并且存储器带宽可以用于估计L3和存储器之间的吞吐量(例如,具有40 GB/s的可实现存储器带宽的2GHzCPU将具有每个高速缓存线3.2个周期的吞吐量)。高速缓存线或存储器块通常是高速缓存和存储器可以在其上操作的最小单元,它们在微体系结构之间不同,并且甚至可以在体系结构内不同,这取决于该高速缓存级别(L1、L2等)。
现在,这是所有的吞吐量而不是延迟,这将无法帮助您估计上面所描述的内容。你需要一遍又一遍地执行指令(至少1/10 s)以获得周期精确测量。通过更改说明,您可以决定是否要测量延迟(通过包括指令之间的依赖性)或吞吐量(通过使指令输入独立于先前指令的结果)。要测量缓存和内存访问,您需要预测访问是否会进入缓存,这可以使用layer conditions完成。
Intel Architecture Code Analyzer是一个用于估计英特尔CPU指令执行(延迟和吞吐量)的工具,它支持多个微架构,最高可支持Haswell。延迟预测要谨慎对待,因为估计延迟比估计吞吐量要困难得多。