如何在不污染缓存的情况下从内存加载值?

Ann*_*nna 15 x86 assembly caching

我想在不污染缓存的情况下读取内存位置.我正在研究X86 Linux机器.我尝试使用MOVNTDQA汇编程序指令:

  asm("movntdqa %[source], %[dest] \n\t"
      : [dest] "=x" (my_var) : [source] "m" (my_mem[0]) : "memory");
Run Code Online (Sandbox Code Playgroud)

my_mem是一个用new分配的int*,my_var是一个int.

这种方法有两个问题:

  1. 代码编译但运行时出现"非法指令"错误.有什么想法吗?
  2. 我不确定用new分配什么类型的内存.我会假设WB.根据文档,MOVNTDQA指令仅适用于USWC内存类型.我如何知道我正在处理的内存类型?

总结一下,我的问题是:

如何在不污染X86机器上的缓存的情况下读取内存位置?我的方法是否正确,是否可以修复?

谢谢.

Gun*_*iez 7

使用%% xmm作为目标的movntdqa指令(从内存加载)的问题是此insn仅适用于SSE4.1和on.这意味着到目前为止只有较新的Core 2(45 nm)或i7.另一种方式(将数据存储到存储器)在早期的SSE版本中可用.

对于这个指令,处理器将数据移动到一个非常小的极少数读缓冲区中(英特尔没有指定确切的大小,但假设它在16字节的范围内),它很容易获得,但被踢出经过一些其他的负荷.

并且它不会污染其他缓存,因此如果您有流数据,那么您的方法是可行的.

记住,之后你需要使用一个sfence insn.

预取存在两种变体:prefetcht0(预取所有高速缓存中的数据)和prefetchnt(预取非时态数据).通常在所有缓存中进行预取是正确的做法,对于流数据循环,后者会更好,如果你随后使用流指令.

您可以将它与您想要在不久的将来使用的对象的地址一起使用,如果您有循环,通常会提前进行一些迭代.prefetch insn不会等待或阻塞,它只是让处理器开始在指定的内存位置获取数据.


moo*_*dow 0

MOVNTDQA 仅适用于 SSE。

为什么你试图避免使用缓存?CPU 通常非常擅长决定何时从缓存中剔除哪些内容。如果确实需要,一种方法是安排您正在读取的内存区域的别名映射到您的地址空间,并禁用缓存并从那里读取。

如果您想要实现的目标实际上是最小化代码对当时保存在缓存中的另一个函数工作集的影响,那么这应该可以通过发出适当的预取和无效指令来实现。

  • @moonshadow:处理器并不总是擅长决定缓存什么。这就是为什么有 movntdqa 指令的明确原因。它用于流数据,一旦使用,就再也不会碰过(至少不会太快;-))。至于辅助线程,如果有另一个可用的线程,这可能是可行的,否则无法完全使用 - 超线程浮现在脑海中。但在大多数情况下,通过两个线程完成全部工作并使用显式预取指令,您将获得更好的结果。 (3认同)