我的目标是在没有缓存一致性的情况下读取过时的内存值。我曾尝试使用prefetchnta
执行非临时加载,但未能获取过时的值。我正在考虑执行某种流式内存到内存的直接内存访问,但由于进行当前项目所需的大量背景知识,我遇到了一些小麻烦。目前我正试图搅乱乌德马布夫,但即使这样也进展缓慢。需要注意的是,理想情况下,我希望忽略所有CPU缓存的内容,包括当前CPU。
为了提供我的理由:我正在开发软件,可以用来证明为非易失性存储器编写的程序的正确性。由于CPU缓存是易失性的,因此CPU的写回缓存仍然是易失的,需要观察它们如何写回内存的任意性质。
如果有人能给我一些如何进行的建议,我将不胜感激。我不介意深入研究Linux内核,事实上我现在正在做这件事,我也不介意修改它,我只需要一点正确的指导。
我还没有讨论过这个问题,但我从文档中了解到,对于加载(与NT存储不同(,没有什么可以绕过缓存或覆盖内存类型的强排序,就像普通的WB(回写(一样。甚至NT存储也会驱逐已经缓存的数据,所以它们不会破坏这个或另一个为您正在写的行缓存数据的核心的一致性。
您可以从WC(写组合(内存区域(使用预取或SSE4 movntdqa(进行弱顺序加载,但它们在物理地址级别可能仍然是一致的。
@MargaretBloom评论
IIRC英特尔警告开发人员使用不同缓存类型的多个映射,在这种情况下这可能确实很好。
因此,也许您实际上可以通过同一物理页的多个虚拟映射来绕过缓存一致性。
我不知道是否可以用PCI/PCIe设备进行非相干DMA,但这可能是您在不经过缓存的情况下获得实际DRAM内容的唯一希望。
通常(总是?(现代x86系统上的DMA是缓存一致的,这对性能有好处。为了保持与386和早期没有缓存的CPU的向后兼容性,第一批带缓存的x86 CPU具有缓存一致DMA,直到后来的几代才引入缓存控制指令,因为现有的操作系统没有使用它们。在现代系统中,内存控制器内置在CPU中。因此,在英特尔CPU上,系统代理可以在向内存控制器发送请求的同时,窥探L3标签,以查看一行是否缓存在芯片上的任何位置。或者,Xeon可以直接DMA到三级缓存,而无需数据通过DRAM反弹,这对高带宽NIC来说很好。
有一条INVD
指令使所有缓存无效,而不首先进行写回操作,但我认为这包括共享的L3缓存,可能还有所有其他核心的私有缓存。因此,你不能在Linux系统上实际使用它,因为其他内核可能正在做一些事情;使用它,以及为您感兴趣的进程模拟带有NVDIMM的机器上的电源故障,可能会破坏内核数据结构。
如果您以某种方式使所有其他CPU内核脱机,并禁用仍在运行的一个内核上的中断
- 您可以
wbinvd
(回写+无效(来刷新所有缓存 - 然后运行一些测试中的代码
- 然后是
invd
,看看是什么导致了DRAM
然后重新启用中断。如果在wbinvd
和invd
之间处理任何中断,中断处理程序最终可能会缓存一些内核数据和内存中的一些内核数据,或者使设备驱动程序与硬件不同步。
更新:确实有人尝试过这个:
- 如何运行"invd";禁用SMP支持的指令
- 如何将结构显式加载到L1d缓存中?在有/没有超线程的隔离核心上,CR0.CD=1的INVD的奇怪结果——
invd
运行得非常好,它在错误设计的尝试中破坏了printk
所做的一些存储