[v18.x backport] child_process: improve spawn performance on Linux by aduh95 · Pull Request #50098 · nodejs/node

added 2 commits

October 9, 2023 12:43
Original commit message:

    [base] add build flag to use MADV_DONTFORK

    Embedders like Node.js and Electron expose fork(2)/execve(2) to their
    users. Unfortunately when the V8 heap is very large, these APIs become
    rather slow on Linux, due to the kernel needing to do all the
    bookkeeping for the forked process (in clone's dup_mmap and execve's
    exec_mmap). Of course, this is useless because the forked child thread
    will never actually need to access the V8 heap.

    Add a new build flag v8_enable_private_mapping_fork_optimization which
    marks all pages allocated by OS::Allocate as MADV_DONTFORK. This
    improves the performance of Node.js's fork/execve combination by 10x on
    a 600 MB heap.

    Fixed: v8:7381
    Change-Id: Ib649f774d4a932b41886313ce89acc369923699d
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4602858
    Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
    Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
    Cr-Commit-Position: refs/heads/main@{#88447}

Refs: v8/v8@1a782f6
PR-URL: nodejs#48523
Fixes: nodejs#25382
Fixes: nodejs#14917
Refs: nodejs/performance#93
Refs: nodejs/performance#89
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
Reviewed-By: Debadree Chatterjee <debadree333@gmail.com>
Speed up child_process.spawn by enabling the new V8 build flag which
makes fork/exec faster.

Here are the results of running the existing benchmark. Note that this
optimization helps more for applications with larger heaps, so this is
somewhat of an underestimate of the real world performance benefits.

```console
$ ./node benchmark/compare.js --runs 15 \
        --new ./node \
        --old ~/node-v20/out/Release/node \
        --filter params child_process > cpr
$ node-benchmark-compare cpr
                                 confidence improvement  (***)
methodName='exec' n=1000                ***     60.84 % ±5.43%
methodName='execFile' n=1000            ***     53.72 % ±3.33%
methodName='execFileSync' n=1000        ***      9.10 % ±0.84%
methodName='execSync' n=1000            ***     10.44 % ±0.97%
methodName='spawn' n=1000               ***     53.10 % ±2.90%
methodName='spawnSync' n=1000           ***      8.64 % ±1.22%

  0.01 false positives, when considering a 0.1% risk acceptance (***)
```

Fixes: nodejs#25382
Fixes: nodejs#14917
Refs: nodejs/performance#93
Refs: nodejs/performance#89
PR-URL: nodejs#48523
Refs: v8/v8@1a782f6
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
Reviewed-By: Debadree Chatterjee <debadree333@gmail.com>

@nodejs-github-bot nodejs-github-bot added build

Issues and PRs related to build files or the CI.

needs-ci

PRs that need a full CI run.

tools

Issues and PRs related to the tools directory.

v18.x

Issues that can be reproduced on v18.x or PRs targeting the v18.x-staging branch.

v8 engine

Issues and PRs related to the V8 dependency.

labels

Oct 9, 2023

This was referenced

Nov 14, 2023

targos pushed a commit that referenced this pull request

Nov 26, 2023
Original commit message:

    [base] add build flag to use MADV_DONTFORK

    Embedders like Node.js and Electron expose fork(2)/execve(2) to their
    users. Unfortunately when the V8 heap is very large, these APIs become
    rather slow on Linux, due to the kernel needing to do all the
    bookkeeping for the forked process (in clone's dup_mmap and execve's
    exec_mmap). Of course, this is useless because the forked child thread
    will never actually need to access the V8 heap.

    Add a new build flag v8_enable_private_mapping_fork_optimization which
    marks all pages allocated by OS::Allocate as MADV_DONTFORK. This
    improves the performance of Node.js's fork/execve combination by 10x on
    a 600 MB heap.

    Fixed: v8:7381
    Change-Id: Ib649f774d4a932b41886313ce89acc369923699d
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4602858
    Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
    Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
    Cr-Commit-Position: refs/heads/main@{#88447}

Refs: v8/v8@1a782f6
PR-URL: #48523
Backport-PR-URL: #50098
Fixes: #25382
Fixes: #14917
Refs: nodejs/performance#93
Refs: nodejs/performance#89
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
Reviewed-By: Debadree Chatterjee <debadree333@gmail.com>

targos pushed a commit that referenced this pull request

Nov 26, 2023
Speed up child_process.spawn by enabling the new V8 build flag which
makes fork/exec faster.

Here are the results of running the existing benchmark. Note that this
optimization helps more for applications with larger heaps, so this is
somewhat of an underestimate of the real world performance benefits.

```console
$ ./node benchmark/compare.js --runs 15 \
        --new ./node \
        --old ~/node-v20/out/Release/node \
        --filter params child_process > cpr
$ node-benchmark-compare cpr
                                 confidence improvement  (***)
methodName='exec' n=1000                ***     60.84 % ±5.43%
methodName='execFile' n=1000            ***     53.72 % ±3.33%
methodName='execFileSync' n=1000        ***      9.10 % ±0.84%
methodName='execSync' n=1000            ***     10.44 % ±0.97%
methodName='spawn' n=1000               ***     53.10 % ±2.90%
methodName='spawnSync' n=1000           ***      8.64 % ±1.22%

  0.01 false positives, when considering a 0.1% risk acceptance (***)
```

Fixes: #25382
Fixes: #14917
Refs: nodejs/performance#93
Refs: nodejs/performance#89
PR-URL: #48523
Backport-PR-URL: #50098
Refs: v8/v8@1a782f6
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
Reviewed-By: Debadree Chatterjee <debadree333@gmail.com>

@aduh95 aduh95 deleted the backport-fork-improvements branch

January 12, 2024 11:31

sercher added a commit to sercher/graaljs that referenced this pull request

Apr 25, 2024
Original commit message:

    [base] add build flag to use MADV_DONTFORK

    Embedders like Node.js and Electron expose fork(2)/execve(2) to their
    users. Unfortunately when the V8 heap is very large, these APIs become
    rather slow on Linux, due to the kernel needing to do all the
    bookkeeping for the forked process (in clone's dup_mmap and execve's
    exec_mmap). Of course, this is useless because the forked child thread
    will never actually need to access the V8 heap.

    Add a new build flag v8_enable_private_mapping_fork_optimization which
    marks all pages allocated by OS::Allocate as MADV_DONTFORK. This
    improves the performance of Node.js's fork/execve combination by 10x on
    a 600 MB heap.

    Fixed: v8:7381
    Change-Id: Ib649f774d4a932b41886313ce89acc369923699d
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4602858
    Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
    Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
    Cr-Commit-Position: refs/heads/main@{#88447}

Refs: v8/v8@1a782f6
PR-URL: nodejs/node#48523
Backport-PR-URL: nodejs/node#50098
Fixes: nodejs/node#25382
Fixes: nodejs/node#14917
Refs: nodejs/performance#93
Refs: nodejs/performance#89
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
Reviewed-By: Debadree Chatterjee <debadree333@gmail.com>

sercher added a commit to sercher/graaljs that referenced this pull request

Apr 25, 2024
Speed up child_process.spawn by enabling the new V8 build flag which
makes fork/exec faster.

Here are the results of running the existing benchmark. Note that this
optimization helps more for applications with larger heaps, so this is
somewhat of an underestimate of the real world performance benefits.

```console
$ ./node benchmark/compare.js --runs 15 \
        --new ./node \
        --old ~/node-v20/out/Release/node \
        --filter params child_process > cpr
$ node-benchmark-compare cpr
                                 confidence improvement  (***)
methodName='exec' n=1000                ***     60.84 % ±5.43%
methodName='execFile' n=1000            ***     53.72 % ±3.33%
methodName='execFileSync' n=1000        ***      9.10 % ±0.84%
methodName='execSync' n=1000            ***     10.44 % ±0.97%
methodName='spawn' n=1000               ***     53.10 % ±2.90%
methodName='spawnSync' n=1000           ***      8.64 % ±1.22%

  0.01 false positives, when considering a 0.1% risk acceptance (***)
```

Fixes: nodejs/node#25382
Fixes: nodejs/node#14917
Refs: nodejs/performance#93
Refs: nodejs/performance#89
PR-URL: nodejs/node#48523
Backport-PR-URL: nodejs/node#50098
Refs: v8/v8@1a782f6
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
Reviewed-By: Debadree Chatterjee <debadree333@gmail.com>

sercher added a commit to sercher/graaljs that referenced this pull request

Apr 25, 2024
Original commit message:

    [base] add build flag to use MADV_DONTFORK

    Embedders like Node.js and Electron expose fork(2)/execve(2) to their
    users. Unfortunately when the V8 heap is very large, these APIs become
    rather slow on Linux, due to the kernel needing to do all the
    bookkeeping for the forked process (in clone's dup_mmap and execve's
    exec_mmap). Of course, this is useless because the forked child thread
    will never actually need to access the V8 heap.

    Add a new build flag v8_enable_private_mapping_fork_optimization which
    marks all pages allocated by OS::Allocate as MADV_DONTFORK. This
    improves the performance of Node.js's fork/execve combination by 10x on
    a 600 MB heap.

    Fixed: v8:7381
    Change-Id: Ib649f774d4a932b41886313ce89acc369923699d
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4602858
    Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
    Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
    Cr-Commit-Position: refs/heads/main@{#88447}

Refs: v8/v8@1a782f6
PR-URL: nodejs/node#48523
Backport-PR-URL: nodejs/node#50098
Fixes: nodejs/node#25382
Fixes: nodejs/node#14917
Refs: nodejs/performance#93
Refs: nodejs/performance#89
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
Reviewed-By: Debadree Chatterjee <debadree333@gmail.com>

sercher added a commit to sercher/graaljs that referenced this pull request

Apr 25, 2024
Speed up child_process.spawn by enabling the new V8 build flag which
makes fork/exec faster.

Here are the results of running the existing benchmark. Note that this
optimization helps more for applications with larger heaps, so this is
somewhat of an underestimate of the real world performance benefits.

```console
$ ./node benchmark/compare.js --runs 15 \
        --new ./node \
        --old ~/node-v20/out/Release/node \
        --filter params child_process > cpr
$ node-benchmark-compare cpr
                                 confidence improvement  (***)
methodName='exec' n=1000                ***     60.84 % ±5.43%
methodName='execFile' n=1000            ***     53.72 % ±3.33%
methodName='execFileSync' n=1000        ***      9.10 % ±0.84%
methodName='execSync' n=1000            ***     10.44 % ±0.97%
methodName='spawn' n=1000               ***     53.10 % ±2.90%
methodName='spawnSync' n=1000           ***      8.64 % ±1.22%

  0.01 false positives, when considering a 0.1% risk acceptance (***)
```

Fixes: nodejs/node#25382
Fixes: nodejs/node#14917
Refs: nodejs/performance#93
Refs: nodejs/performance#89
PR-URL: nodejs/node#48523
Backport-PR-URL: nodejs/node#50098
Refs: v8/v8@1a782f6
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
Reviewed-By: Debadree Chatterjee <debadree333@gmail.com>