Edd*_*ett 8 c benchmarking assembly inline-assembly rdtsc
我正在研究使用x86 CPU中的时间戳寄存器(TSR)来测量基准性能.它是一个有用的寄存器,因为它以单调时间单位测量,不受时钟速度变化的影响.很酷.
这是一份英特尔文档,显示了使用TSR进行可靠基准测试的asm片段,包括使用cpuid进行管道同步.见第16页:
要读取开始时间,它说(我注释了一下):
__asm volatile (
"cpuid\n\t" // writes e[abcd]x
"rdtsc\n\t" // writes edx, eax
"mov %%edx, %0\n\t"
"mov %%eax, %1\n\t"
//
:"=r" (cycles_high), "=r" (cycles_low) // outputs
: // inputs
:"%rax", "%rbx", "%rcx", "%rdx"); // clobber
Run Code Online (Sandbox Code Playgroud)
我不知道为什么暂存寄存器用来取的价值观edx
和eax
.为什么不删除MOVS和读取TSR值右出的edx
和eax
?像这样:
__asm volatile(
"cpuid\n\t"
"rdtsc\n\t"
//
: "=d" (cycles_high), "=a" (cycles_low) // outputs
: // inputs
: "%rbx", "%rcx"); // clobber
Run Code Online (Sandbox Code Playgroud)
通过这样做,您可以保存两个寄存器,从而降低C编译器需要溢出的可能性.
我对吗?或者那些MOV在某种程度上是战略性的?
(我同意你确实需要临时寄存器来读取停止时间,因为在那种情况下指令的顺序是相反的:你有rdtscp,...,cpuid.cpuid指令破坏了rdtscp的结果).
谢谢
你是对的,这个例子很笨重. 通常if mov
是inline-asm语句中的第一个或最后一个指令,你做错了,并且应该使用约束来告诉编译器你想要输入的位置,或输出的位置.
请参阅我的GNU C内联asm指南/链接集合,以及内联汇编标记wiki 中的其他链接.(对于asm来说,x86标签wiki也充满了好东西.)
或者rdtsc
具体来说,请参阅获取CPU周期数?对于__rdtsc()
@ Mysticial的答案中的内在和良好的内联asm.
它以单调时间单位测量,不受时钟速度变化的影响.
是的,在过去10年左右的CPU上.
对于分析,在核心时钟周期中有时间而不是挂钟时间通常更有用,因此您的微基准测试结果不依赖于省电/ turbo. 性能计数器可以做到这一点以及更多.
尽管如此,如果实时是你想要的,rdtsc
那么它是获得它的最低开销方式.
并且重新:评论中的讨论:是的cpuid
是序列化,确保rdtsc
在CPUID之后直到指令才能开始执行.您可以在RDTSC之后添加另一个CPUID,但这会增加测量开销,我认为在准确度/精度方面会给出接近零的增益.
LFENCE是一种更便宜的替代品,对RDTSC很有用.该指令裁判手动输入文档的事实,它不会让后面的指令开始执行,直到它和以前的指令已退休(从ROB /核心的乱序部分RS).请参阅是否加载并存储重新排序的唯一指令?,并且对于使用它的具体示例,请参阅clflush以通过C函数使高速缓存行无效.与真正的序列化指令不同cpuid
,它不会刷新存储缓冲区.
(在最近的AMD的CPU没有幽灵缓解启用,lfence
甚至不是部分序列化,并在4运行每个时钟根据昂纳雾的测试. 是LFENCE序列化的AMD处理器?)
玛格丽特布鲁姆挖出了这个有用的链接,这也证实了LFENCE根据英特尔的SDM序列化RDTSC,还有一些关于如何围绕RDTSC进行序列化的东西.
归档时间: |
|
查看次数: |
803 次 |
最近记录: |