Optimize child_process IPC for large data#10557
Optimize child_process IPC for large data#10557ypresto wants to merge 6 commits intonodejs:masterfrom
Conversation
d648a5b to
f99d46f
Compare
f99d46f to
4b13964
Compare
lib/internal/child_process.js
Outdated
| //Linebreak is used as a message end sign | ||
| while ((i = jsonBuffer.indexOf('\n', start)) >= 0) { | ||
| var json = jsonBuffer.slice(start, i); | ||
| chunks.forEach(function(json) { |
There was a problem hiding this comment.
forEach() is slower than a normal for loop.
4bfbcbc to
01da0d4
Compare
|
forEach() removed! setTimeout() is 20: setTimeout() is 0: |
01da0d4 to
ccac4b4
Compare
|
I wonder how it performs with setImmediate or possibly other ways of queueing up callbacks |
|
I don't think the |
|
58f6cc0 fixes New benchmark result with setImmediate(): |
lib/internal/child_process.js
Outdated
There was a problem hiding this comment.
Does this work? for (var … in …) iterates over the indices of the array, so it does not do the same thing as for (var i = 0; i < args.length; ++i)
Oops... test was failing. Fixed in de82d97..! |
addaleax
left a comment
There was a problem hiding this comment.
The changes in lib LGTM, can’t really speak up for the benchmark part
Squashed from: - child_process: fix IPC bench to obey send() ret val - child_process: fix IPC benchmark message has two more bytes - child_process: use setImmediate for IPC bench PR-URL: nodejs#10557 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Squashed from: - child_process: stop indexOf() on whole IPC buffer - child_process: get rid of forEach() and slice() in IPC - child_process: get rid of another forEach() in IPC Fixes: nodejs#3145 PR-URL: nodejs#10557 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Squashed from: - child_process: fix IPC bench to obey send() ret val - child_process: fix IPC benchmark message has two more bytes - child_process: use setImmediate for IPC bench PR-URL: nodejs#10557 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Squashed from: - child_process: stop indexOf() on whole IPC buffer - child_process: get rid of forEach() and slice() in IPC - child_process: get rid of another forEach() in IPC Fixes: nodejs#3145 PR-URL: nodejs#10557 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Squashed from: - child_process: fix IPC bench to obey send() ret val - child_process: fix IPC benchmark message has two more bytes - child_process: use setImmediate for IPC bench PR-URL: nodejs#10557 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Squashed from: - child_process: stop indexOf() on whole IPC buffer - child_process: get rid of forEach() and slice() in IPC - child_process: get rid of another forEach() in IPC Fixes: nodejs#3145 PR-URL: nodejs#10557 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Squashed from: - child_process: fix IPC bench to obey send() ret val - child_process: fix IPC benchmark message has two more bytes - child_process: use setImmediate for IPC bench PR-URL: nodejs#10557 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Squashed from: - child_process: stop indexOf() on whole IPC buffer - child_process: get rid of forEach() and slice() in IPC - child_process: get rid of another forEach() in IPC Fixes: nodejs#3145 PR-URL: nodejs#10557 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
|
Is this something we will want to backport? Should it bake a bit longer first? |
|
ping |
Squashed from: - child_process: fix IPC bench to obey send() ret val - child_process: fix IPC benchmark message has two more bytes - child_process: use setImmediate for IPC bench PR-URL: #10557 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Squashed from: - child_process: stop indexOf() on whole IPC buffer - child_process: get rid of forEach() and slice() in IPC - child_process: get rid of another forEach() in IPC Fixes: #3145 PR-URL: #10557 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
|
@MylesBorins This should be fine to backport to v6.x… I’ve cherry-picked the changes here to |
Squashed from: - child_process: fix IPC bench to obey send() ret val - child_process: fix IPC benchmark message has two more bytes - child_process: use setImmediate for IPC bench PR-URL: nodejs/node#10557 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Squashed from: - child_process: stop indexOf() on whole IPC buffer - child_process: get rid of forEach() and slice() in IPC - child_process: get rid of another forEach() in IPC Fixes: nodejs/node#3145 PR-URL: nodejs/node#10557 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
jsonBuffer.indexOf('\n', start)inchannel.onread(internal/child_process.js) dramatically slows down whenjsonBufferis very large.jsonBufferdoes not contains linebreak beforejsonBuffer += decoder.write(pool)call, so checking linebreaks in return value ofdecoder.write(pool)is enough to parse chunks.This increases total bytes received in 5 secs by 2-4x in benchmark...!
I found this when developing vscode plugin which returns very large result (around 10MB):
rubyide/vscode-ruby#107
Also vscode core has workaround for this bottleneck:
microsoft/vscode#6026 (comment)
Also fixed benchmark script which only shows zero.
Checklist
make -j4 test(UNIX), orvcbuild test(Windows) passesAffected core subsystem(s)
child_process
Benchmark result
Mac OS X 10.12.2
MacBook Pro (Retina, 15-inch, Mid 2014)
2.2 GHz Intel Core i7
Before:
child_process/child-process-read-ipc.js dur=5 len=64: 7,583,464
child_process/child-process-read-ipc.js dur=5 len=256: 10,687,553
child_process/child-process-read-ipc.js dur=5 len=1024: 6,279,313
child_process/child-process-read-ipc.js dur=5 len=4096: 6,319,896
child_process/child-process-read-ipc.js dur=5 len=16384: 6,482,388
child_process/child-process-read-ipc.js dur=5 len=65536: 8,580,203
child_process/child-process-read-ipc.js dur=5 len=1048576: 13,398,807
child_process/child-process-read-ipc.js dur=5 len=16777216: 0
After:
child_process/child-process-read-ipc.js dur=5 len=64: 9,131,734
child_process/child-process-read-ipc.js dur=5 len=256: 10,502,876
child_process/child-process-read-ipc.js dur=5 len=1024: 6,272,325
child_process/child-process-read-ipc.js dur=5 len=4096: 6,195,482
child_process/child-process-read-ipc.js dur=5 len=16384: 6,505,698
child_process/child-process-read-ipc.js dur=5 len=65536: 8,513,730
child_process/child-process-read-ipc.js dur=5 len=1048576: 40,615,305
child_process/child-process-read-ipc.js dur=5 len=16777216: 30,183,113
When setTimeout() in benchmark is 0:
(I have no idea why this produces quite different result.)
Before:
child_process/child-process-read-ipc.js dur=5 len=64: 11,924,365
child_process/child-process-read-ipc.js dur=5 len=256: 34,004,413
child_process/child-process-read-ipc.js dur=5 len=1024: 51,082,451
child_process/child-process-read-ipc.js dur=5 len=4096: 61,968,471
child_process/child-process-read-ipc.js dur=5 len=16384: 59,297,771
child_process/child-process-read-ipc.js dur=5 len=65536: 59,533,374
child_process/child-process-read-ipc.js dur=5 len=1048576: 6,704,920
child_process/child-process-read-ipc.js dur=5 len=16777216: 0
After:
child_process/child-process-read-ipc.js dur=5 len=64: 12,209,873
child_process/child-process-read-ipc.js dur=5 len=256: 36,964,340
child_process/child-process-read-ipc.js dur=5 len=1024: 50,775,987
child_process/child-process-read-ipc.js dur=5 len=4096: 79,817,420
child_process/child-process-read-ipc.js dur=5 len=16384: 92,115,253
child_process/child-process-read-ipc.js dur=5 len=65536: 105,704,985
child_process/child-process-read-ipc.js dur=5 len=1048576: 23,256,095
child_process/child-process-read-ipc.js dur=5 len=16777216: 0