c-如何在x86 Windows中刷新CPU缓存?

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

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

英特尔i686平台(也可以使用P4及更高版本)。

user183135 asked 2020-06-27T10:58:10Z
4个解决方案
52 votes

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

指令“ wbinvd”写回修改后的缓存内容,并将缓存标记为空。 它执行一个总线周期,以使外部缓存刷新其数据。 不幸的是,这是一个特权指令。 但是,如果可以在类似DOS的环境下运行测试程序,则可以采用这种方法。 这具有使“ OS”的缓存占用空间保持很小的优点。

此外,还有“ invd”指令,该指令可使高速缓存无效而不将其刷新回主存储器。 这违反了主内存和缓存的一致性,因此您必须自己照顾。 不太推荐。

为了进行基准测试,最简单的解决方案可能是将大内存块复制到标有WC(写合并)而不是WB的区域。 图形卡的内存映射区域是不错的选择,或者您可以自己通过MTRR寄存器将区域标记为WC。

您可以在测试程序中找到一些有关对短例程进行基准测试的资源,以测量时钟周期和性能监控。

Gunther Piez answered 2020-06-27T10:58:45Z
8 votes

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

像偷偷摸摸的说一个大memcpy?

是的,这是最简单的方法,并且将确保CPU刷新所有级别的缓存。 只需从基准测试中排除缓存刷新时间,您就应该很好地了解程序在缓存压力下的性能。

intgr answered 2020-06-27T10:59:15Z
2 votes

不幸的是,没有办法显式刷新缓存。 您有以下几种选择:

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

2.)在x86控制寄存器中启用Cache Disable,并对其进行基准测试。 这也可能会禁用指令缓存,这可能不是您想要的。

3.)使用非临时性指令实现代码的基准测试部分(如果可能)。 尽管这些只是对处理器使用缓存的提示,但仍然可以随意执行所需的操作。

1可能是最简单并且足以满足您的目的的。

编辑:糟糕,我已纠正,有一条指令使x86缓存无效,请参阅drhirsch的答案

Falaina answered 2020-06-27T10:59:57Z
0 votes

x86指令WBINVD回写并使所有缓存无效。 它描述为:

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

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

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

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

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

Lukas Kalbertodt answered 2020-06-27T11:00:41Z
translate from https://stackoverflow.com:/questions/1756825/how-can-i-do-a-cpu-cache-flush-in-x86-windows