I am writing code for a real-time program running in an embedded Linux system. As it is critical that we don't stall unpredictably on page faults, I would like to prefault in the stack so that the region that we use is guaranteed to be covered by a mlockall()
call.
我正在为在嵌入式Linux系统中运行的实时程序编写代码。因为关键是我们不会在页面错误上无法预测,我想在堆栈中预先故障,以便我们使用的区域保证被mlockall()调用覆盖。
For the main thread this is simple enough; simply do a few big alloca()
s and make sure to do a write every few pages. This works because at program startup, the stack limit is much larger than the amount we need; we end up allocating exactly how much we prefault in.
对于主线程来说这很简单;只需做一些大的alloca(),并确保每隔几页写一次。这是有效的,因为在程序启动时,堆栈限制远远大于我们需要的数量;我们最终确定了我们预先确定了多少。
However, for pthread stacks, will they be allocated using MAP_GROWSDOWN
as well? If so, what's the best way to prefault them in, considering that:
但是,对于pthread堆栈,它们是否也将使用MAP_GROWSDOWN进行分配?如果是这样的话,考虑到以下因素是什么是预防它们的最好方法:
- We don't know how much of the (known) stack size is consumed by libc startup
- We don't want to allocate more memory to the stack than is necessary
我们不知道libc启动消耗了多少(已知的)堆栈大小
我们不希望为堆栈分配比必要更多的内存
I'm aware that I can use pthread_attr_setstack
to pass in a manually-allocated stack, but this complicates cleaning up after the thread, and so I'd prefer to avoid this if possible.
我知道我可以使用pthread_attr_setstack来传递一个手动分配的堆栈,但是这会使线程之后的清理变得复杂,所以如果可能的话我宁愿避免这种情况。
As such, what's the best way to perform this prefaulting? It would be sufficient if there was an easy way to find out the lower bound of the stack (just above the guard page); at this point I could simply write to every page from there to the current stack pointer.
因此,执行此预测的最佳方法是什么?如果有一种简单的方法来找出堆栈的下限(就在保护页面上方)就足够了;在这一点上,我可以简单地从那里写入每个页面到当前的堆栈指针。
Note that portability is not a concern; we'd be happy to have a solution that works only under x86-32 and Linux.
请注意,可移植性不是问题;我们很高兴有一个仅适用于x86-32和Linux的解决方案。
2 个解决方案
#1
3
If you use pthread_attr_setstacksize
you can still have automatic allocation with a known size.
如果使用pthread_attr_setstacksize,仍然可以使用已知大小进行自动分配。
glibc nptl leaves guard pages between the stacks, so you could also set a SEGV
handler and simply scribble until you fault and then longjmp
out of the loop. That'd be ugly!
glibc nptl在栈之间留下了保护页面,所以你也可以设置一个SEGV处理程序并简单地涂鸦直到你出错,然后longjmp离开循环。那太丑了!
Edit: A really nonportable way would be to open /proc/self/maps
to find your stacks!
编辑:一个真正不可移植的方式是打开/ proc / self / maps来找到你的堆栈!
#2
1
yes. if you have called mlockall(MCL_CURRENT | MCL_FUTURE) before pthread_create, page fault for thread stack will happen when starting the thread. and after that, there will be no page fault again while accessing stack in the thread. so people always set the suitable thread size for the new created thread to avoid lock too much memory for the future coming threads. take a look at: https://rt.wiki.kernel.org/index.php/Threaded_RT-application_with_memory_locking_and_stack_handling_example
是。如果在pthread_create之前调用了mlockall(MCL_CURRENT | MCL_FUTURE),则在启动线程时会发生线程堆栈的页面错误。之后,在线程中访问堆栈时不会再出现页面错误。所以人们总是为新创建的线程设置合适的线程大小,以避免为将来的线程锁定太多内存。看看:https://rt.wiki.kernel.org/index.php/Threaded_RT-application_with_memory_locking_and_stack_handling_example
if you change the thread stack size to 7MB, you will see: Initial count : Pagefaults, Major:0 (Allowed >=0), Minor:190 (Allowed >=0) mlockall() generated : Pagefaults, Major:0 (Allowed >=0), Minor:393 (Allowed >=0) malloc() and touch generated : Pagefaults, Major:0 (Allowed >=0), Minor:25633 (Allowed >=0) 2nd malloc() and use generated: Pagefaults, Major:0 (Allowed 0), Minor:0 (Allowed 0)
如果将线程堆栈大小更改为7MB,您将看到:初始计数:Pagefaults,Major:0(Allowed> = 0),Minor:190(Allowed> = 0)mlockall()生成:Pagefaults,Major:0(允许) > = 0),Minor:393(允许> = 0)malloc()并触摸生成:Pagefaults,Major:0(Allowed> = 0),Minor:25633(Allowed> = 0)2nd malloc()并使用生成: Pagefaults,Major:0(允许0),Minor:0(允许0)
Look at the output of ps -leyf, and see that the RSS is now about 100 [MB] Press to exit I am an RT-thread with a stack that does not generate page-faults during use, stacksize=7340032 Caused by creating thread : Pagefaults, Major:0 (Allowed >=0), Minor:1797 (Allowed >=0) Caused by using thread stack : Pagefaults, Major:0 (Allowed 0), Minor:0 (Allowed 0)
查看ps -leyf的输出,看看RSS现在大约100 [MB]按退出我是一个带有堆栈的RT线程,在使用过程中不会生成页面错误,stacksize = 7340032由创建线程引起:Pagefaults,Major:0(允许> = 0),次要:1797(允许> = 0)由使用线程堆栈引起:Pagefaults,Major:0(允许0),Minor:0(允许0)
1797 page faults happen while creating thread, it is about 7MB. -barry
创建线程时发生1797页错误,大约7MB。 -barry
#1
3
If you use pthread_attr_setstacksize
you can still have automatic allocation with a known size.
如果使用pthread_attr_setstacksize,仍然可以使用已知大小进行自动分配。
glibc nptl leaves guard pages between the stacks, so you could also set a SEGV
handler and simply scribble until you fault and then longjmp
out of the loop. That'd be ugly!
glibc nptl在栈之间留下了保护页面,所以你也可以设置一个SEGV处理程序并简单地涂鸦直到你出错,然后longjmp离开循环。那太丑了!
Edit: A really nonportable way would be to open /proc/self/maps
to find your stacks!
编辑:一个真正不可移植的方式是打开/ proc / self / maps来找到你的堆栈!
#2
1
yes. if you have called mlockall(MCL_CURRENT | MCL_FUTURE) before pthread_create, page fault for thread stack will happen when starting the thread. and after that, there will be no page fault again while accessing stack in the thread. so people always set the suitable thread size for the new created thread to avoid lock too much memory for the future coming threads. take a look at: https://rt.wiki.kernel.org/index.php/Threaded_RT-application_with_memory_locking_and_stack_handling_example
是。如果在pthread_create之前调用了mlockall(MCL_CURRENT | MCL_FUTURE),则在启动线程时会发生线程堆栈的页面错误。之后,在线程中访问堆栈时不会再出现页面错误。所以人们总是为新创建的线程设置合适的线程大小,以避免为将来的线程锁定太多内存。看看:https://rt.wiki.kernel.org/index.php/Threaded_RT-application_with_memory_locking_and_stack_handling_example
if you change the thread stack size to 7MB, you will see: Initial count : Pagefaults, Major:0 (Allowed >=0), Minor:190 (Allowed >=0) mlockall() generated : Pagefaults, Major:0 (Allowed >=0), Minor:393 (Allowed >=0) malloc() and touch generated : Pagefaults, Major:0 (Allowed >=0), Minor:25633 (Allowed >=0) 2nd malloc() and use generated: Pagefaults, Major:0 (Allowed 0), Minor:0 (Allowed 0)
如果将线程堆栈大小更改为7MB,您将看到:初始计数:Pagefaults,Major:0(Allowed> = 0),Minor:190(Allowed> = 0)mlockall()生成:Pagefaults,Major:0(允许) > = 0),Minor:393(允许> = 0)malloc()并触摸生成:Pagefaults,Major:0(Allowed> = 0),Minor:25633(Allowed> = 0)2nd malloc()并使用生成: Pagefaults,Major:0(允许0),Minor:0(允许0)
Look at the output of ps -leyf, and see that the RSS is now about 100 [MB] Press to exit I am an RT-thread with a stack that does not generate page-faults during use, stacksize=7340032 Caused by creating thread : Pagefaults, Major:0 (Allowed >=0), Minor:1797 (Allowed >=0) Caused by using thread stack : Pagefaults, Major:0 (Allowed 0), Minor:0 (Allowed 0)
查看ps -leyf的输出,看看RSS现在大约100 [MB]按退出我是一个带有堆栈的RT线程,在使用过程中不会生成页面错误,stacksize = 7340032由创建线程引起:Pagefaults,Major:0(允许> = 0),次要:1797(允许> = 0)由使用线程堆栈引起:Pagefaults,Major:0(允许0),Minor:0(允许0)
1797 page faults happen while creating thread, it is about 7MB. -barry
创建线程时发生1797页错误,大约7MB。 -barry