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

标签 c++ linux operating-system system

我正在阅读 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.

所有自动变量(堆栈上的变量)都是在调用函数时在堆栈上“即时”创建的。那么我怎样才能实现最后一条语句所说的呢?

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

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 exists above is just to bring another related question -- 如果我想为使用堆栈页面和堆页面的东西保留内存怎么办。调用“堆”版本的 reserveStackPages() 会有帮助吗?

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

提前致谢。

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

最佳答案

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

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

您应该首先详细了解进程的虚拟地址空间。为此,proc(5)很有用:从进程内部,您将读取 /proc/self/maps(参见 this ),从外部(例如某些终端),您将执行 cat/proc/1234/maps 用于 pid 1234 的进程。或使用 pmap(1) .

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

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

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

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

如果您确实需要 mlockall(这不太可能),您可以考虑静态链接您的程序(以减少虚拟地址空间中的段)。

另请查看 madvise(2) (也许还有 mincore(2) )。它通常比 mlockall 有用得多。顺便说一句,实际上,您的大部分虚拟内存都在 RAM 中(除非您的系统试验 thrashing ,然后您会立即看到它)。

另请阅读 Operating Systems: Three Easy Pieces了解paging的作用.

附言。纳秒级敏感应用程序没有多大意义(因为软件无法控制的 cache misses)。

关于c++ - 使用 mlockall() 进行实时应用程序的最佳方式(纳秒敏感),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49345177/

相关文章:

c - 如何在不忙等待的情况下呈现计数信号量的监视器实现?

c++ - 第一次方法调用比使用相同数据的连续调用花费的时间长 10 倍

c - 使用 pwrite() API 时出现错误 no set to EIO

linux - AWS/Ubuntu 存档服务器似乎已关闭?

c++ - 编译后的程序如何与操作系统交互?

linux - 在 Jenkins 上,如何检测服务器是 Windows 还是 Linux?

c++ - 在不强制转换的情况下混合索引和指针算法时避免 C4365

c++ - 从 C++11 模板参数包创建空指针

c++ - 为什么程序会这样做? C++

linux - rsync bash 脚本复制目录结构?