是否有可能在用户空间中在Linux上分配不可缓存的内存块?

时间:2009-05-20 00:20:19

标签: linux memory caching

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

无论如何,我想到如果我将一块内存标记为不可缓存的话会很酷......从理论上讲,这会为缓存中的其他一切留下更多空间。

那么,他们是否有办法在Linux中标记为不可缓存的内存块?

4 个答案:

答案 0 :(得分:8)

如何避免使用这样的数据来污染缓存What Every Programmer Should Know About Memory(PDF) - 这是从红帽开发的角度编写的,非常适合您。但是,大多数都是跨平台的。

您想要的是“非时间访问”,并告诉处理器期望您现在正在阅读的值暂时不再需要。然后处理器避免缓存该值。

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

  

在阅读方面,处理器,直到   最近,除了缺乏支持   使用非时间访问的弱提示   (NTA)预取指令。有   没有相当于写入组合的   读,这是特别糟糕的   无法缓解的记忆如   内存映射I / O.英特尔,与   SSE4.1扩展,引入了NTA   负载。它们是使用a实现的   少量流媒体负载   缓冲区;每个缓冲区包含一个缓存   线。第一个movntdqa指令   对于给定的缓存行,将加载一个   可能会将缓存行缓存到缓冲区中   替换另一个缓存行。   随后的16字节对齐访问   将为相同的缓存行提供服务   来自加载缓冲区,成本很低。   除非有其他理由要做   因此,不会加载缓存行   进入缓存,从而启用   加载大量内存   没有污染缓存。该   编译器提供了内在的   这条指令:

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

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

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

答案 1 :(得分: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

答案 2 :(得分:1)

您可能还想查看处理器关联以减少缓存抖动。

答案 3 :(得分:0)

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

PS:如果可以,您可能想要以不同的方式来处理数据?