Skip to content

stream: fast path single-destination pipe (2)#63604

Closed
trivikr wants to merge 4 commits into
nodejs:mainfrom
trivikr:stream-pipe-hot-path-listener-overhead-2
Closed

stream: fast path single-destination pipe (2)#63604
trivikr wants to merge 4 commits into
nodejs:mainfrom
trivikr:stream-pipe-hot-path-listener-overhead-2

Conversation

@trivikr
Copy link
Copy Markdown
Member

@trivikr trivikr commented May 28, 2026

This is a draft.

Testing if avoiding helper for non-pipe data emission impacts readable-from benchmarks

trivikr added 4 commits May 27, 2026 18:35
Avoid EventEmitter dispatch for the readable pipe data handler when it
is the only data listener. Fall back to normal data event emission when
additional data listeners are present to preserve listener ordering.

Track the pipe data handler lazily so non-piped readable streams do not
pay an extra ReadableState property initialization or data listener
identity check.

Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: openai:gpt-5.5
@nodejs-github-bot
Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/streams

@nodejs-github-bot nodejs-github-bot added needs-ci PRs that need a full CI run. stream Issues and PRs related to the stream subsystem. labels May 28, 2026
@trivikr
Copy link
Copy Markdown
Member Author

trivikr commented May 28, 2026

Benchmark CI: https://ci.nodejs.org/view/Node.js%20benchmark/job/benchmark-node-micro-benchmarks/1864/

Details
                                                                                         confidence improvement accuracy (*)    (**)   (***)
streams/compose.js n=1000                                                                         *     -0.78 %       ±0.65%  ±0.87%  ±1.13%
streams/creation.js kind='duplex' n=50000000                                                             0.31 %       ±0.50%  ±0.67%  ±0.88%
streams/creation.js kind='readable' n=50000000                                                           0.58 %       ±1.10%  ±1.46%  ±1.90%
streams/creation.js kind='transform' n=50000000                                                  **      1.00 %       ±0.60%  ±0.80%  ±1.04%
streams/creation.js kind='writable' n=50000000                                                          -0.51 %       ±2.49%  ±3.36%  ±4.44%
streams/destroy.js kind='duplex' n=1000000                                                               0.11 %       ±0.42%  ±0.56%  ±0.74%
streams/destroy.js kind='readable' n=1000000                                                            -0.22 %       ±0.90%  ±1.20%  ±1.56%
streams/destroy.js kind='transform' n=1000000                                                           -0.18 %       ±0.56%  ±0.75%  ±0.97%
streams/destroy.js kind='writable' n=1000000                                                            -0.08 %       ±0.66%  ±0.87%  ±1.14%
streams/finished.js streamType='readable' n=10000000                                                     0.17 %       ±0.70%  ±0.93%  ±1.21%
streams/finished.js streamType='writable' n=10000000                                              *      0.54 %       ±0.53%  ±0.70%  ±0.91%
streams/iter-creation.js n=100000 type='pair' api='classic'                                              2.03 %       ±3.29%  ±4.39%  ±5.72%
streams/iter-creation.js n=100000 type='pair' api='iter'                                                -0.32 %       ±0.54%  ±0.72%  ±0.93%
streams/iter-creation.js n=100000 type='pair' api='webstream'                                            0.13 %       ±0.80%  ±1.07%  ±1.39%
streams/iter-creation.js n=100000 type='readable' api='classic'                                          0.88 %       ±6.40%  ±8.52% ±11.10%
streams/iter-creation.js n=100000 type='readable' api='iter'                                             0.86 %       ±2.31%  ±3.07%  ±4.00%
streams/iter-creation.js n=100000 type='readable' api='webstream'                                        0.51 %       ±0.77%  ±1.02%  ±1.33%
streams/iter-creation.js n=100000 type='transform' api='classic'                                         0.93 %       ±2.93%  ±3.90%  ±5.08%
streams/iter-creation.js n=100000 type='transform' api='webstream'                                       0.06 %       ±0.93%  ±1.23%  ±1.61%
streams/iter-creation.js n=100000 type='writable' api='classic'                                         -3.01 %       ±4.59%  ±6.13%  ±8.03%
streams/iter-creation.js n=100000 type='writable' api='iter'                                             0.57 %       ±2.46%  ±3.28%  ±4.27%
streams/iter-creation.js n=100000 type='writable' api='webstream'                                       -0.73 %       ±1.76%  ±2.34%  ±3.05%
streams/iter-file-read.js n=5 filesize=1048576 api='classic'                                            -1.45 %       ±9.11% ±12.12% ±15.78%
streams/iter-file-read.js n=5 filesize=1048576 api='iter'                                               -8.94 %      ±10.58% ±14.08% ±18.33%
streams/iter-file-read.js n=5 filesize=1048576 api='webstream'                                           1.40 %       ±5.93%  ±7.90% ±10.28%
streams/iter-file-read.js n=5 filesize=16777216 api='classic'                                            1.06 %       ±7.13%  ±9.48% ±12.34%
streams/iter-file-read.js n=5 filesize=16777216 api='iter'                                             -16.53 %      ±20.56% ±27.36% ±35.61%
streams/iter-file-read.js n=5 filesize=16777216 api='webstream'                                          0.06 %       ±0.49%  ±0.65%  ±0.84%
streams/iter-file-read.js n=5 filesize=67108864 api='classic'                                            0.41 %       ±5.40%  ±7.18%  ±9.35%
streams/iter-file-read.js n=5 filesize=67108864 api='iter'                                              -0.47 %      ±21.00% ±27.94% ±36.36%
streams/iter-file-read.js n=5 filesize=67108864 api='webstream'                                         -0.27 %       ±0.55%  ±0.73%  ±0.95%
streams/iter-from-batching.js n=100 chunkSize=16 chunks=256 method='from-sync-writev'                    3.01 %       ±6.78%  ±9.11% ±12.03%
streams/iter-from-batching.js n=100 chunkSize=16 chunks=4096 method='from-sync-writev'                  -0.85 %       ±3.57%  ±4.74%  ±6.18%
streams/iter-from-batching.js n=1000 chunkSize=16 chunks=16384 method='from-first-batch'                -4.69 %       ±6.04%  ±8.06% ±10.54%
streams/iter-from-batching.js n=1000 chunkSize=16 chunks=256 method='from-first-batch'                   0.01 %       ±4.09%  ±5.44%  ±7.08%
streams/iter-from-batching.js n=1000 chunkSize=16 chunks=4096 method='from-first-batch'                 -3.51 %       ±4.87%  ±6.49%  ±8.45%
streams/iter-throughput-broadcast.js n=5 datasize=1048576 consumers=1 api='classic'                      3.84 %       ±5.83%  ±7.85% ±10.42%
streams/iter-throughput-broadcast.js n=5 datasize=1048576 consumers=1 api='iter'                        -0.75 %       ±2.27%  ±3.02%  ±3.94%
streams/iter-throughput-broadcast.js n=5 datasize=1048576 consumers=1 api='webstream'                   -3.18 %      ±13.25% ±17.63% ±22.95%
streams/iter-throughput-broadcast.js n=5 datasize=1048576 consumers=2 api='classic'                     -1.99 %       ±4.15%  ±5.54%  ±7.26%
streams/iter-throughput-broadcast.js n=5 datasize=1048576 consumers=2 api='iter'                         0.24 %       ±0.89%  ±1.18%  ±1.54%
streams/iter-throughput-broadcast.js n=5 datasize=1048576 consumers=2 api='webstream'                    2.09 %      ±13.23% ±17.61% ±22.92%
streams/iter-throughput-broadcast.js n=5 datasize=1048576 consumers=4 api='classic'                      0.45 %       ±3.06%  ±4.12%  ±5.46%
streams/iter-throughput-broadcast.js n=5 datasize=1048576 consumers=4 api='iter'                        -9.22 %      ±12.26% ±16.52% ±21.93%
streams/iter-throughput-broadcast.js n=5 datasize=1048576 consumers=4 api='webstream'                   -3.34 %       ±7.80% ±10.41% ±13.60%
streams/iter-throughput-broadcast.js n=5 datasize=16777216 consumers=1 api='classic'            ***     63.39 %      ±11.74% ±15.63% ±20.37%
streams/iter-throughput-broadcast.js n=5 datasize=16777216 consumers=1 api='iter'                        6.95 %      ±14.33% ±19.07% ±24.82%
streams/iter-throughput-broadcast.js n=5 datasize=16777216 consumers=1 api='webstream'                   4.98 %      ±10.06% ±13.38% ±17.42%
streams/iter-throughput-broadcast.js n=5 datasize=16777216 consumers=2 api='classic'                    -0.90 %       ±8.20% ±10.91% ±14.20%
streams/iter-throughput-broadcast.js n=5 datasize=16777216 consumers=2 api='iter'                       -3.28 %      ±12.40% ±16.50% ±21.48%
streams/iter-throughput-broadcast.js n=5 datasize=16777216 consumers=2 api='webstream'                  -1.85 %       ±7.01%  ±9.32% ±12.14%
streams/iter-throughput-broadcast.js n=5 datasize=16777216 consumers=4 api='classic'                    -1.29 %       ±6.95%  ±9.25% ±12.05%
streams/iter-throughput-broadcast.js n=5 datasize=16777216 consumers=4 api='iter'                        5.81 %      ±12.50% ±16.64% ±21.66%
streams/iter-throughput-broadcast.js n=5 datasize=16777216 consumers=4 api='webstream'                   1.61 %       ±4.39%  ±5.84%  ±7.60%
streams/iter-throughput-compression.js n=5 datasize=1048576 api='classic'                                1.55 %      ±14.33% ±19.07% ±24.82%
streams/iter-throughput-compression.js n=5 datasize=1048576 api='iter'                                  -5.09 %      ±12.08% ±16.07% ±20.92%
streams/iter-throughput-compression.js n=5 datasize=1048576 api='webstream'                              3.70 %       ±9.05% ±12.05% ±15.69%
streams/iter-throughput-compression.js n=5 datasize=16777216 api='classic'                              20.97 %      ±27.43% ±36.63% ±47.94%
streams/iter-throughput-compression.js n=5 datasize=16777216 api='iter'                                -18.99 %      ±28.60% ±38.08% ±49.62%
streams/iter-throughput-compression.js n=5 datasize=16777216 api='webstream'                            -1.39 %      ±22.72% ±30.22% ±39.34%
streams/iter-throughput-compression.js n=5 datasize=67108864 api='classic'                              -4.76 %      ±18.13% ±24.13% ±31.45%
streams/iter-throughput-compression.js n=5 datasize=67108864 api='iter'                                 -8.52 %      ±13.08% ±17.44% ±22.77%
streams/iter-throughput-compression.js n=5 datasize=67108864 api='webstream'                           -11.19 %      ±18.74% ±24.99% ±32.66%
streams/iter-throughput-identity.js n=5 datasize=1048576 api='classic'                                   2.34 %       ±5.01%  ±6.74%  ±8.94%
streams/iter-throughput-identity.js n=5 datasize=1048576 api='iter-sync'                                 0.97 %       ±1.93%  ±2.56%  ±3.34%
streams/iter-throughput-identity.js n=5 datasize=1048576 api='iter'                                     -0.09 %       ±0.90%  ±1.20%  ±1.56%
streams/iter-throughput-identity.js n=5 datasize=1048576 api='webstream'                                -4.59 %      ±13.66% ±18.18% ±23.66%
streams/iter-throughput-identity.js n=5 datasize=16777216 api='classic'                                  2.14 %       ±8.38% ±11.16% ±14.53%
streams/iter-throughput-identity.js n=5 datasize=16777216 api='iter-sync'                               -5.27 %      ±34.23% ±45.55% ±59.29%
streams/iter-throughput-identity.js n=5 datasize=16777216 api='iter'                                    -8.77 %      ±18.34% ±24.40% ±31.78%
streams/iter-throughput-identity.js n=5 datasize=16777216 api='webstream'                                0.97 %      ±10.30% ±13.71% ±17.84%
streams/iter-throughput-identity.js n=5 datasize=67108864 api='classic'                                  6.19 %       ±7.66% ±10.20% ±13.28%
streams/iter-throughput-identity.js n=5 datasize=67108864 api='iter-sync'                                0.16 %       ±1.91%  ±2.54%  ±3.31%
streams/iter-throughput-identity.js n=5 datasize=67108864 api='iter'                                     8.49 %      ±11.38% ±15.22% ±19.95%
streams/iter-throughput-identity.js n=5 datasize=67108864 api='webstream'                               -2.61 %       ±5.78%  ±7.68% ±10.00%
streams/iter-throughput-pipeto.js n=5 datasize=1048576 api='classic'                                    -2.85 %       ±3.47%  ±4.67%  ±6.19%
streams/iter-throughput-pipeto.js n=5 datasize=1048576 api='iter-sync-source'                           -0.25 %       ±0.82%  ±1.09%  ±1.42%
streams/iter-throughput-pipeto.js n=5 datasize=1048576 api='iter-sync'                                   1.55 %       ±2.45%  ±3.27%  ±4.30%
streams/iter-throughput-pipeto.js n=5 datasize=1048576 api='iter'                                 *      0.98 %       ±0.83%  ±1.11%  ±1.45%
streams/iter-throughput-pipeto.js n=5 datasize=1048576 api='webstream'                                  -0.78 %      ±13.85% ±18.43% ±23.99%
streams/iter-throughput-pipeto.js n=5 datasize=16777216 api='classic'                           ***     50.39 %      ±10.58% ±14.10% ±18.40%
streams/iter-throughput-pipeto.js n=5 datasize=16777216 api='iter-sync-source'                           4.18 %      ±23.29% ±30.99% ±40.34%
streams/iter-throughput-pipeto.js n=5 datasize=16777216 api='iter-sync'                                -10.77 %      ±33.71% ±44.86% ±58.40%
streams/iter-throughput-pipeto.js n=5 datasize=16777216 api='iter'                                      -3.56 %      ±15.42% ±20.55% ±26.80%
streams/iter-throughput-pipeto.js n=5 datasize=16777216 api='webstream'                                  1.42 %       ±8.82% ±11.76% ±15.36%
streams/iter-throughput-pipeto.js n=5 datasize=67108864 api='classic'                            **     13.15 %       ±9.31% ±12.39% ±16.13%
streams/iter-throughput-pipeto.js n=5 datasize=67108864 api='iter-sync-source'                           4.94 %      ±13.24% ±17.63% ±22.97%
streams/iter-throughput-pipeto.js n=5 datasize=67108864 api='iter-sync'                                  0.30 %       ±2.20%  ±2.94%  ±3.82%
streams/iter-throughput-pipeto.js n=5 datasize=67108864 api='iter'                                       6.07 %       ±9.25% ±12.41% ±16.38%
streams/iter-throughput-pipeto.js n=5 datasize=67108864 api='webstream'                                  3.48 %       ±6.71%  ±8.93% ±11.63%
streams/iter-throughput-share.js n=5 backpressure='block' batches=10000 consumers=2                      0.76 %       ±1.54%  ±2.05%  ±2.66%
streams/iter-throughput-share.js n=5 backpressure='block' batches=10000 consumers=32                     0.07 %       ±0.33%  ±0.44%  ±0.57%
streams/iter-throughput-share.js n=5 backpressure='block' batches=10000 consumers=8                      0.45 %       ±0.71%  ±0.95%  ±1.23%
streams/iter-throughput-transform.js n=5 datasize=1048576 api='classic'                         ***    -22.87 %       ±9.03% ±12.08% ±15.86%
streams/iter-throughput-transform.js n=5 datasize=1048576 api='iter-sync'                               -0.98 %       ±1.94%  ±2.59%  ±3.40%
streams/iter-throughput-transform.js n=5 datasize=1048576 api='iter'                                     3.73 %      ±17.38% ±23.12% ±30.09%
streams/iter-throughput-transform.js n=5 datasize=1048576 api='webstream'                               -5.16 %      ±10.17% ±13.53% ±17.62%
streams/iter-throughput-transform.js n=5 datasize=16777216 api='classic'                                 1.53 %       ±3.63%  ±4.85%  ±6.34%
streams/iter-throughput-transform.js n=5 datasize=16777216 api='iter-sync'                              -1.07 %       ±5.37%  ±7.15%  ±9.31%
streams/iter-throughput-transform.js n=5 datasize=16777216 api='iter'                                    0.54 %       ±7.78% ±10.36% ±13.48%
streams/iter-throughput-transform.js n=5 datasize=16777216 api='webstream'                               0.66 %       ±5.70%  ±7.59%  ±9.89%
streams/iter-throughput-transform.js n=5 datasize=67108864 api='classic'                          *     -4.34 %       ±4.16%  ±5.56%  ±7.29%
streams/iter-throughput-transform.js n=5 datasize=67108864 api='iter-sync'                               1.11 %       ±2.11%  ±2.81%  ±3.68%
streams/iter-throughput-transform.js n=5 datasize=67108864 api='iter'                                    1.93 %       ±4.64%  ±6.17%  ±8.03%
streams/iter-throughput-transform.js n=5 datasize=67108864 api='webstream'                              -2.99 %       ±4.98%  ±6.63%  ±8.63%
streams/pipe-object-mode.js n=5000000                                                           ***     25.80 %       ±0.57%  ±0.77%  ±1.00%
streams/pipe.js n=5000000                                                                       ***     12.45 %       ±0.46%  ±0.62%  ±0.81%
streams/readable-async-iterator.js sync='no' n=100000                                                    0.01 %       ±2.06%  ±2.75%  ±3.58%
streams/readable-async-iterator.js sync='yes' n=100000                                                  -0.90 %       ±4.33%  ±5.77%  ±7.52%
streams/readable-bigread.js n=1000                                                                      -0.28 %       ±1.92%  ±2.56%  ±3.34%
streams/readable-bigunevenread.js n=1000                                                                -0.19 %       ±0.73%  ±0.97%  ±1.26%
streams/readable-boundaryread.js type='buffer' n=2000                                            **     -0.60 %       ±0.39%  ±0.52%  ±0.68%
streams/readable-boundaryread.js type='string' n=2000                                                    0.85 %       ±1.37%  ±1.82%  ±2.37%
streams/readable-from.js type='array' n=10000000                                                         0.45 %       ±2.22%  ±2.96%  ±3.85%
streams/readable-from.js type='async-generator' n=10000000                                               0.50 %       ±0.91%  ±1.21%  ±1.58%
streams/readable-from.js type='sync-generator-with-async-values' n=10000000                             -0.58 %       ±1.13%  ±1.50%  ±1.96%
streams/readable-from.js type='sync-generator-with-sync-values' n=10000000                              -0.12 %       ±0.98%  ±1.30%  ±1.70%
streams/readable-readall.js n=5000                                                                      -0.22 %       ±0.97%  ±1.29%  ±1.68%
streams/readable-uint8array.js kind='encoding' n=1000000                                                -0.41 %       ±1.39%  ±1.85%  ±2.41%
streams/readable-uint8array.js kind='read' n=1000000                                                    -0.50 %       ±1.68%  ±2.24%  ±2.91%
streams/readable-unevenread.js n=1000                                                                   -0.82 %       ±0.96%  ±1.28%  ±1.66%
streams/writable-manywrites.js len=1024 callback='no' writev='no' sync='no' n=100000                    -0.04 %       ±4.53%  ±6.03%  ±7.84%
streams/writable-manywrites.js len=1024 callback='no' writev='no' sync='yes' n=100000                   -7.34 %      ±13.22% ±17.59% ±22.90%
streams/writable-manywrites.js len=1024 callback='no' writev='yes' sync='no' n=100000                   -0.95 %       ±5.77%  ±7.68% ±10.00%
streams/writable-manywrites.js len=1024 callback='no' writev='yes' sync='yes' n=100000                  -0.23 %       ±1.97%  ±2.62%  ±3.41%
streams/writable-manywrites.js len=1024 callback='yes' writev='no' sync='no' n=100000                    1.13 %       ±3.78%  ±5.03%  ±6.56%
streams/writable-manywrites.js len=1024 callback='yes' writev='no' sync='yes' n=100000                   4.31 %       ±6.68%  ±8.89% ±11.60%
streams/writable-manywrites.js len=1024 callback='yes' writev='yes' sync='no' n=100000                  -0.44 %       ±4.31%  ±5.74%  ±7.47%
streams/writable-manywrites.js len=1024 callback='yes' writev='yes' sync='yes' n=100000                  0.02 %       ±3.22%  ±4.29%  ±5.60%
streams/writable-manywrites.js len=32768 callback='no' writev='no' sync='no' n=100000                    0.49 %       ±5.32%  ±7.08%  ±9.22%
streams/writable-manywrites.js len=32768 callback='no' writev='no' sync='yes' n=100000                   8.95 %      ±10.87% ±14.48% ±18.86%
streams/writable-manywrites.js len=32768 callback='no' writev='yes' sync='no' n=100000                   2.04 %       ±5.20%  ±6.93%  ±9.03%
streams/writable-manywrites.js len=32768 callback='no' writev='yes' sync='yes' n=100000                 -1.02 %       ±2.97%  ±3.95%  ±5.15%
streams/writable-manywrites.js len=32768 callback='yes' writev='no' sync='no' n=100000                  -0.13 %       ±3.76%  ±5.00%  ±6.51%
streams/writable-manywrites.js len=32768 callback='yes' writev='no' sync='yes' n=100000                  0.42 %       ±7.62% ±10.14% ±13.20%
streams/writable-manywrites.js len=32768 callback='yes' writev='yes' sync='no' n=100000                 -1.15 %       ±4.26%  ±5.67%  ±7.38%
streams/writable-manywrites.js len=32768 callback='yes' writev='yes' sync='yes' n=100000                 0.32 %       ±2.04%  ±2.72%  ±3.54%
streams/writable-uint8array.js kind='object-mode' n=50000000                                             0.03 %       ±0.11%  ±0.14%  ±0.18%
streams/writable-uint8array.js kind='write' n=50000000                                                   0.57 %       ±0.60%  ±0.80%  ±1.05%
streams/writable-uint8array.js kind='writev' n=50000000                                                  0.03 %       ±0.28%  ±0.37%  ±0.48%

@trivikr
Copy link
Copy Markdown
Member Author

trivikr commented May 28, 2026

Closing as test commit was merged in #63592 (comment)

@trivikr trivikr closed this May 28, 2026
@trivikr trivikr deleted the stream-pipe-hot-path-listener-overhead-2 branch May 28, 2026 04:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-ci PRs that need a full CI run. stream Issues and PRs related to the stream subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants