如何在x86 Windows中执行CPU缓存刷新?

时间:2009-11-18 15:34:12

标签: c windows x86 cpu cpu-cache

我有兴趣在Windows中强制执行CPU缓存刷新(出于基准测试的原因,我想模拟从CPU缓存中没有数据开始),最好是基本的C实现或Win32调用。

是否有一种已知的方法可以通过系统调用执行此操作,甚至可以像执行大型memcpy那样偷偷摸摸地进行操作?

Intel i686平台(P4及以上版本也可以)。

4 个答案:

答案 0 :(得分:52)

幸运的是,有多种方法可以显式刷新缓存。

指令“wbinvd”写回修改的缓存内容并将缓存标记为空。它执行一个总线周期,以使外部缓存刷新其数据。不幸的是,这是一项特权指导。但是,如果可以在DOS之类的东西下运行测试程序,那么这就是要走的路。这样做的好处是可以保持“OS”的缓存占用空间非常小。

此外,还有“invd”指令,它使缓存无效将它们刷回主内存。这违反了主内存和缓存的一致性,因此您必须自己处理。不是真的推荐。

出于基准测试目的,最简单的解决方案可能是将大内存块复制到标有WC(写入组合)而不是WB的区域。图形卡的内存映射区域是一个很好的候选区域,或者您可以通过MTRR寄存器自己将区域标记为WC。

您可以在Test programs for measuring clock cycles and performance monitoring.

找到一些有关基准短程序基准的资源

答案 1 :(得分:8)

有强制CPU刷新某些缓存行(例如CLFLUSH)的x86汇编指令,但它们非常模糊。特别是CLFLUSH只刷新L1缓存中的选定地址。

  像一个大型记忆复制品一样偷偷摸摸的东西?

是的,这是最简单的方法,并确保CPU刷新所有级别的缓存。只需从您的工作台中排除缓存刷新时间,您就应该知道您的程序在缓存压力下的执行情况。

答案 2 :(得分:2)

遗憾的是,无法显式刷新缓存。您可以选择以下几种方式:

1。)通过在您进行基准测试的代码的迭代之间执行一些非常大的内存操作来激活缓存。

2。)在x86 Control Registers中启用缓存禁用并对其进行基准测试。这可能也会禁用指令缓存,这可能不是你想要的。

3。)使用Non-Temporal instructions实现代码的部分基准(如果可能)。虽然这些只是处理器关于使用缓存的提示,但它仍然可以自由地做它想要的。

1对您的目的来说可能是最简单和最充分的。

编辑:哎呀,我更正有一条指令让x86缓存无效,请参阅drhirsch的回答

答案 3 :(得分:1)

x86指令WBINVD 将回写并使所有缓存无效。 is described as

  

将处理器内部缓存中所有修改的缓存行写回到主内存,并使内部缓存无效(刷新)。然后,该指令发出一个特殊功能的总线周期,该总线周期指示外部高速缓存也写回修改后的数据,并发出另一个总线周期以指示应该使外部高速缓存无效。

重要的是,该指令只能在ring0(即操作系统)中执行。因此,您的userland程序不能简单地使用它。在Linux上,您可以编写一个内核模块,该模块可以按需执行该指令。实际上,已经有人编写了这样的内核模块:https://github.com/batmac/wbinvd

幸运的是,内核模块的代码很小,因此您实际上可以在将代码从Internet上的陌生人加载到内核之前进行检查。您可以通过读取WBINVD来使用该模块(并触发执行/proc/wbinvd指令),例如通过cat /proc/wbinvd

但是,我发现该指令(或至少是此内核模块)确实很慢。在我的i7-6700HQ上,我估计它要花费750µs!这个数字对我来说似乎真的很高,因此我在测量此数字时可能会犯一个错误-请记住这一点!该指令的说明只是说:

  

完成WBINVD所需的时间或周期将因大小和不同缓存层次结构的其他因素而有所不同。