我正在测试一些内部操作的行为。当我注意到_mm_mfence()从用户空间发出加载指令时,我感到很惊讶,但它不计入L1数据高速缓存中-未命中,命中或填充缓冲区命中。我正在使用诸如MEM_INST_RETIRED和MEM_LOAD_RETIRED的papi本地事件来读取性能计数器。这段代码:
for(int i=0; i < 1000000; i++){
_mm_mfence();
}
计数ALL_LOADS:737030,L1_HIT:99,L1_MISS:10,FB_HIT:25。 而没有mfence,读取计数器的开销是这样的: ALL_LOADS:125,L1_HIT:94,L1_MISS:11,FB_HIT:24
我检查了一下,科学和科学没有这种影响。我正在使用-O3进行编译。从编译的文件中,我猜它调用了__builtin_ia32_mfence函数,但是在它上找不到太多。
我通常了解_mm_mfence()的功能以及为什么使用它,但是现在的问题更多是关于它如何工作的。如果有人可以解释或提供任何相关文章以了解这种行为,那将是很好的。
答案 0 :(得分:3)
_mm_mfence()
仅编译为mfence
指令,从结构上来说,这不是加载或存储
它解码后的一个或多个微指令可能会微体系结构运行在加载端口上,但是会算作负载。
您正在使用哪个CPU?如果是Skylake,我假设您已经更新了微代码,因此mfence
的花费比Agner Fog的表列出的要高。 (并且它阻止了乱序的非内存微指令执行程序,例如lfence
。请参阅Are loads and stores the only instructions that gets reordered?,在Skylake对mfence
而言,显然有些英特尔CPU并未这样做。)>