-
Notifications
You must be signed in to change notification settings - Fork 29.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ENOMEM with exec/spawn - child process tries to reserve as much mem as parent #25382
Comments
This could be the underlying cause of this very popular SO issue for some users: https://stackoverflow.com/questions/26193654/node-js-catch-enomem-error-thrown-after-spawn |
I think something like this would be handled/solved at the libuv level, not node. The libuv issue tracker is here. |
Duplicate of |
Not really a dupe. Both are caused by using Edit May 23, 2019 tried Edit: in Aug 2019 it does seem to work: #25382 (comment) |
What does As you've probably gathered from the issues linked in libuv/libuv#2133, this is not something that is solvable, easily or at all. |
@bnoordhuis Can you point me in the right direction for the issues you've encountered with using It's been a couple years, but when I looked into the linux kernel code for |
The biggest issue for libuv is that
Linux's overcommit logic has been overhauled several times in the last years. I wouldn't know where exactly it stands now without checking the source (and also of past releases.) :-) |
They aren't run though because they shouldn't often be needed. Although I don't know what Node.js does (or promises to do) in this case. From the rationale of pthread_atfork, running them is necessary to work around design issues with OTOH, libuv now does register a But if the overcommit-related logic has changed, perhaps it might be faster now too? I see the OP is on an older Ubuntu 16.04. But if the kernel can do |
@bnoordhuis the default 0 - ENOMEM Aside from that workaround (possibly viable) or adding swap (not viable), for my specific situation I'm looking into a PR to make https://github.com/googleapis/google-auth-library-nodejs either not exec at all, or exec earlier before the process grows. |
@vtjnash There is (or was) at least one shared memory add-on module that uses I say "indirectly" because add-on X might depend on shared library Y, which in turn depends on a functioning @zbjornson Thanks for checking! I figured that DWIM mode ( It's curious that |
(Random data point: also seeing this on a 2GB server trying to execute |
Hrm, twice previously I tried using Anyway, getting https://chromium-review.googlesource.com/c/v8/v8/+/1101679 landed would be great. Looks like there's just a typo pending. (Also, on my system an |
can we push https://chromium-review.googlesource.com/c/v8/v8/+/1101679 forward? |
cc @bnoordhuis |
This would explain why we've had some ENOMEM errors on production since switching to Node 12. Because default old space size was 1.4G on Node 10, 1.4*2=2.8GB was still under our 4GB server's ram. Since Node 12 removed the old space size limit, the heap size was sometimes over 3GB, so the spawn would require 3*2 =6GB, and our instances -who do not have SWAP-, would just throw an ENOMEM error. I will keep an eye on this issue ! |
Hi, there is progress on this topic ? |
From what I've read the cheapest way to safely do it is use vfork+exec. True fork should setup just a memory with most/all pages mapped from the parent but this is not easy/fast task for huge memory hog as most of node process tend to become. So if we're going to exec past fork and if vfork exist in the system why not use it? |
Stumbled on this issue trying to figure out why Line 237 in f1ae7ea
Given that the I'm not sure why |
Further to my comment above, perhaps it would help to consider that using the |
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
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
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
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
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 Refs: v8/v8@1a782f6 Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 <[email protected]> Reviewed-by: Michael Lippautz <[email protected]> Cr-Commit-Position: refs/heads/main@{#88447} Refs: v8/v8@1a782f6 PR-URL: #48523 Fixes: #25382 Fixes: #14917 Refs: nodejs/performance#93 Refs: nodejs/performance#89 Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 Refs: v8/v8@1a782f6 Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 <[email protected]> Reviewed-by: Michael Lippautz <[email protected]> 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 <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 <[email protected]> Reviewed-by: Michael Lippautz <[email protected]> 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 <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 <[email protected]> Reviewed-by: Michael Lippautz <[email protected]> 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 <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 <[email protected]> Reviewed-by: Michael Lippautz <[email protected]> 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 <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 <[email protected]> Reviewed-by: Michael Lippautz <[email protected]> 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 <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 <[email protected]> Reviewed-by: Michael Lippautz <[email protected]> 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 <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 <[email protected]> Reviewed-by: Michael Lippautz <[email protected]> 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 <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 <[email protected]> Reviewed-by: Michael Lippautz <[email protected]> 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 <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 <[email protected]> Reviewed-by: Michael Lippautz <[email protected]> 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 <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 <[email protected]> Reviewed-by: Michael Lippautz <[email protected]> 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 <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 <[email protected]> Reviewed-by: Michael Lippautz <[email protected]> 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 <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
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 <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Debadree Chatterjee <[email protected]>
A tiny
exec
call when Node.js is using at least half of the otherwise-available memory causesspawn ENOMEM
:Apparently this is a common problem when using
fork()
/clone()
,and using.posix_spawn(3)
avoids itI don't see any upstream issues in libuv for this.
The text was updated successfully, but these errors were encountered: