使用 mlockall() 进行实时应用程序的最佳方式(纳秒敏感)

Optimal Way of Using mlockall() for Real-time Application (nanosecond sensitive)

我正在阅读 mlockall() 的联机帮助页:http://man7.org/linux/man-pages/man2/mlock.2.html

它提到

Real-time processes that are using mlockall() to prevent delays on page 
faults should reserve enough locked stack pages before entering the time-
critical section, so that no page fault can be caused by function calls.  This 
can be achieved by calling a function that allocates a sufficiently large 
automatic variable (an array) and writes to the memory occupied by this array in 
order to touch these stack pages.  This way, enough pages will be mapped for the 
stack and can be locked into RAM.  The dummy writes ensure that not even copy-
on-write page faults can occur in the critical section.

我对这个说法有点困惑:

This can be achieved by calling a function that allocates a sufficiently large 
automatic variable (an array) and writes to the memory occupied by this array in 
order to touch these stack pages.

调用函数时,所有自动变量(堆栈上的变量)都会在堆栈上创建"on the fly"。那么我怎样才能实现最后一句话所说的呢?

例如,假设我有这个功能:

void foo() {
char a;
uint16_t b;
std::deque<int64_t> c;
// do something with those variables
}

或者这是否意味着在我调用任何函数之前,我应该在 main() 中调用这样的函数:

void reserveStackPages() {
int64_t stackPage[4096/8 * 1024 * 1024];
memset(stackPage, 0, sizeof(stackPage));
}

如果是,如果我先在堆上分配 stackPage 变量,写入然后释放,会有什么不同吗?可能是的,因为堆和堆栈是 RAM 中的 2 个不同区域?

std::deque 上面的存在只是为了提出另一个相关问题——如果我想为使用堆栈页面和堆页面的东西保留内存怎么办。调用 "heap" 版本的 reserveStackPages() 会有帮助吗?

目标是尽量减少应用程序中的所有抖动(是的,我知道还有很多其他事情要看,例如 TLB 未命中等;只是尝试一次处理一种抖动,然后慢慢处理进入全部)。

提前致谢。

P.S。如果重要的话,这适用于低延迟交易应用程序。

您通常不需要使用 mlockall,除非您编写(或多或少的困难)real-time 应用程序(我实际上从未使用过它)。

如果确实需要,最好用 C(而不是真正的 C++)编写代码的大部分 real-time 部分,因为您肯定想了解内存分配的细节。请注意,除非您深入研究 std::deque 实现 ,否则您不会确切知道它位于何处(可能大部分数据都是堆分配的,即使您的 c 是一个 automatic variable).

您应该首先详细了解您进程的虚拟地址space。为此,proc(5) is useful: from inside your process, you'll read /proc/self/maps (see this), from outside (e.g. some terminal) you'll do cat /proc/1234/maps for a process of pid 1234. Or use pmap(1).

because heap and stack are 2 different regions in the RAM?

事实上,您进程的地址 space 包含许多段(在 /proc/1234/maps 中列出),远不止两个。通常每个动态链接的共享库(例如libc.so)都会带来一些段。

在您的终端中尝试 cat /proc/self/mapscat /proc/$$/maps 以获得关于虚拟地址 space 的更好直觉。在我的机器上,第一个给出 cat 过程的 19 段 - 每个显示为一行 - zsh(我的 shell)过程的第二个 97 段。

为了确保您的堆栈有足够的 space,您确实可以调用一个函数来分配足够大的自动变量,例如您的 reserveStackPages。请注意,调用堆栈的大小实际上是有限的(通常只有几兆字节,另请参阅 setrlimit(2))。

如果你真的需要 mlockall(这不太可能),你可以考虑静态链接你的程序(在你的虚拟地址 space 中有更少的段)。

同时查看 madvise(2) (and perhaps mincore(2)). It is generally much more useful than mlockall. BTW, in practice, most of your virtual memory is in RAM (unless your system experiments thrashing,然后您会立即看到它)。

另请阅读 Operating Systems: Three Easy Pieces to understand the role of paging

PS。 Nano-second 敏感应用程序没有多大意义(因为 cache misses 软件无法控制)。