C语言 spawn会显著降低子进程执行大分配的速度

siotufzp  于 2023-04-05  发布在  其他
关注(0)|答案(1)|浏览(105)

Ruby Process.spawn显著降低了子进程的执行速度。
出现这种情况的最小程序是以下用-O0编译的C程序:

#include <stdlib.h>
#include <string.h>

int main(void) {
    int n = 1024*1024*128;
    for (int i = 0; i < 100; ++i) {
        char *mem = malloc(n);
        memset(mem, 1, n);
        free(mem);
    }
}

当通过bash或python或C作为子进程执行时,执行时间为1.8秒。
但是当使用下面的ruby脚本时,它需要5秒的时间来执行:

Process.wait(Process.spawn("./a.out"))

为什么会发生这种情况,我该如何预防?
编辑:我使用的是Ruby版本3.1.2p20

uujelgoq

uujelgoq1#

原因是参考ruby实现在Linux上关闭了透明巨大页面(THP)。此设置在execve()中保留,如man page中所述:

PR_SET_THP_DISABLE (since Linux 3.15)
              Set  the  state  of  the  "THP  disable"  flag for the calling
              thread.  If arg2 has a nonzero value, the flag is set,  other‐
              wise  it  is cleared.  Setting this flag provides a method for
              disabling transparent huge pages for jobs where the code  can‐
              not  be  modified,  and using a malloc hook with madvise(2) is
              not an option (i.e., statically allocated data).  The  setting
              of  the "THP disable" flag is inherited by a child created via
              fork(2) and is preserved across execve(2).

关闭透明的大页面:

$ echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled

将使运行时一致。
添加

prctl(PR_SET_THP_DISABLE, 0 /* or 1 */, 0, 0, 0);

测试程序也将使运行时一致。
The change that introduced this in ruby可能没有考虑到这个设置是跨execve()保留的,因此它会对子进程中的大分配重工作负载产生负面影响。

相关问题