Skip to content

http: keep request option copies in fast mode - #67395

Open
gurgunday wants to merge 1 commit into
nodejs:mainfrom
gurgunday:perf/http-client-options-copy
Open

gurgunday wants to merge 1 commit into
nodejs:mainfrom
gurgunday:perf/http-client-options-copy

Conversation

@gurgunday

@gurgunday gurgunday commented Nov 10, 2026 •

Copy link
Copy Markdown
Member

Replaces the { __proto__: null, ...options } copies on the client request path and the http/https Agent constructors with ObjectSetPrototypeOf({ ...options }, null) so they stay out of dictionary mode

benchmark/http/create-clientrequest.js (50 runs at the default e=1, 30 runs with --set e=6):

arg url e=1 e=6
URL long +17.75 % *** +59.93 % ***
string long +15.64 % *** +55.37 % ***
options long +16.06 % *** +41.99 % ***
URL idn +20.46 % *** +67.04 % ***
string idn +8.78 % *** +52.59 % ***
options idn +13.40 % *** +41.10 % ***
URL wpt +17.28 % *** +56.80 % ***
string wpt +13.70 % *** +54.19 % ***
options wpt +2.76 % +33.58 % ***

Server benchmarks driven by benchmarker=test-double-http(s), where the
client half is http.request (30 runs, c=50 chunks=1 len=4 type=buffer):

http/simple.js +6.28 % **
https/simple.js +11.20 % ***

The options of every client request are copied several times: once
in ClientRequest to merge the URL and the options, once more to
build the options handed to the agent, and again in Agent#addRequest
(on every request, including keep-alive reuse) and createSocket to
merge in the agent options. Each copy was a `{ __proto__: null, ...}`
literal or an Object.assign() onto `{ __proto__: null }`. V8 creates
such an object in dictionary mode, and copying from a dictionary-mode
source takes the generic slow path, so every copy in the chain was
slow and fed a slow source into the next one.

Build each copy as an ordinary object literal and set its prototype
to null afterwards, which leaves a fast-mode object with a null
prototype and the same own properties in the same order. The same is
done for the copy of the options in the http and https Agent
constructors, which is the source of the agent options merged into
every request.

On a keep-alive client against a raw TCP responder (10 runs each,
medians, busy machine) this goes from 68.7k to 83.1k requests per
second and from 8.7 to 6.4 us of user CPU per request.

Assisted-by: claude:opus-5.5
Signed-off-by: Gürgün Dayıoğlu <hey@gurgun.day>
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/crypto
  • @nodejs/http
  • @nodejs/net

@nodejs-github-bot nodejs-github-bot added http Issues and PRs related to the http subsystem. https Issues and PRs related to the https subsystem. needs-ci PRs that need a full CI run. labels Nov 10, 2026
@gurgunday gurgunday added the performance Issues and PRs related to the performance of Node.js. label Nov 10, 2026
@codecov

codecov Bot commented Nov 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.73%. Comparing base (2aef805) to head (24cb5f2).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #67395      +/-   ##
==========================================
- Coverage   90.74%   90.73%   -0.01%     
==========================================
  Files         798      798              
  Lines      280083   280083              
  Branches    53900    53888      -12     
==========================================
- Hits       254166   254139      -27     
- Misses      16217    16258      +41     
+ Partials     9700     9686      -14     
Files with missing lines Coverage Δ
lib/https.js 97.19% <100.00%> (ø)
lib/internal/http/agent.js 96.64% <100.00%> (ø)
lib/internal/http/client.js 97.39% <100.00%> (ø)

... and 41 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

http Issues and PRs related to the http subsystem. https Issues and PRs related to the https subsystem. needs-ci PRs that need a full CI run. performance Issues and PRs related to the performance of Node.js.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants