Skip to content

stream: keep webstreams nil requests in fast mode - #66230

Merged
nodejs-github-bot merged 2 commits into
nodejs:mainfrom
mcollina:webstream-perf-round19
Sep 28, 2026
Merged

nodejs-github-bot merged 2 commits into
nodejs:mainfrom
mcollina:webstream-perf-round19

Conversation

@mcollina

@mcollina mcollina commented Sep 23, 2026 •

Copy link
Copy Markdown
Member

Round 19 of the webstreams performance work (follows #66154). A small one: two shared sentinel objects on the writable side were in dictionary mode, and every write and every pipe paid for it.

Nil requests in fast mode

The shared "no pending request" records in writablestream.js (kNilRequest, kNilPendingAbortRequest) were { __proto__: null, ... } literals, which V8 creates in dictionary mode (the same trap #65625 removed from the per-stream state records). They sit in inFlightWriteRequest, closeRequest and pendingAbortRequest whenever nothing is pending, and their promise field is checked several times per write, so each of those loads was a hash lookup. They are now built as plain literals and get their null prototype afterwards with ObjectSetPrototypeOf(), which keeps them in fast mode (only an object created with a null prototype starts in dictionary mode).

Readable controllers: no throwaway state object

ReadableStreamDefaultController and ReadableByteStreamController initialized [kState] with an empty object that setup replaced immediately. The field initializer is gone, matching the writable and transform controllers; every construction site goes straight into setup.

New benchmark

benchmark/webstreams/writable-write.js: nothing in benchmark/webstreams drove WritableStreamDefaultWriter.write() directly (await each write, or queue them all).

Benchmarks

node benchmark/compare.js --runs 20 on the final code (pipe-to, pipe-through, lifecycle, writable-write), significant rows only:

                                                                        confidence improvement accuracy
webstreams/pipe-to.js highWaterMarkW=1 highWaterMarkR=1 n=500000               ***     12.44 %       ±2.20%
webstreams/pipe-to.js highWaterMarkW=1 highWaterMarkR=1024 n=500000            ***     14.33 %       ±2.84%
webstreams/pipe-to.js highWaterMarkW=1 highWaterMarkR=4096 n=500000            ***     13.70 %       ±2.27%
webstreams/pipe-to.js highWaterMarkW=1024 highWaterMarkR=1 n=500000            ***     12.32 %       ±2.76%
webstreams/pipe-to.js highWaterMarkW=1024 highWaterMarkR=1024 n=500000         ***     13.61 %       ±1.98%
webstreams/pipe-to.js highWaterMarkW=1024 highWaterMarkR=4096 n=500000         ***     14.53 %       ±2.38%
webstreams/pipe-to.js highWaterMarkW=4096 highWaterMarkR=1 n=500000            ***     14.80 %       ±1.98%
webstreams/pipe-to.js highWaterMarkW=4096 highWaterMarkR=1024 n=500000         ***     14.91 %       ±1.93%
webstreams/pipe-to.js highWaterMarkW=4096 highWaterMarkR=4096 n=500000         ***     13.10 %       ±2.29%
webstreams/pipe-through.js kind='transform' n=500000                           ***      6.78 %       ±1.91%
webstreams/pipe-through.js kind='default' n=500000                               *      2.59 %       ±2.47%
webstreams/lifecycle.js kind='readable' n=50000                                  *      3.14 %       ±2.98%
webstreams/writable-write.js type='await' n=100000                             ***     17.57 %       ±4.32%

writable-write is noisy on this machine: an earlier 30-run pass measured await at +6.5 % () and queued at +3.6 % (); here queued is +2.6 % ±3.0 %.

An earlier full-suite run (creation, tee, readable-read, readable-read-buffered, readable-async-iterator, from, js_transfer as well) showed no other significant change; its one negative flag, creation.js kind='ReadableStream.tee' at −3.6 % (*), re-ran at 30 runs as −2.05 % ±2.14 %, not significant.

No behavior change: a 48-scenario microtask-ordering stress logs identically against main, and WPT streams plus the webstreams parallel batch are green.


AI generated, humanly reviewed.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/performance

@nodejs-github-bot nodejs-github-bot added needs-ci PRs that need a full CI run. web streams Issues and PRs related to the Web Streams API. labels Sep 23, 2026
The shared "no pending request" records in the writable stream were
`__proto__: null` literals, which V8 creates in dictionary mode. They
sit in inFlightWriteRequest, closeRequest and pendingAbortRequest
whenever nothing is pending, and their promise field is checked several
times per write, so those loads did a hash lookup on every write and
every pipe. They are now built as plain literals and get their null
prototype afterwards, which keeps them in fast mode.

The readable controllers also initialized their state slot with an
empty object that setup replaced immediately. That throwaway allocation
is gone, matching the writable and transform controllers.

Add a writable-write benchmark: nothing in benchmark/webstreams drove
WritableStreamDefaultWriter.write() directly.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
@mcollina
mcollina force-pushed the webstream-perf-round19 branch from 992b90b to bc320cd Compare September 23, 2026 06:34
Comment thread lib/internal/webstreams/readablestream.js
Comment thread lib/internal/webstreams/writablestream.js
@mcollina
mcollina marked this pull request as ready for review September 24, 2026 16:41
@codecov

codecov Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.37%. Comparing base (3d85c94) to head (42256de).
⚠️ Report is 142 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #66230      +/-   ##
==========================================
+ Coverage   90.29%   90.37%   +0.08%     
==========================================
  Files         790      790              
  Lines      272880   274499    +1619     
  Branches    52103    52562     +459     
==========================================
+ Hits       246385   248078    +1693     
+ Misses      16936    16891      -45     
+ Partials     9559     9530      -29     
Files with missing lines Coverage Δ
lib/internal/webstreams/readablestream.js 98.07% <100.00%> (ø)
lib/internal/webstreams/transformstream.js 98.72% <100.00%> (+<0.01%) ⬆️
lib/internal/webstreams/writablestream.js 99.52% <100.00%> (+<0.01%) ⬆️

... and 122 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Controller instances declared only [kType] and set [kState] later in the
setup function, so each construction took a shape transition when setup
added the slot. Declaring [kState] keeps the slot in the initial map and
makes the setup assignment an in-place store. Applied to the readable
default, readable byte, writable, and transform controllers so all four
share the same instance shape.

Assisted-by: pi
Signed-off-by: Matteo Collina <hello@matteocollina.com>
@panva panva added author ready PRs with CI started, the required approvals, and no outstanding review comments. request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. labels Sep 27, 2026
@github-actions github-actions Bot removed the request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. label Sep 27, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@mcollina mcollina added the commit-queue PRs queued for automated landing through the Commit Queue. label Sep 28, 2026
@nodejs-github-bot nodejs-github-bot added the lacks-second-approval Commit Queue PRs awaiting a second collaborator approval or completion of the required wait. label Sep 28, 2026
@nodejs-github-bot nodejs-github-bot added commit-queue-failed PRs whose Commit Queue landing failed and need manual intervention before retrying. and removed commit-queue PRs queued for automated landing through the Commit Queue. lacks-second-approval Commit Queue PRs awaiting a second collaborator approval or completion of the required wait. labels Sep 28, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Commit Queue failed

This pull request has multiple commits, but no landing policy was selected.

Add commit-queue-squash PRs the Commit Queue should land as one squashed commit. to land it as one commit, or commit-queue-rebase PRs the Commit Queue should land as multiple self-contained commits. to land the commits separately.

The pull request was removed from the Commit Queue and labeled commit-queue-failed PRs whose Commit Queue landing failed and need manual intervention before retrying. . After resolving the failure, remove that label and add commit-queue PRs queued for automated landing through the Commit Queue. to retry.

Full Commit Queue output
�[36m⠋�[39m Loading data for nodejs/node/pull/66230
�[36m⠋�[39m Loading data for nodejs/node/pull/66230
�[36m⠋�[39m Getting collaborator contacts from README of nodejs/node
�[36m⠋�[39m Getting PR from nodejs/node/pull/66230
�[36m⠋�[39m Getting reviews from nodejs/node/pull/66230
�[36m⠋�[39m Getting comments from nodejs/node/pull/66230
�[36m⠋�[39m Getting commits from nodejs/node/pull/66230
✔  Done loading data for nodejs/node/pull/66230
----------------------------------- PR info ------------------------------------
Title      stream: keep webstreams nil requests in fast mode (#66230)
Author     Matteo Collina <matteo.collina@gmail.com> (@mcollina)
Branch     mcollina:webstream-perf-round19 -> nodejs:main
Labels     author ready, needs-ci, commit-queue, web streams, lacks-second-approval
Commits    2
 - stream: keep webstreams nil requests in fast mode
 - stream: keep webstreams controller state fast
Committers 1
 - Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/66230
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
------------------------------ Generated metadata ------------------------------
PR-URL: https://github.com/nodejs/node/pull/66230
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
--------------------------------------------------------------------------------
   ℹ  This PR was created on Wed, 23 Sep 2026 06:23:45 GMT
   ✔  Approvals: 2
   ✔  - Mattias Buelens (@MattiasBuelens): https://github.com/nodejs/node/pull/66230#pullrequestreview-5329475825
   ✔  - Filip Skokan (@panva) (TSC): https://github.com/nodejs/node/pull/66230#pullrequestreview-5334815070
   ✔  Last GitHub CI successful
   ℹ  Last Full PR CI on 2026-09-27T08:16:13Z: https://ci.nodejs.org/job/node-test-pull-request/77996/
�[36m⠙�[39m Querying data for job/node-test-pull-request/77996/
�[36m⠙�[39m Querying data for job/node-test-pull-request/77996/
�[36m⠙�[39m Querying API for job/node-test-pull-request/77996/
✔  Build data downloaded
   ✔  Last Jenkins CI successful
--------------------------------------------------------------------------------
   ✔  No git cherry-pick in progress
   ✔  No git am in progress
   ✔  No git rebase in progress
--------------------------------------------------------------------------------
�[36m⠹�[39m Bringing origin/main up to date...
�[36m⠹�[39m Bringing origin/main up to date...
From https://github.com/nodejs/node
 * branch                  main       -> FETCH_HEAD
✔  origin/main is now up-to-date
�[36m⠸�[39m Downloading patch for 66230
�[36m⠸�[39m Downloading patch for 66230
From https://github.com/nodejs/node
 * branch                  refs/pull/66230/merge -> FETCH_HEAD
✔  Fetched commits as b59840b59306..42256de2e6ab
--------------------------------------------------------------------------------
[main 897ae474b0] stream: keep webstreams nil requests in fast mode
 Author: Matteo Collina <hello@matteocollina.com>
 Date: Wed Sep 23 07:48:37 2026 +0200
 3 files changed, 38 insertions(+), 9 deletions(-)
 create mode 100644 benchmark/webstreams/writable-write.js
[main c8b3bd67c6] stream: keep webstreams controller state fast
 Author: Matteo Collina <hello@matteocollina.com>
 Date: Sat Sep 26 09:49:49 2026 +0000
 3 files changed, 4 insertions(+)
   ✔  Patches applied
There are 2 commits in the PR. Attempting autorebase.
(node:444) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.
(Use `node --trace-deprecation ...` to show where the warning was created)
Rebasing (2/4)
Executing: git node land --amend --yes
--------------------------------- New Message ----------------------------------
stream: keep webstreams nil requests in fast mode

The shared "no pending request" records in the writable stream were
`__proto__: null` literals, which V8 creates in dictionary mode. They
sit in inFlightWriteRequest, closeRequest and pendingAbortRequest
whenever nothing is pending, and their promise field is checked several
times per write, so those loads did a hash lookup on every write and
every pipe. They are now built as plain literals and get their null
prototype afterwards, which keeps them in fast mode.

The readable controllers also initialized their state slot with an
empty object that setup replaced immediately. That throwaway allocation
is gone, matching the writable and transform controllers.

Add a writable-write benchmark: nothing in benchmark/webstreams drove
WritableStreamDefaultWriter.write() directly.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/66230
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
--------------------------------------------------------------------------------
[detached HEAD 5c3a445531] stream: keep webstreams nil requests in fast mode
 Author: Matteo Collina <hello@matteocollina.com>
 Date: Wed Sep 23 07:48:37 2026 +0200
 3 files changed, 38 insertions(+), 9 deletions(-)
 create mode 100644 benchmark/webstreams/writable-write.js
Rebasing (3/4)
Rebasing (4/4)
Executing: git node land --amend --yes
--------------------------------- New Message ----------------------------------
stream: keep webstreams controller state fast

Controller instances declared only [kType] and set [kState] later in the
setup function, so each construction took a shape transition when setup
added the slot. Declaring [kState] keeps the slot in the initial map and
makes the setup assignment an in-place store. Applied to the readable
default, readable byte, writable, and transform controllers so all four
share the same instance shape.

Assisted-by: pi
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/66230
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
--------------------------------------------------------------------------------
[detached HEAD 5529be676c] stream: keep webstreams controller state fast
 Author: Matteo Collina <hello@matteocollina.com>
 Date: Sat Sep 26 09:49:49 2026 +0000
 3 files changed, 4 insertions(+)
Successfully rebased and updated refs/heads/main.
--------------------------------------------------------------------------------
   ℹ  Add `commit-queue-squash` label to land the PR as one commit, or `commit-queue-rebase` to land as separate commits.

View workflow run

@mcollina mcollina added commit-queue PRs queued for automated landing through the Commit Queue. commit-queue-squash PRs the Commit Queue should land as one squashed commit. and removed commit-queue-failed PRs whose Commit Queue landing failed and need manual intervention before retrying. labels Sep 28, 2026
@nodejs-github-bot
nodejs-github-bot merged commit cff7b12 into nodejs:main Sep 28, 2026
92 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in cff7b12

@nodejs-github-bot nodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Sep 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author ready PRs with CI started, the required approvals, and no outstanding review comments. commit-queue-squash PRs the Commit Queue should land as one squashed commit. needs-ci PRs that need a full CI run. web streams Issues and PRs related to the Web Streams API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants