rdtsc
使用序列化指令执行合理测量所需的内容.
众所周知,很多人cpuid
以前都在 使用rdtsc
.
rdtsc
需要从上方和下方序列化(读取:必须退出之前的所有指令,并且必须在测试代码开始之前退出).
不幸的是,第二个条件经常被忽略,因为cpuid
这个任务是一个非常糟糕的选择(它破坏了输出rdtsc
).
在寻找替代方案时,人们会认为在他们的名字中有"围栏"的说明会有用,但这也是不真实的.直接来自英特尔:
MFENCE不会序列化指令流.
几乎序列化的指令,将在以前的商店不需要完成的任何测量中执行lfence
.
简单地说,lfence
确保在任何先前指令在本地完成之前没有新指令开始.请参阅我的这个答案,以获得有关当地情况的更详细解释.
它也不会像存在那样耗尽存储缓冲区mfence
,也不会像寄存器那样破坏寄存器cpuid
.
因此,除非您明确希望在测试开始/结束之前完成之前的存储(但不是之前执行!),否则lfence / rdtsc / lfence
指令序列更好mfence / rdtsc
,mfence
除非您明确无用rdstc
.
如果您检测重新排序的测试是assert(t2 > t1)
我认为您将测试什么.
抛出return
可能会或可能不会阻止CPU rdtsc
及时查看重新排序的调用,不太可能(尽管可能!)CPU将重新排序两个,rdtsc
即使一个正好在另一个之后.
试想一下,我们有一个rdtsc2
被精确地喜欢rdtsc
,但写入ecx:ebx
1.
执行
rdtsc rdtsc2
很可能是ecx:ebx > edx:eax
因为CPU 之前没有理由执行.
重新排序并不意味着随机排序,它意味着如果当前的指令无法执行,则查找其他指令.
但是它不依赖于任何先前的指令,因此当OoO核心遇到它时,它不太可能被延迟.
然而,特殊的内部微观建筑细节可能会使我的论文无效,因此在我之前的陈述中可能是这个词.rdtsc2
rdtsc
rdtsc
1我们不需要这个改变的指令:寄存器重命名将会这样做,但是如果你不熟悉它,这将有所帮助.
rdtsc
使用序列化指令执行合理测量所需的内容.
众所周知,很多人cpuid
以前都在 使用rdtsc
.
rdtsc
需要从上方和下方序列化(读取:必须退出之前的所有指令,并且必须在测试代码开始之前退出).
不幸的是,第二个条件经常被忽略,因为cpuid
这个任务是一个非常糟糕的选择(它破坏了输出rdtsc
).
在寻找替代方案时,人们会认为在他们的名字中有"围栏"的说明会有用,但这也是不真实的.直接来自英特尔:
MFENCE不会序列化指令流.
几乎序列化的指令,将在以前的商店不需要完成的任何测量中执行lfence
.
简单地说,lfence
确保在任何先前指令在本地完成之前没有新指令开始.请参阅我的这个答案,以获得有关当地情况的更详细解释.
它也不会像存在那样耗尽存储缓冲区mfence
,也不会像寄存器那样破坏寄存器cpuid
.
因此,除非您明确希望在测试开始/结束之前完成之前的存储(但不是之前执行!),否则lfence / rdtsc / lfence
指令序列更好mfence / rdtsc
,mfence
除非您明确无用rdstc
.
如果您检测重新排序的测试是assert(t2 > t1)
我认为您将测试什么.
抛出return
可能会或可能不会阻止CPU rdtsc
及时查看重新排序的调用,不太可能(尽管可能!)CPU将重新排序两个,rdtsc
即使一个正好在另一个之后.
试想一下,我们有一个rdtsc2
被精确地喜欢rdtsc
,但写入ecx:ebx
1.
执行
rdtsc rdtsc2
很可能是ecx:ebx > edx:eax
因为CPU 之前没有理由执行.
重新排序并不意味着随机排序,它意味着如果当前的指令无法执行,则查找其他指令.
但是它不依赖于任何先前的指令,因此当OoO核心遇到它时,它不太可能被延迟.
然而,特殊的内部微观建筑细节可能会使我的论文无效,因此在我之前的陈述中可能是这个词.rdtsc2
rdtsc
rdtsc
1我们不需要这个改变的指令:寄存器重命名将会这样做,但是如果你不熟悉它,这将有所帮助.