简体   繁体   English

使用mlockall()进行实时应用的最佳方法(纳秒级敏感)

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

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

It mentions 它提到

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.

I am a bit confused by this statement: 我对这个陈述感到困惑:

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.

All the automatic variables (variables on stack) are created "on the fly" on the stack when the function is called. 调用函数时,所有自动变量(堆栈中的变量)都是在堆栈中“即时”创建的。 So how can I achieve what the last statement says? 那么,如何才能实现上一条语句的内容呢?

For example, let's say I have this function: 例如,假设我具有以下功能:

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

Or does it mean before I call any function, I should call a function like this in main(): 或者这意味着在我调用任何函数之前,我应该在main()中调用这样的函数:

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

If yes, does it make a difference if I first allocate the stackPage variable on heap, write and then free? 如果是的话,如果我先在堆上分配stackPage变量,然后写入然后释放,这会有所不同吗? Probably yes, because heap and stack are 2 different region in the RAM? 可能是的,因为RAM中的堆和堆栈是2个不同的区域?

std::deque exists above is just to bring up another related question -- what if I want to reserve memory for things using both stack pages and heap pages. 上面存在的std :: deque只是在提出另一个相关的问题-如果我想同时使用堆栈页面和堆页面来为某些事情保留内存该怎么办。 Will calling "heap" version of reserveStackPages() help? 调用“堆”版本的reserveStackPages()会有所帮助吗?

The goal is to minimize all the jitters in the application (yes, I know there are many other things to look at such as TLB miss, etc; just trying to deal with one kind of jitter at once, and slowly progressing into all). 目标是最大程度地减少应用程序中的所有抖动(是的,我知道还有很多其他事情要考虑,例如TLB遗漏等;只是尝试一次处理一种抖动,然后慢慢处理所有抖动)。

Thanks in advance. 提前致谢。

PS This is for a low latency trading application if it matters. PS:这对于低延迟交易应用程序很重要。

You generally don't need to use mlockall , unless you code (more or less hard) real-time applications (I actually never used it). 通常,您不需要使用mlockall ,除非您为实时应用程序(或多或少用硬编码)(我实际上从未使用过)。

If you do need it, you'll better code in C (not in genuine C++) the most real-time parts of your code, because you surely want to understand the details of memory allocation. 如果确实需要它,则最好使用C(而不是真正的C ++)代码中最实时的部分,因为您肯定希望了解内存分配的详细信息。 Notice that unless you dive into std::deque implementation , you don't exactly know where it is sitting (probably most of the data is heap allocated, even if your c is an automatic variable ). 请注意,除非您深入了解std::deque 实现 ,否则您将无法完全知道它的位置(即使c自动变量 ,大多数数据也可能是堆分配的)。

You should first understand in details the virtual address space of your process. 您应该首先详细了解进程的虚拟地址空间。 For that, proc(5) is useful: from inside your process, you'll read /proc/self/maps (see this ), from outside (eg some terminal) you'll do cat /proc/1234/maps for a process of pid 1234. Or use pmap(1) . 为此, proc(5)很有用:从您的进程内部,您将读/proc/self/maps (请参阅 ),从外部(例如某个终端)您将为cat /proc/1234/maps做一个pid 1234的处理。或使用pmap(1)

because heap and stack are 2 different regions in the RAM? 因为堆和堆栈是RAM中2个不同的区域?

In fact, your process' address space contains many segments (listed in /proc/1234/maps ), much more that two. 实际上,您的进程的地址空间包含许多段(在/proc/1234/maps列出),远不止两个。 Typically every dynamically linked shared library (such as libc.so ) brings a few segments. 通常,每个动态链接的共享库(例如libc.so )都会带来一些段。

Try cat /proc/self/maps and cat /proc/$$/maps in your terminal to get a better intuition about virtual address spaces. 在终端中尝试使用cat /proc/self/mapscat /proc/$$/maps可以更好地了解虚拟地址空间。 On my machine, the first gives 19 segments of the cat process -each displayed as a line- and the second 97 segments of the zsh (my shell) process. 在我的机器上,第一个给出了cat进程的19个部分(每个显示为一行),第二个给出了zsh (我的shell)进程的97个部分。

To ensure that your stack has enough space, you indeed could call a function allocating a large enough automatic variable, like your reserveStackPages . 为了确保堆栈有足够的空间,您确实可以调用分配足够大的自动变量的函数,例如reserveStackPages Beware that call stacks are practically of limited size (a few megabytes usually, see also setrlimit(2) ). 注意,调用栈实际上是有限的大小(通常为几兆字节,另请参见setrlimit(2) )。

If you really need mlockall (which is unlikely) you might consider linking statically your program (to have less segments in your virtual address space). 如果确实需要mlockall (这不太可能),则可以考虑静态链接程序(以在虚拟地址空间中减少段)。

Look also into madvise(2) (and perhaps mincore(2) ). 还要研究madvise(2) (也许还有mincore(2) )。 It is generally much more useful than mlockall . 通常,它比mlockall有用得多。 BTW, in practice, most of your virtual memory is in RAM (unless your system experiments thrashing , and then you'll see it immediately). 顺便说一句,在实践中,大多数的虚拟内存是在RAM(除非你的系统实验颠簸 ,然后你会马上看到它)。

Read also Operating Systems: Three Easy Pieces to understand the role of paging . 另请阅读操作系统:三篇简单的文章,以了解分页的作用。

PS. PS。 Nano-second sensitive applications does not make much sense (because of cache misses that the software does not control). 纳秒级敏感的应用程序没有多大意义(因为该软件无法控制的高速缓存未命中 )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM