一尘不染

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

linux

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

无论如何,我想到,如果我可以将内存块标记为不可缓存,那将是很酷的……从理论上讲,这将为其他所有内容在缓存中留出更多空间。

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


阅读 288

收藏
2020-06-02

共1个答案

一尘不染

每个程序员都应该了解的内存(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字节块的地址作为参数传递,直到读取每个高速缓存行。只有这样才能启动下一个缓存行。由于有一些流读取缓冲区,因此可能可以一次从两个内存位置读取

如果在读取时通过存储器以线性顺序读取缓冲区,则对您而言将是完美的。您使用流读取来这样做。当您要修改它们时,缓冲区将按线性顺序进行修改,如果您不希望很快再从同一线程读取它们,则可以使用流式写入来执行。

2020-06-02