【问题标题】:Is it possible to allocate, in user space, a non cacheable block of memory on Linux?是否可以在 Linux 上的用户空间中分配不可缓存的内存块?
【发布时间】:2010-10-27 12:07:44
【问题描述】:

我的应用程序中有一堆缓冲区(其中 25 到 30 个),它们相当大 (.5mb) 并且可以同时访问。更糟糕的是,它们中的数据通常只读取一次,并且经常更新(例如每秒 30 次)。有点像非最佳缓存使用的完美风暴。

无论如何,我突然想到,如果我可以将一块内存标记为不可缓存,那就太酷了……理论上,这会在缓存中为其他所有内容留出更多空间。

那么,他们是一种在 Linux 中获取标记为不可缓存的内存块的方法吗?

【问题讨论】:

  • 我认为这会损害性能——将所有频繁的更新写入都标记为不可缓存,而不是写入缓存。
  • 缓存仅在这种情况下有用,如果写入不是连续的并且多个写入落在同一缓存行上。如果写入是半随机的,并且当再次写入相同的位置时,该位置已从缓存中刷新,则意义不大。
  • @Michael - 在这种情况下,更新应该绕过缓存。

标签: linux memory caching


【解决方案1】:

What Every Programmer Should Know About Memory (PDF) 中介绍了如何避免此类数据污染缓存 - 这是从 Red Hat 开发的角​​度编写的,非常适合您。不过大部分都是跨平台的。

您想要的称为“非临时访问”,并告诉处理器预期您现在正在读取的值将在一段时间内不再需要。然后处理器避免缓存该值。

请参阅我上面链接的 PDF 的第 49 页。它使用 intel 内在函数来围绕缓存进行流式传输。

在读取端,处理器,直到 最近,除了缺乏支持 使用非临时访问的弱提示 (NTA) 预取指令。有 不等同于写组合 读取,这对 不可缓存的内存,例如 内存映射 I/O。英特尔,与 SSE4.1 扩展,引入 NTA 负载。它们是使用 少量流式加载 缓冲器;每个缓冲区包含一个缓存 线。第一条 movntdqa 指令 对于给定的缓存行将加载一个 缓存行到缓冲区中,可能 替换另一个缓存行。 随后的 16 字节对齐访问 将提供相同的缓存行 以很少的成本从负载缓冲器中获取。 除非有其他理由 所以,缓存行将不会被加载 进入缓存,从而使 加载大量内存 不污染缓存。这 编译器提供了一个内在的 这条指令:

#include <smmintrin.h>
__m128i _mm_stream_load_si128 (__m128i *p); 

这个内在函数应该被多次使用,地址为 16 字节块作为 参数,直到每个缓存行 读。只有这样才能下一个缓存 线开始。由于有几个 流式读取缓冲区可能是 可以从两个内存中读取 一次定位

如果在读取时,缓冲区以线性顺序通过内存读取,那将是完美的选择。您使用流式读取来执行此操作。当您想要修改它们时,缓冲区会按线性顺序修改,如果您不希望很快从同一个线程再次读取它们,您可以使用流式写入来做到这一点。

【讨论】:

  • 非临时加载指令不是只为写组合(WC)内存指定的吗?看来 MOVNTDQA 的行为依赖于写回 (WB) 内存(这是用户空间应用程序将使用的)的实现。简而言之,要获得非临时负载,似乎使用不可缓存的内存是正确的方法
【解决方案2】:

经常更新的数据其实就是缓存的完美应用。正如 jdt 所提到的,现代 CPU 缓存非常大,0.5mb 可能很适合缓存。不过,更重要的是,对未缓存内存的读取-修改-写入非常慢 - 初始读取必须在内存上阻塞,然后写入操作也必须在内存上阻塞才能提交。雪上加霜的是,CPU 可能会通过将数据加载到缓存中来实现无缓存内存,然后立即使缓存行无效 - 从而使您处于一个肯定比以前更糟的位置。

在您尝试像这样超越 CPU 之前,您确实应该对整个程序进行基准测试,看看真正的减速在哪里。现代分析器(例如 valgrind 的 cachegrind)可以测量缓存未命中,因此您可以发现这是否也是导致速度下降的重要原因。

另一方面,更实际的说明是,如果您每秒执行 30 个 RMW,那么在最坏的情况下,缓存占用量大约为 1920 字节。这只是现代 Core 2 处理器的 L1 大小的 1/16,并且可能会在系统的一般噪音中丢失。所以不用太担心:)

也就是说,如果“同时访问”是指“同时被多个线程访问”,请注意缓存线在 CPU 之间弹跳。未缓存的 RAM 无济于事——如果有的话,情况会更糟,因为数据每次都必须一路返回物理 RAM,而不是可能通过更快的 CPU 间总线——这是唯一的方法避免它成为问题的方法是尽量减少访问共享数据的频率。有关更多信息,请参阅http://www.ddj.com/hpc-high-performance-computing/217500206

【讨论】:

  • Read-modify-write 非常慢,但如果您不通过少量指令写入整个高速缓存行,这只会成为问题。 CPU 可以检测整个缓存行是否被修改并避免读取。
  • 锁定另一个CPU在缓存中的内存也应该很慢,所以我会小心你断言锁定内存以进行另一个缓存中的修改比它更快从系统中读取相同的内存。
【解决方案3】:

您可能还想研究处理器关联性以减少缓存抖动。

【讨论】:

    【解决方案4】:

    在某些处理器架构上,有一些特殊指令可用于将某些高速缓存行标记为禁用。但是,这些通常是特定于体系结构的,并且取决于一些汇编指令。因此,我建议您参考处理器架构文档并弄清楚如何在汇编中进行操作。然后,您可以使用带有 GCC 的内联汇编来激活它。不过这会让性能很差。

    PS:如果可以的话,您可能想考虑一种不同的方式来处理数据?

    【讨论】:

    • 是的,在它是特权指令的处理器上。然后,对于 Linux,您需要在内核空间中找到一个放置它的位置,并编写某种用户空间函数来访问它。
    猜你喜欢
    • 1970-01-01
    • 2021-10-29
    • 1970-01-01
    • 2020-02-19
    • 2016-04-21
    • 1970-01-01
    • 2015-06-04
    • 2011-08-16
    • 2015-08-08
    相关资源
    最近更新 更多