有没有办法在x86 CPU下不接触L1/L2/L3高速缓存的情况下读写内存?
x86 CPU中的高速缓存是否完全由硬件管理?
编辑:我想这样做是因为我想采样内存速度并查看内存性能是否下降。
有没有办法在x86 CPU下不接触L1/L2/L3高速缓存的情况下读写内存?
x86 CPU中的高速缓存是否完全由硬件管理?
编辑:我想这样做是因为我想采样内存速度并查看内存性能是否下降。
CPU在硬件中确实管理其自己的缓存,但x86为您提供了一些影响此管理方式的方法。
要访问没有缓存的内存,您可以:
使用x86非暂态指令,它们意味着告诉CPU您不会再次重用这些数据,因此保留在缓存中没有意义。x86中的这些指令通常称为movnt*(后缀根据数据类型而异,例如用于将普通整数加载到通用寄存器的movnti)。还有用于流式加载/存储的指令,也使用类似的技术,但对于高BW流(连续加载完整行时)更为适合。 要使用这些,请将它们编码为内联汇编,或使用编译器提供的内部函数,其中大多数称之为_mm_stream_*系列
更改特定区域的内存类型为不可缓存。由于您声明不希望禁用所有缓存(这样也包括代码、堆栈、页面映射等),因此您可以将基准测试数据集所在的特定区域定义为不可缓存,使用MTRRs(内存类型范围寄存器)。有几种方法可以做到这一点,您需要阅读一些文档。
最后一种选择是正常获取行,这意味着它确实最初被缓存,但然后强制清除所有缓存级别使用专用的clflush指令(或完整的wbinvd如果您想刷新整个缓存)。确保正确地隔离这些操作,以便您可以保证它们已完成(当然不要将它们作为延迟的一部分进行测量)。
话虽如此,如果您只是想计时读取内存,那么您可能会得到糟糕的结果,因为大多数CPU处理非暂态或不可缓存的访问方式“效率低下”。如果您只是为了强制从内存中读取数据,则最好通过顺序访问足够大的数据集来操纵缓存LRU,以使大多数LRU方案(并非全部!)首先删除最旧的行,因此下次您再次进行包装时,它们必须来自内存。
需要注意的是,为了使其起作用,您需要确保硬件预取器不起作用(并且意外覆盖您想要测量的延迟) - 要么禁用它,要么使访问跨度足够大,以使其无效。
clflush
命令是相对较新的。我认为它只在服务器上可用。 - Nathan Fellmanmovntdqa
)除非在 WC 存储器上使用,否则不会绕过缓存。当前的 CPU 仍然忽略普通(WB)存储器区域上的 NT 提示。 - Peter CordesLeeor已经列出了与您的任务相关的最“专业”解决方案。我会尝试提出另一个建议,可以使用简单的C代码实现同样的结果。这个想法是创建一个内核,类似于在HPCC Challenge基准测试中发现的“全局随机访问”。
内核的想法是通过大量的8B值数组随机跳转,通常该数组大小为物理内存的1/2(因此如果您有16 GB的RAM,则需要一个8GB的数组导致8B的1G元素)。对于每个跳跃,您可以读取、写入或RMW目标位置。
这很可能测量RAM延迟,因为随机跳跃使缓存非常低效。你将得到极低的缓存命中率,如果你对数组进行足够的操作,你将能够测量内存的实际性能。这种方法还使预取非常低效,因为没有可检测的模式。
您需要考虑以下问题: