http: improve performance for end() with known-length string - #65466

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
pimterry:h1-clean-end-perf
Aug 24, 2026
Merged

http: improve performance for end() with known-length string#65466
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
pimterry:h1-clean-end-perf

Conversation

@pimterry

Copy link
Copy Markdown
Member

When you call end(data) on an outgoing HTTP request, we previously wrote the data, and then ran _send('', ...) just to trigger flushing the headers, which resulted in an extra zero-byte write call and bonus nextTick before 'finish'.

When the length is known and content-length is used (not chunking, so we don't need a terminator) we can skip this completely: prep the content-length header explicitly, and combine the finish into the existing write step.

This drops a nextTick, and goes from 2 write calls to 1 for the very common case of response.end(data) with a string, and for buffer data goes from 3 writes to 2.

In practice, in the tiny benchmark here which I think represents a very common use case (small API responses) I see this boosting HTTP RPS by up to 9% for writes up to 1KB or so. For larger responses the response write time starts to outweigh this, but I still see 3% RPS boost at 16KB. Needs autocannon to hit the rates required, you can test yourself with:

node benchmark/compare.js --old ./node-main --new ./node-pr --runs 20 --set benchmarker=autocannon --filter end-string http

Added a new test confirming the specific details and edge cases this touches, and updated one existing test which specifically asserted that end(data) triggered two writes, including the empty one.

This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/http
  • @nodejs/net
  • @nodejs/performance

@nodejs-github-botnodejs-github-bot added http Issues and PRs related to the http subsystem. needs-ci PRs that need a full CI run. labels Aug 21, 2026

@mcollinamcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@mcollina
mcollina requested a review from anonrigAugust 21, 2026 19:24
@codecov

codecovBot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.13%. Comparing base (15940ef) to head (659d6b9).
⚠️ Report is 61 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #65466 +/- ##
==========================================
- Coverage 90.14% 90.13% -0.01% 
==========================================
Files 751 751 Lines 252298 252333 +35 Branches 47446 47449 +3 ==========================================
+ Hits 227436 227451 +15 - Misses 16175 16186 +11 - Partials 8687 8696 +9 
Files with missing linesCoverage Δ
lib/_http_outgoing.js97.76% <100.00%> (-0.02%)⬇️

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

@pimterrypimterry added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 21, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 22, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@bjohansebasbjohansebas added the needs-benchmark-ci PRs that need a benchmark CI run. label Aug 22, 2026
@pimterry

Copy link
Copy Markdown
MemberAuthor

@bjohansebas benchmark label was a good suggestion. I've done a run here.

Unfortunately it seems like the microbenchmark job is broken generally (cc @nodejs/build) and all recent jobs have failed with:

++ Rscript benchmark/compare.R
Error: package or namespace load failed for ‘ggplot2’ in dyn.load(file, DLLpath = DLLpath, ...):
unable to load shared object '/usr/local/lib/R/site-library/rlang/libs/rlang.so':
/usr/local/lib/R/site-library/rlang/libs/rlang.so: undefined symbol: SETLENGTH
Execution halted

I've manually extracted the CSV from the console output to get some numbers though, and run node-benchmark-compare on the result, which gives:

Details
 confidence improvement accuracy (*) (**) (***)
http/bench-parser-fragmented.js n=100000 frags=2 len=16 -0.20 % ±1.06% ±1.42% ±1.85%
http/bench-parser-fragmented.js n=100000 frags=2 len=8 -0.01 % ±0.94% ±1.25% ±1.63%
http/bench-parser-fragmented.js n=100000 frags=4 len=16 -0.17 % ±0.77% ±1.02% ±1.33%
http/bench-parser-fragmented.js n=100000 frags=4 len=8 -0.57 % ±0.64% ±0.85% ±1.11%
http/bench-parser-fragmented.js n=100000 frags=8 len=16 -0.07 % ±0.84% ±1.12% ±1.45%
http/bench-parser-fragmented.js n=100000 frags=8 len=8 0.43 % ±0.78% ±1.04% ±1.35%
http/bench-parser.js n=100000 len=16 0.20 % ±0.93% ±1.24% ±1.61%
http/bench-parser.js n=100000 len=32 0.03 % ±0.68% ±0.90% ±1.17%
http/bench-parser.js n=100000 len=4 0.60 % ±1.08% ±1.43% ±1.86%
http/bench-parser.js n=100000 len=8 0.32 % ±1.11% ±1.47% ±1.92%
http/check_invalid_header_char.js n=1000000 input='' 1.25 % ±2.48% ±3.30% ±4.30%
http/check_invalid_header_char.js n=1000000 input='\t\t\t\t\t\t\t\t\t\tFoo bar baz' 0.39 % ±1.66% ±2.21% ±2.88%
http/check_invalid_header_char.js n=1000000 input='\x7F' * 4.92 % ±3.90% ±5.19% ±6.75%
http/check_invalid_header_char.js n=1000000 input='1' -0.41 % ±3.47% ±4.62% ±6.02%
http/check_invalid_header_char.js n=1000000 input='20091' -0.50 % ±3.85% ±5.12% ±6.66%
http/check_invalid_header_char.js n=1000000 input='close' 0.49 % ±3.34% ±4.44% ±5.78%
http/check_invalid_header_char.js n=1000000 input='en-US' -0.66 % ±3.59% ±4.77% ±6.21%
http/check_invalid_header_char.js n=1000000 input='foo\nbar' -1.88 % ±2.70% ±3.60% ±4.70%
http/check_invalid_header_char.js n=1000000 input='group_acmeair' 0.85 % ±1.82% ±2.42% ±3.16%
http/check_invalid_header_char.js n=1000000 input='gzip' -0.60 % ±3.29% ±4.37% ±5.70%
http/check_invalid_header_char.js n=1000000 input='keep-alive' -1.28 % ±2.16% ±2.88% ±3.75%
http/check_invalid_header_char.js n=1000000 input='LONG_AND_INVALID' 0.08 % ±1.13% ±1.51% ±1.97%
http/check_invalid_header_char.js n=1000000 input='private' 1.00 % ±2.68% ±3.57% ±4.65%
http/check_invalid_header_char.js n=1000000 input='SAMEORIGIN' 1.36 % ±2.81% ±3.74% ±4.88%
http/check_invalid_header_char.js n=1000000 input='Sat, 07 May 2016 16:54:48 GMT' 0.79 % ±1.41% ±1.87% ±2.44%
http/check_invalid_header_char.js n=1000000 input='text/html; charset=utf-8' -0.12 % ±1.41% ±1.88% ±2.45%
http/check_invalid_header_char.js n=1000000 input='text/plain' -1.49 % ±2.96% ±3.95% ±5.14%
http/check_invalid_header_char.js n=1000000 input='中文呢' 1.95 % ±2.71% ±3.61% ±4.69%
http/check_is_http_token.js n=1000000 key=':' -0.22 % ±2.22% ±2.96% ±3.85%
http/check_is_http_token.js n=1000000 key=':alternate-protocol' 2.82 % ±4.07% ±5.42% ±7.06%
http/check_is_http_token.js n=1000000 key='((((())))' -1.22 % ±2.75% ±3.71% ±4.91%
http/check_is_http_token.js n=1000000 key='@@' 0.52 % ±2.14% ±2.85% ±3.71%
http/check_is_http_token.js n=1000000 key='Accept-Ranges' 0.51 % ±2.25% ±2.99% ±3.90%
http/check_is_http_token.js n=1000000 key='alt-svc' -0.09 % ±2.23% ±2.97% ±3.87%
http/check_is_http_token.js n=1000000 key='alternate-protocol:' -0.94 % ±2.08% ±2.77% ±3.61%
http/check_is_http_token.js n=1000000 key='alternate-protocol' -1.19 % ±2.32% ±3.09% ±4.03%
http/check_is_http_token.js n=1000000 key='Cache-Control' -0.96 % ±2.14% ±2.85% ±3.71%
http/check_is_http_token.js n=1000000 key='Connection' 0.78 % ±2.39% ±3.19% ±4.15%
http/check_is_http_token.js n=1000000 key='Content-Encoding' * -2.76 % ±2.26% ±3.01% ±3.92%
http/check_is_http_token.js n=1000000 key='content-length' 0.93 % ±2.27% ±3.02% ±3.92%
http/check_is_http_token.js n=1000000 key='Content-Location' -0.15 % ±2.52% ±3.35% ±4.36%
http/check_is_http_token.js n=1000000 key='content-type' -0.49 % ±2.55% ±3.39% ±4.41%
http/check_is_http_token.js n=1000000 key='Content-Type' 0.46 % ±2.58% ±3.43% ±4.47%
http/check_is_http_token.js n=1000000 key='date' 0.62 % ±2.42% ±3.22% ±4.19%
http/check_is_http_token.js n=1000000 key='ETag' -2.60 % ±3.97% ±5.32% ±7.01%
http/check_is_http_token.js n=1000000 key='Expires' ** 3.69 % ±2.64% ±3.52% ±4.59%
http/check_is_http_token.js n=1000000 key='Keep-Alive' -0.03 % ±2.59% ±3.45% ±4.48%
http/check_is_http_token.js n=1000000 key='Last-Modified' -0.99 % ±2.34% ±3.12% ±4.07%
http/check_is_http_token.js n=1000000 key='location' 0.79 % ±2.44% ±3.25% ±4.23%
http/check_is_http_token.js n=1000000 key='server' 0.37 % ±2.46% ±3.27% ±4.25%
http/check_is_http_token.js n=1000000 key='Server' * 3.70 % ±3.00% ±4.00% ±5.23%
http/check_is_http_token.js n=1000000 key='status' ** -4.32 % ±3.09% ±4.13% ±5.40%
http/check_is_http_token.js n=1000000 key='TCN' -0.86 % ±1.00% ±1.33% ±1.73%
http/check_is_http_token.js n=1000000 key='Transfer-Encoding' -1.00 % ±2.32% ±3.09% ±4.02%
http/check_is_http_token.js n=1000000 key='Vary' -0.56 % ±1.47% ±1.95% ±2.54%
http/check_is_http_token.js n=1000000 key='version' 1.90 % ±2.74% ±3.65% ±4.75%
http/check_is_http_token.js n=1000000 key='x-frame-options' 0.57 % ±2.05% ±2.73% ±3.55%
http/check_is_http_token.js n=1000000 key='x-xss-protection' -1.39 % ±2.29% ±3.06% ±3.99%
http/check_is_http_token.js n=1000000 key='中文呢' -1.00 % ±4.47% ±6.01% ±7.92%
http/chunked.js duration=5 c=100 len=1 n=1 benchmarker='wrk' -0.19 % ±0.68% ±0.91% ±1.18%
http/chunked.js duration=5 c=100 len=1 n=16 benchmarker='wrk' 0.41 % ±0.78% ±1.03% ±1.35%
http/chunked.js duration=5 c=100 len=1 n=4 benchmarker='wrk' 0.61 % ±2.08% ±2.76% ±3.60%
http/chunked.js duration=5 c=100 len=1 n=8 benchmarker='wrk' 0.13 % ±0.81% ±1.07% ±1.40%
http/chunked.js duration=5 c=100 len=256 n=1 benchmarker='wrk' -0.10 % ±0.70% ±0.93% ±1.21%
http/chunked.js duration=5 c=100 len=256 n=16 benchmarker='wrk' -0.70 % ±0.73% ±0.97% ±1.26%
http/chunked.js duration=5 c=100 len=256 n=4 benchmarker='wrk' -0.58 % ±1.84% ±2.45% ±3.18%
http/chunked.js duration=5 c=100 len=256 n=8 benchmarker='wrk' 0.11 % ±0.87% ±1.16% ±1.51%
http/chunked.js duration=5 c=100 len=64 n=1 benchmarker='wrk' -0.26 % ±0.60% ±0.80% ±1.04%
http/chunked.js duration=5 c=100 len=64 n=16 benchmarker='wrk' 0.56 % ±0.63% ±0.84% ±1.10%
http/chunked.js duration=5 c=100 len=64 n=4 benchmarker='wrk' 0.08 % ±1.81% ±2.41% ±3.15%
http/chunked.js duration=5 c=100 len=64 n=8 benchmarker='wrk' 0.26 % ±0.75% ±1.00% ±1.30%
http/client-request-body.js method='end' len=1024 type='asc' dur=5 -0.06 % ±0.69% ±0.92% ±1.20%
http/client-request-body.js method='end' len=1024 type='buf' dur=5 0.01 % ±0.76% ±1.02% ±1.32%
http/client-request-body.js method='end' len=1024 type='utf' dur=5 -0.28 % ±0.59% ±0.79% ±1.03%
http/client-request-body.js method='end' len=256 type='asc' dur=5 -0.49 % ±0.67% ±0.90% ±1.17%
http/client-request-body.js method='end' len=256 type='buf' dur=5 * -0.75 % ±0.68% ±0.90% ±1.18%
http/client-request-body.js method='end' len=256 type='utf' dur=5 0.03 % ±0.62% ±0.83% ±1.08%
http/client-request-body.js method='end' len=32 type='asc' dur=5 -0.01 % ±0.56% ±0.75% ±0.98%
http/client-request-body.js method='end' len=32 type='buf' dur=5 -0.37 % ±0.60% ±0.79% ±1.03%
http/client-request-body.js method='end' len=32 type='utf' dur=5 -0.16 % ±0.62% ±0.83% ±1.08%
http/client-request-body.js method='write' len=1024 type='asc' dur=5 -0.16 % ±0.78% ±1.03% ±1.34%
http/client-request-body.js method='write' len=1024 type='buf' dur=5 -0.34 % ±0.68% ±0.90% ±1.17%
http/client-request-body.js method='write' len=1024 type='utf' dur=5 0.06 % ±0.78% ±1.04% ±1.35%
http/client-request-body.js method='write' len=256 type='asc' dur=5 0.27 % ±0.70% ±0.93% ±1.21%
http/client-request-body.js method='write' len=256 type='buf' dur=5 0.09 % ±0.76% ±1.02% ±1.32%
http/client-request-body.js method='write' len=256 type='utf' dur=5 0.49 % ±0.59% ±0.79% ±1.03%
http/client-request-body.js method='write' len=32 type='asc' dur=5 -0.40 % ±0.64% ±0.86% ±1.11%
http/client-request-body.js method='write' len=32 type='buf' dur=5 -0.21 % ±0.65% ±0.86% ±1.12%
http/client-request-body.js method='write' len=32 type='utf' dur=5 0.02 % ±0.60% ±0.79% ±1.03%
http/cluster.js duration=5 c=50 len=1024 type='buffer' benchmarker='wrk' 0.13 % ±0.46% ±0.62% ±0.81%
http/cluster.js duration=5 c=50 len=1024 type='bytes' benchmarker='wrk' -0.11 % ±0.38% ±0.50% ±0.66%
http/cluster.js duration=5 c=50 len=102400 type='buffer' benchmarker='wrk' -0.24 % ±0.49% ±0.65% ±0.85%
http/cluster.js duration=5 c=50 len=102400 type='bytes' benchmarker='wrk' 0.14 % ±0.80% ±1.06% ±1.38%
http/cluster.js duration=5 c=50 len=4 type='buffer' benchmarker='wrk' -0.23 % ±0.29% ±0.39% ±0.51%
http/cluster.js duration=5 c=50 len=4 type='bytes' benchmarker='wrk' 0.00 % ±0.51% ±0.67% ±0.88%
http/cluster.js duration=5 c=500 len=1024 type='buffer' benchmarker='wrk' ** -0.77 % ±0.50% ±0.67% ±0.87%
http/cluster.js duration=5 c=500 len=1024 type='bytes' benchmarker='wrk' -0.18 % ±0.65% ±0.86% ±1.12%
http/cluster.js duration=5 c=500 len=102400 type='buffer' benchmarker='wrk' -0.18 % ±0.59% ±0.78% ±1.02%
http/cluster.js duration=5 c=500 len=102400 type='bytes' benchmarker='wrk' 0.28 % ±0.72% ±0.95% ±1.24%
http/cluster.js duration=5 c=500 len=4 type='buffer' benchmarker='wrk' -0.25 % ±0.47% ±0.62% ±0.81%
http/cluster.js duration=5 c=500 len=4 type='bytes' benchmarker='wrk' -0.36 % ±0.52% ±0.70% ±0.91%
http/create-clientrequest.js e=1 arg='options' url='idn' 2.09 % ±7.80% ±10.38% ±13.50%
http/create-clientrequest.js e=1 arg='options' url='long' -9.98 % ±14.10% ±18.77% ±24.46%
http/create-clientrequest.js e=1 arg='options' url='wpt' -4.69 % ±6.75% ±8.98% ±11.70%
http/create-clientrequest.js e=1 arg='string' url='idn' -4.15 % ±10.23% ±13.61% ±17.71%
http/create-clientrequest.js e=1 arg='string' url='long' -0.93 % ±12.77% ±16.99% ±22.12%
http/create-clientrequest.js e=1 arg='string' url='wpt' 0.60 % ±11.36% ±15.12% ±19.68%
http/create-clientrequest.js e=1 arg='URL' url='idn' 0.87 % ±9.17% ±12.20% ±15.88%
http/create-clientrequest.js e=1 arg='URL' url='long' -5.01 % ±10.02% ±13.35% ±17.41%
http/create-clientrequest.js e=1 arg='URL' url='wpt' 1.99 % ±8.00% ±10.64% ±13.85%
http/end-string.js duration=5 c=50 len=1024 benchmarker='wrk' *** 10.48 % ±0.81% ±1.08% ±1.41%
http/end-string.js duration=5 c=50 len=102400 benchmarker='wrk' *** 2.47 % ±0.50% ±0.66% ±0.86%
http/end-string.js duration=5 c=50 len=16384 benchmarker='wrk' *** 5.59 % ±0.89% ±1.19% ±1.55%
http/end-string.js duration=5 c=50 len=4 benchmarker='wrk' *** 9.92 % ±0.82% ±1.10% ±1.43%
http/end-string.js duration=5 c=50 len=64 benchmarker='wrk' *** 8.43 % ±0.71% ±0.94% ±1.23%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='asc' benchmarker='wrk' *** 2.48 % ±0.47% ±0.62% ±0.81%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='buf' benchmarker='wrk' -0.12 % ±0.43% ±0.57% ±0.74%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='utf' benchmarker='wrk' *** 0.68 % ±0.38% ±0.51% ±0.66%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='asc' benchmarker='wrk' ** 1.19 % ±0.81% ±1.09% ±1.43%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='buf' benchmarker='wrk' *** 1.50 % ±0.59% ±0.78% ±1.01%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='utf' benchmarker='wrk' *** 2.25 % ±0.45% ±0.59% ±0.77%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='asc' benchmarker='wrk' *** 1.18 % ±0.42% ±0.56% ±0.73%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='buf' benchmarker='wrk' *** 0.92 % ±0.48% ±0.63% ±0.83%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='utf' benchmarker='wrk' *** 1.25 % ±0.32% ±0.43% ±0.56%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='asc' benchmarker='wrk' *** 1.60 % ±0.83% ±1.10% ±1.44%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='buf' benchmarker='wrk' *** 2.34 % ±0.88% ±1.18% ±1.53%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='utf' benchmarker='wrk' *** 2.95 % ±0.48% ±0.64% ±0.83%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='asc' benchmarker='wrk' -0.33 % ±0.57% ±0.77% ±1.00%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='buf' benchmarker='wrk' -0.16 % ±0.52% ±0.69% ±0.90%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='utf' benchmarker='wrk' -0.12 % ±0.36% ±0.47% ±0.62%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='asc' benchmarker='wrk' 0.07 % ±0.76% ±1.01% ±1.32%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='buf' benchmarker='wrk' -0.25 % ±0.51% ±0.68% ±0.89%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='utf' benchmarker='wrk' 0.53 % ±1.00% ±1.34% ±1.74%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='asc' benchmarker='wrk' -0.26 % ±0.61% ±0.81% ±1.06%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='buf' benchmarker='wrk' -0.05 % ±0.47% ±0.62% ±0.81%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='utf' benchmarker='wrk' -0.08 % ±0.56% ±0.74% ±0.96%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='asc' benchmarker='wrk' -0.50 % ±0.96% ±1.28% ±1.66%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='buf' benchmarker='wrk' -0.22 % ±0.71% ±0.94% ±1.23%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='utf' benchmarker='wrk' 0.10 % ±0.58% ±0.77% ±1.01%
http/headers.js group='fewHeaders' duration=5 len=1 n=10 benchmarker='wrk' -0.23 % ±0.65% ±0.86% ±1.13%
http/headers.js group='fewHeaders' duration=5 len=5 n=10 benchmarker='wrk' 0.25 % ±0.59% ±0.79% ±1.03%
http/headers.js group='manyHeaders' duration=5 len=1 n=600 benchmarker='wrk' -0.11 % ±0.86% ±1.15% ±1.49%
http/headers.js group='manyHeaders' duration=5 len=100 n=600 benchmarker='wrk' 0.22 % ±1.12% ±1.49% ±1.94%
http/headers.js group='mediumHeaders' duration=5 len=1 n=50 benchmarker='wrk' -0.28 % ±0.51% ±0.67% ±0.88%
http/headers.js group='mediumHeaders' duration=5 len=10 n=50 benchmarker='wrk' 0.04 % ±0.53% ±0.71% ±0.93%
http/http_server_for_chunky_client.js type='send' n=2000 len=1 0.19 % ±0.57% ±0.77% ±1.00%
http/http_server_for_chunky_client.js type='send' n=2000 len=128 -0.12 % ±0.59% ±0.78% ±1.02%
http/http_server_for_chunky_client.js type='send' n=2000 len=16 -0.01 % ±0.60% ±0.79% ±1.03%
http/http_server_for_chunky_client.js type='send' n=2000 len=32 0.15 % ±0.61% ±0.81% ±1.06%
http/http_server_for_chunky_client.js type='send' n=2000 len=4 0.67 % ±0.69% ±0.92% ±1.21%
http/http_server_for_chunky_client.js type='send' n=2000 len=64 -0.30 % ±0.48% ±0.64% ±0.83%
http/http_server_for_chunky_client.js type='send' n=2000 len=8 -0.50 % ±0.55% ±0.73% ±0.95%
http/http_server_for_chunky_client.js type='send' n=5 len=1 -1.39 % ±2.60% ±3.47% ±4.51%
http/http_server_for_chunky_client.js type='send' n=5 len=128 -4.15 % ±13.02% ±17.32% ±22.54%
http/http_server_for_chunky_client.js type='send' n=5 len=16 7.54 % ±10.05% ±13.50% ±17.81%
http/http_server_for_chunky_client.js type='send' n=5 len=32 0.87 % ±11.95% ±15.91% ±20.71%
http/http_server_for_chunky_client.js type='send' n=5 len=4 1.73 % ±10.57% ±14.06% ±18.30%
http/http_server_for_chunky_client.js type='send' n=5 len=64 -5.12 % ±14.17% ±18.86% ±24.56%
http/http_server_for_chunky_client.js type='send' n=5 len=8 -2.55 % ±5.92% ±7.90% ±10.32%
http/http_server_for_chunky_client.js type='send' n=50 len=1 1.27 % ±2.86% ±3.81% ±4.96%
http/http_server_for_chunky_client.js type='send' n=50 len=128 * 5.17 % ±4.13% ±5.49% ±7.15%
http/http_server_for_chunky_client.js type='send' n=50 len=16 -0.71 % ±2.69% ±3.58% ±4.67%
http/http_server_for_chunky_client.js type='send' n=50 len=32 -0.12 % ±2.72% ±3.63% ±4.74%
http/http_server_for_chunky_client.js type='send' n=50 len=4 -1.47 % ±3.06% ±4.07% ±5.29%
http/http_server_for_chunky_client.js type='send' n=50 len=64 2.04 % ±3.51% ±4.67% ±6.09%
http/http_server_for_chunky_client.js type='send' n=50 len=8 -0.08 % ±2.21% ±2.94% ±3.84%
http/http_server_for_chunky_client.js type='send' n=500 len=1 -0.08 % ±0.80% ±1.07% ±1.40%
http/http_server_for_chunky_client.js type='send' n=500 len=128 -0.38 % ±0.70% ±0.93% ±1.21%
http/http_server_for_chunky_client.js type='send' n=500 len=16 * -0.94 % ±0.83% ±1.11% ±1.45%
http/http_server_for_chunky_client.js type='send' n=500 len=32 -0.43 % ±0.83% ±1.11% ±1.45%
http/http_server_for_chunky_client.js type='send' n=500 len=4 -0.02 % ±0.71% ±0.95% ±1.24%
http/http_server_for_chunky_client.js type='send' n=500 len=64 -0.19 % ±0.93% ±1.24% ±1.62%
http/http_server_for_chunky_client.js type='send' n=500 len=8 -0.15 % ±0.71% ±0.95% ±1.23%
http/incoming_headers.js duration=5 w=0 headers=20 connections=50 benchmarker='wrk' 0.04 % ±0.81% ±1.08% ±1.42%
http/incoming_headers.js duration=5 w=6 headers=20 connections=50 benchmarker='wrk' 0.04 % ±0.64% ±0.85% ±1.11%
http/set_header.js n=1000000 value='Connection' ** -2.20 % ±1.65% ±2.19% ±2.85%
http/set_header.js n=1000000 value='Content-Length' 0.29 % ±1.71% ±2.28% ±2.97%
http/set_header.js n=1000000 value='Content-Type' 1.33 % ±1.88% ±2.51% ±3.27%
http/set_header.js n=1000000 value='Set-Cookie' 1.14 % ±1.33% ±1.77% ±2.30%
http/set_header.js n=1000000 value='Transfer-Encoding' 1.06 % ±1.33% ±1.76% ±2.30%
http/set_header.js n=1000000 value='Vary' -0.57 % ±1.72% ±2.29% ±2.99%
http/set_header.js n=1000000 value='X-Powered-By' * 1.49 % ±1.33% ±1.77% ±2.30%
http/set-header.js duration=5 res='normal' benchmarker='wrk' *** 9.74 % ±0.78% ±1.04% ±1.35%
http/set-header.js duration=5 res='setHeader' benchmarker='wrk' *** 9.87 % ±0.83% ±1.10% ±1.44%
http/set-header.js duration=5 res='setHeaderWH' benchmarker='wrk' *** 9.59 % ±0.92% ±1.22% ±1.59%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=1024 type='buffer' benchmarker='wrk' *** 2.60 % ±0.75% ±1.00% ±1.30%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=1024 type='bytes' benchmarker='wrk' *** 9.54 % ±0.74% ±0.99% ±1.28%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=102400 type='buffer' benchmarker='wrk' ** 1.23 % ±0.75% ±0.99% ±1.29%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=102400 type='bytes' benchmarker='wrk' *** 1.98 % ±0.49% ±0.65% ±0.84%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=4 type='buffer' benchmarker='wrk' *** 2.43 % ±0.76% ±1.01% ±1.31%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=4 type='bytes' benchmarker='wrk' *** 9.55 % ±0.71% ±0.95% ±1.24%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=1024 type='buffer' benchmarker='wrk' *** 3.14 % ±0.86% ±1.15% ±1.50%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=1024 type='bytes' benchmarker='wrk' *** 2.94 % ±0.78% ±1.04% ±1.35%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=102400 type='buffer' benchmarker='wrk' *** 1.55 % ±0.62% ±0.82% ±1.07%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=102400 type='bytes' benchmarker='wrk' ** 1.10 % ±0.82% ±1.09% ±1.42%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=4 type='buffer' benchmarker='wrk' *** 3.91 % ±0.83% ±1.10% ±1.44%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=4 type='bytes' benchmarker='wrk' *** 3.47 % ±0.93% ±1.23% ±1.60%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=1024 type='buffer' benchmarker='wrk' *** 3.60 % ±0.96% ±1.27% ±1.66%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=1024 type='bytes' benchmarker='wrk' *** 9.20 % ±0.99% ±1.32% ±1.72%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=102400 type='buffer' benchmarker='wrk' *** 1.28 % ±0.53% ±0.71% ±0.93%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=102400 type='bytes' benchmarker='wrk' *** 1.28 % ±0.65% ±0.87% ±1.13%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=4 type='buffer' benchmarker='wrk' *** 3.59 % ±0.96% ±1.28% ±1.67%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=4 type='bytes' benchmarker='wrk' *** 9.93 % ±1.01% ±1.35% ±1.76%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=1024 type='buffer' benchmarker='wrk' *** 2.04 % ±0.98% ±1.31% ±1.70%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=1024 type='bytes' benchmarker='wrk' *** 2.14 % ±0.82% ±1.08% ±1.41%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=102400 type='buffer' benchmarker='wrk' *** 1.74 % ±0.67% ±0.89% ±1.16%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=102400 type='bytes' benchmarker='wrk' ** 1.10 % ±0.79% ±1.05% ±1.36%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=4 type='buffer' benchmarker='wrk' *** 3.20 % ±0.94% ±1.24% ±1.62%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=4 type='bytes' benchmarker='wrk' *** 3.12 % ±0.76% ±1.01% ±1.32%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=1024 type='buffer' benchmarker='wrk' -0.19 % ±0.80% ±1.06% ±1.38%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=1024 type='bytes' benchmarker='wrk' -0.44 % ±0.95% ±1.26% ±1.65%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=102400 type='buffer' benchmarker='wrk' 0.11 % ±0.61% ±0.81% ±1.06%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=102400 type='bytes' benchmarker='wrk' * -1.19 % ±1.11% ±1.47% ±1.92%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=4 type='buffer' benchmarker='wrk' -0.23 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=4 type='bytes' benchmarker='wrk' 0.10 % ±0.75% ±1.00% ±1.30%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=1024 type='buffer' benchmarker='wrk' -0.55 % ±0.76% ±1.01% ±1.32%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=1024 type='bytes' benchmarker='wrk' 0.19 % ±0.95% ±1.27% ±1.65%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=102400 type='buffer' benchmarker='wrk' ** -1.32 % ±0.79% ±1.06% ±1.37%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=102400 type='bytes' benchmarker='wrk' 0.69 % ±1.07% ±1.42% ±1.85%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=4 type='buffer' benchmarker='wrk' 0.54 % ±0.81% ±1.07% ±1.40%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=4 type='bytes' benchmarker='wrk' 0.56 % ±0.71% ±0.95% ±1.23%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=1024 type='buffer' benchmarker='wrk' -0.48 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=1024 type='bytes' benchmarker='wrk' -0.62 % ±0.85% ±1.13% ±1.48%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=102400 type='buffer' benchmarker='wrk' -0.20 % ±0.69% ±0.92% ±1.20%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=102400 type='bytes' benchmarker='wrk' 0.43 % ±1.18% ±1.56% ±2.04%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=4 type='buffer' benchmarker='wrk' 0.29 % ±0.89% ±1.19% ±1.55%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=4 type='bytes' benchmarker='wrk' * -1.01 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=1024 type='buffer' benchmarker='wrk' -0.18 % ±0.68% ±0.90% ±1.18%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=1024 type='bytes' benchmarker='wrk' 0.09 % ±0.65% ±0.86% ±1.12%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=102400 type='buffer' benchmarker='wrk' * -0.55 % ±0.49% ±0.66% ±0.86%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=102400 type='bytes' benchmarker='wrk' 0.10 % ±0.82% ±1.09% ±1.42%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=4 type='buffer' benchmarker='wrk' 0.35 % ±0.74% ±0.98% ±1.28%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=4 type='bytes' benchmarker='wrk' -0.26 % ±0.65% ±0.86% ±1.12%
http/upgrade.js n=1000 0.73 % ±2.37% ±3.16% ±4.11%
http/upgrade.js n=5 6.72 % ±8.30% ±11.05% ±14.38%

Be aware that when doing many comparisons the risk of a false-positive result increases.
In this case, there are 235 comparisons, you can thus expect the following amount of false-positive results:
11.75 false positives, when considering a 5% risk acceptance (*, **, *),
2.35 false positives, when considering a 1% risk acceptance (
, ),
0.24 false positives, when considering a 0.1% risk acceptance (
)

Looks good I think. Headlines:

  • No notable regressions - each of the small negative cases I can see are low-confidence and fit into an overall pattern of no change considering the tests around them
  • A very consistent 9.59% - 9.87% speed up in http/set-header.js test, which tests headers + res.end(body).
  • For http/simple:
    • Consistent boost around 9.5% with type=bytes, no chunking, and len up to 1024.
    • 3% boost with type=buffer, on the same small non-chunked responses.
    • Both buffer & byte body perf dropping to about 1-2% improvement for larger bodies (1MB).
    • No significant change with chunked encoding.
  • 10.48% boost to http/end-string test with 1KB, dropping to 5.59% with 16KB, down to 2.47% improvement with 1MB.
  • ~2% boost across various http/end-vs-write-end.js cases that call end(data) on different large sizes.

Looks pretty convincing to me! All approved and ready-to-go now and I think this is all just good news, so I'll commit-queue.

@pimterrypimterry added the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 24, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 214cf06 into nodejs:mainAug 24, 2026
85 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 214cf06

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 24, 2026
@pimterry
pimterry deleted the h1-clean-end-perf branch August 25, 2026 15:12
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
aduh95 pushed a commit that referenced this pull request Aug 27, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

httpIssues and PRs related to the http subsystem.needs-benchmark-ciPRs that need a benchmark CI run.needs-ciPRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants

@pimterry@nodejs-github-bot@mcollina@lpinca@anonrig@efekrskl@mertcanaltin@gurgunday@bjohansebas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

http: improve performance for end() with known-length string - #65466

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
pimterry:h1-clean-end-perf
Aug 24, 2026
Merged

http: improve performance for end() with known-length string#65466
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
pimterry:h1-clean-end-perf

Conversation

@pimterry

Copy link
Copy Markdown
Member

When you call end(data) on an outgoing HTTP request, we previously wrote the data, and then ran _send('', ...) just to trigger flushing the headers, which resulted in an extra zero-byte write call and bonus nextTick before 'finish'.

When the length is known and content-length is used (not chunking, so we don't need a terminator) we can skip this completely: prep the content-length header explicitly, and combine the finish into the existing write step.

This drops a nextTick, and goes from 2 write calls to 1 for the very common case of response.end(data) with a string, and for buffer data goes from 3 writes to 2.

In practice, in the tiny benchmark here which I think represents a very common use case (small API responses) I see this boosting HTTP RPS by up to 9% for writes up to 1KB or so. For larger responses the response write time starts to outweigh this, but I still see 3% RPS boost at 16KB. Needs autocannon to hit the rates required, you can test yourself with:

node benchmark/compare.js --old ./node-main --new ./node-pr --runs 20 --set benchmarker=autocannon --filter end-string http

Added a new test confirming the specific details and edge cases this touches, and updated one existing test which specifically asserted that end(data) triggered two writes, including the empty one.

This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/http
  • @nodejs/net
  • @nodejs/performance

@nodejs-github-botnodejs-github-bot added http Issues and PRs related to the http subsystem. needs-ci PRs that need a full CI run. labels Aug 21, 2026

@mcollinamcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@mcollina
mcollina requested a review from anonrigAugust 21, 2026 19:24
@codecov

codecovBot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.13%. Comparing base (15940ef) to head (659d6b9).
⚠️ Report is 61 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #65466 +/- ##
==========================================
- Coverage 90.14% 90.13% -0.01% 
==========================================
Files 751 751 Lines 252298 252333 +35 Branches 47446 47449 +3 ==========================================
+ Hits 227436 227451 +15 - Misses 16175 16186 +11 - Partials 8687 8696 +9 
Files with missing linesCoverage Δ
lib/_http_outgoing.js97.76% <100.00%> (-0.02%)⬇️

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

@pimterrypimterry added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 21, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 22, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@bjohansebasbjohansebas added the needs-benchmark-ci PRs that need a benchmark CI run. label Aug 22, 2026
@pimterry

Copy link
Copy Markdown
MemberAuthor

@bjohansebas benchmark label was a good suggestion. I've done a run here.

Unfortunately it seems like the microbenchmark job is broken generally (cc @nodejs/build) and all recent jobs have failed with:

++ Rscript benchmark/compare.R
Error: package or namespace load failed for ‘ggplot2’ in dyn.load(file, DLLpath = DLLpath, ...):
unable to load shared object '/usr/local/lib/R/site-library/rlang/libs/rlang.so':
/usr/local/lib/R/site-library/rlang/libs/rlang.so: undefined symbol: SETLENGTH
Execution halted

I've manually extracted the CSV from the console output to get some numbers though, and run node-benchmark-compare on the result, which gives:

Details
 confidence improvement accuracy (*) (**) (***)
http/bench-parser-fragmented.js n=100000 frags=2 len=16 -0.20 % ±1.06% ±1.42% ±1.85%
http/bench-parser-fragmented.js n=100000 frags=2 len=8 -0.01 % ±0.94% ±1.25% ±1.63%
http/bench-parser-fragmented.js n=100000 frags=4 len=16 -0.17 % ±0.77% ±1.02% ±1.33%
http/bench-parser-fragmented.js n=100000 frags=4 len=8 -0.57 % ±0.64% ±0.85% ±1.11%
http/bench-parser-fragmented.js n=100000 frags=8 len=16 -0.07 % ±0.84% ±1.12% ±1.45%
http/bench-parser-fragmented.js n=100000 frags=8 len=8 0.43 % ±0.78% ±1.04% ±1.35%
http/bench-parser.js n=100000 len=16 0.20 % ±0.93% ±1.24% ±1.61%
http/bench-parser.js n=100000 len=32 0.03 % ±0.68% ±0.90% ±1.17%
http/bench-parser.js n=100000 len=4 0.60 % ±1.08% ±1.43% ±1.86%
http/bench-parser.js n=100000 len=8 0.32 % ±1.11% ±1.47% ±1.92%
http/check_invalid_header_char.js n=1000000 input='' 1.25 % ±2.48% ±3.30% ±4.30%
http/check_invalid_header_char.js n=1000000 input='\t\t\t\t\t\t\t\t\t\tFoo bar baz' 0.39 % ±1.66% ±2.21% ±2.88%
http/check_invalid_header_char.js n=1000000 input='\x7F' * 4.92 % ±3.90% ±5.19% ±6.75%
http/check_invalid_header_char.js n=1000000 input='1' -0.41 % ±3.47% ±4.62% ±6.02%
http/check_invalid_header_char.js n=1000000 input='20091' -0.50 % ±3.85% ±5.12% ±6.66%
http/check_invalid_header_char.js n=1000000 input='close' 0.49 % ±3.34% ±4.44% ±5.78%
http/check_invalid_header_char.js n=1000000 input='en-US' -0.66 % ±3.59% ±4.77% ±6.21%
http/check_invalid_header_char.js n=1000000 input='foo\nbar' -1.88 % ±2.70% ±3.60% ±4.70%
http/check_invalid_header_char.js n=1000000 input='group_acmeair' 0.85 % ±1.82% ±2.42% ±3.16%
http/check_invalid_header_char.js n=1000000 input='gzip' -0.60 % ±3.29% ±4.37% ±5.70%
http/check_invalid_header_char.js n=1000000 input='keep-alive' -1.28 % ±2.16% ±2.88% ±3.75%
http/check_invalid_header_char.js n=1000000 input='LONG_AND_INVALID' 0.08 % ±1.13% ±1.51% ±1.97%
http/check_invalid_header_char.js n=1000000 input='private' 1.00 % ±2.68% ±3.57% ±4.65%
http/check_invalid_header_char.js n=1000000 input='SAMEORIGIN' 1.36 % ±2.81% ±3.74% ±4.88%
http/check_invalid_header_char.js n=1000000 input='Sat, 07 May 2016 16:54:48 GMT' 0.79 % ±1.41% ±1.87% ±2.44%
http/check_invalid_header_char.js n=1000000 input='text/html; charset=utf-8' -0.12 % ±1.41% ±1.88% ±2.45%
http/check_invalid_header_char.js n=1000000 input='text/plain' -1.49 % ±2.96% ±3.95% ±5.14%
http/check_invalid_header_char.js n=1000000 input='中文呢' 1.95 % ±2.71% ±3.61% ±4.69%
http/check_is_http_token.js n=1000000 key=':' -0.22 % ±2.22% ±2.96% ±3.85%
http/check_is_http_token.js n=1000000 key=':alternate-protocol' 2.82 % ±4.07% ±5.42% ±7.06%
http/check_is_http_token.js n=1000000 key='((((())))' -1.22 % ±2.75% ±3.71% ±4.91%
http/check_is_http_token.js n=1000000 key='@@' 0.52 % ±2.14% ±2.85% ±3.71%
http/check_is_http_token.js n=1000000 key='Accept-Ranges' 0.51 % ±2.25% ±2.99% ±3.90%
http/check_is_http_token.js n=1000000 key='alt-svc' -0.09 % ±2.23% ±2.97% ±3.87%
http/check_is_http_token.js n=1000000 key='alternate-protocol:' -0.94 % ±2.08% ±2.77% ±3.61%
http/check_is_http_token.js n=1000000 key='alternate-protocol' -1.19 % ±2.32% ±3.09% ±4.03%
http/check_is_http_token.js n=1000000 key='Cache-Control' -0.96 % ±2.14% ±2.85% ±3.71%
http/check_is_http_token.js n=1000000 key='Connection' 0.78 % ±2.39% ±3.19% ±4.15%
http/check_is_http_token.js n=1000000 key='Content-Encoding' * -2.76 % ±2.26% ±3.01% ±3.92%
http/check_is_http_token.js n=1000000 key='content-length' 0.93 % ±2.27% ±3.02% ±3.92%
http/check_is_http_token.js n=1000000 key='Content-Location' -0.15 % ±2.52% ±3.35% ±4.36%
http/check_is_http_token.js n=1000000 key='content-type' -0.49 % ±2.55% ±3.39% ±4.41%
http/check_is_http_token.js n=1000000 key='Content-Type' 0.46 % ±2.58% ±3.43% ±4.47%
http/check_is_http_token.js n=1000000 key='date' 0.62 % ±2.42% ±3.22% ±4.19%
http/check_is_http_token.js n=1000000 key='ETag' -2.60 % ±3.97% ±5.32% ±7.01%
http/check_is_http_token.js n=1000000 key='Expires' ** 3.69 % ±2.64% ±3.52% ±4.59%
http/check_is_http_token.js n=1000000 key='Keep-Alive' -0.03 % ±2.59% ±3.45% ±4.48%
http/check_is_http_token.js n=1000000 key='Last-Modified' -0.99 % ±2.34% ±3.12% ±4.07%
http/check_is_http_token.js n=1000000 key='location' 0.79 % ±2.44% ±3.25% ±4.23%
http/check_is_http_token.js n=1000000 key='server' 0.37 % ±2.46% ±3.27% ±4.25%
http/check_is_http_token.js n=1000000 key='Server' * 3.70 % ±3.00% ±4.00% ±5.23%
http/check_is_http_token.js n=1000000 key='status' ** -4.32 % ±3.09% ±4.13% ±5.40%
http/check_is_http_token.js n=1000000 key='TCN' -0.86 % ±1.00% ±1.33% ±1.73%
http/check_is_http_token.js n=1000000 key='Transfer-Encoding' -1.00 % ±2.32% ±3.09% ±4.02%
http/check_is_http_token.js n=1000000 key='Vary' -0.56 % ±1.47% ±1.95% ±2.54%
http/check_is_http_token.js n=1000000 key='version' 1.90 % ±2.74% ±3.65% ±4.75%
http/check_is_http_token.js n=1000000 key='x-frame-options' 0.57 % ±2.05% ±2.73% ±3.55%
http/check_is_http_token.js n=1000000 key='x-xss-protection' -1.39 % ±2.29% ±3.06% ±3.99%
http/check_is_http_token.js n=1000000 key='中文呢' -1.00 % ±4.47% ±6.01% ±7.92%
http/chunked.js duration=5 c=100 len=1 n=1 benchmarker='wrk' -0.19 % ±0.68% ±0.91% ±1.18%
http/chunked.js duration=5 c=100 len=1 n=16 benchmarker='wrk' 0.41 % ±0.78% ±1.03% ±1.35%
http/chunked.js duration=5 c=100 len=1 n=4 benchmarker='wrk' 0.61 % ±2.08% ±2.76% ±3.60%
http/chunked.js duration=5 c=100 len=1 n=8 benchmarker='wrk' 0.13 % ±0.81% ±1.07% ±1.40%
http/chunked.js duration=5 c=100 len=256 n=1 benchmarker='wrk' -0.10 % ±0.70% ±0.93% ±1.21%
http/chunked.js duration=5 c=100 len=256 n=16 benchmarker='wrk' -0.70 % ±0.73% ±0.97% ±1.26%
http/chunked.js duration=5 c=100 len=256 n=4 benchmarker='wrk' -0.58 % ±1.84% ±2.45% ±3.18%
http/chunked.js duration=5 c=100 len=256 n=8 benchmarker='wrk' 0.11 % ±0.87% ±1.16% ±1.51%
http/chunked.js duration=5 c=100 len=64 n=1 benchmarker='wrk' -0.26 % ±0.60% ±0.80% ±1.04%
http/chunked.js duration=5 c=100 len=64 n=16 benchmarker='wrk' 0.56 % ±0.63% ±0.84% ±1.10%
http/chunked.js duration=5 c=100 len=64 n=4 benchmarker='wrk' 0.08 % ±1.81% ±2.41% ±3.15%
http/chunked.js duration=5 c=100 len=64 n=8 benchmarker='wrk' 0.26 % ±0.75% ±1.00% ±1.30%
http/client-request-body.js method='end' len=1024 type='asc' dur=5 -0.06 % ±0.69% ±0.92% ±1.20%
http/client-request-body.js method='end' len=1024 type='buf' dur=5 0.01 % ±0.76% ±1.02% ±1.32%
http/client-request-body.js method='end' len=1024 type='utf' dur=5 -0.28 % ±0.59% ±0.79% ±1.03%
http/client-request-body.js method='end' len=256 type='asc' dur=5 -0.49 % ±0.67% ±0.90% ±1.17%
http/client-request-body.js method='end' len=256 type='buf' dur=5 * -0.75 % ±0.68% ±0.90% ±1.18%
http/client-request-body.js method='end' len=256 type='utf' dur=5 0.03 % ±0.62% ±0.83% ±1.08%
http/client-request-body.js method='end' len=32 type='asc' dur=5 -0.01 % ±0.56% ±0.75% ±0.98%
http/client-request-body.js method='end' len=32 type='buf' dur=5 -0.37 % ±0.60% ±0.79% ±1.03%
http/client-request-body.js method='end' len=32 type='utf' dur=5 -0.16 % ±0.62% ±0.83% ±1.08%
http/client-request-body.js method='write' len=1024 type='asc' dur=5 -0.16 % ±0.78% ±1.03% ±1.34%
http/client-request-body.js method='write' len=1024 type='buf' dur=5 -0.34 % ±0.68% ±0.90% ±1.17%
http/client-request-body.js method='write' len=1024 type='utf' dur=5 0.06 % ±0.78% ±1.04% ±1.35%
http/client-request-body.js method='write' len=256 type='asc' dur=5 0.27 % ±0.70% ±0.93% ±1.21%
http/client-request-body.js method='write' len=256 type='buf' dur=5 0.09 % ±0.76% ±1.02% ±1.32%
http/client-request-body.js method='write' len=256 type='utf' dur=5 0.49 % ±0.59% ±0.79% ±1.03%
http/client-request-body.js method='write' len=32 type='asc' dur=5 -0.40 % ±0.64% ±0.86% ±1.11%
http/client-request-body.js method='write' len=32 type='buf' dur=5 -0.21 % ±0.65% ±0.86% ±1.12%
http/client-request-body.js method='write' len=32 type='utf' dur=5 0.02 % ±0.60% ±0.79% ±1.03%
http/cluster.js duration=5 c=50 len=1024 type='buffer' benchmarker='wrk' 0.13 % ±0.46% ±0.62% ±0.81%
http/cluster.js duration=5 c=50 len=1024 type='bytes' benchmarker='wrk' -0.11 % ±0.38% ±0.50% ±0.66%
http/cluster.js duration=5 c=50 len=102400 type='buffer' benchmarker='wrk' -0.24 % ±0.49% ±0.65% ±0.85%
http/cluster.js duration=5 c=50 len=102400 type='bytes' benchmarker='wrk' 0.14 % ±0.80% ±1.06% ±1.38%
http/cluster.js duration=5 c=50 len=4 type='buffer' benchmarker='wrk' -0.23 % ±0.29% ±0.39% ±0.51%
http/cluster.js duration=5 c=50 len=4 type='bytes' benchmarker='wrk' 0.00 % ±0.51% ±0.67% ±0.88%
http/cluster.js duration=5 c=500 len=1024 type='buffer' benchmarker='wrk' ** -0.77 % ±0.50% ±0.67% ±0.87%
http/cluster.js duration=5 c=500 len=1024 type='bytes' benchmarker='wrk' -0.18 % ±0.65% ±0.86% ±1.12%
http/cluster.js duration=5 c=500 len=102400 type='buffer' benchmarker='wrk' -0.18 % ±0.59% ±0.78% ±1.02%
http/cluster.js duration=5 c=500 len=102400 type='bytes' benchmarker='wrk' 0.28 % ±0.72% ±0.95% ±1.24%
http/cluster.js duration=5 c=500 len=4 type='buffer' benchmarker='wrk' -0.25 % ±0.47% ±0.62% ±0.81%
http/cluster.js duration=5 c=500 len=4 type='bytes' benchmarker='wrk' -0.36 % ±0.52% ±0.70% ±0.91%
http/create-clientrequest.js e=1 arg='options' url='idn' 2.09 % ±7.80% ±10.38% ±13.50%
http/create-clientrequest.js e=1 arg='options' url='long' -9.98 % ±14.10% ±18.77% ±24.46%
http/create-clientrequest.js e=1 arg='options' url='wpt' -4.69 % ±6.75% ±8.98% ±11.70%
http/create-clientrequest.js e=1 arg='string' url='idn' -4.15 % ±10.23% ±13.61% ±17.71%
http/create-clientrequest.js e=1 arg='string' url='long' -0.93 % ±12.77% ±16.99% ±22.12%
http/create-clientrequest.js e=1 arg='string' url='wpt' 0.60 % ±11.36% ±15.12% ±19.68%
http/create-clientrequest.js e=1 arg='URL' url='idn' 0.87 % ±9.17% ±12.20% ±15.88%
http/create-clientrequest.js e=1 arg='URL' url='long' -5.01 % ±10.02% ±13.35% ±17.41%
http/create-clientrequest.js e=1 arg='URL' url='wpt' 1.99 % ±8.00% ±10.64% ±13.85%
http/end-string.js duration=5 c=50 len=1024 benchmarker='wrk' *** 10.48 % ±0.81% ±1.08% ±1.41%
http/end-string.js duration=5 c=50 len=102400 benchmarker='wrk' *** 2.47 % ±0.50% ±0.66% ±0.86%
http/end-string.js duration=5 c=50 len=16384 benchmarker='wrk' *** 5.59 % ±0.89% ±1.19% ±1.55%
http/end-string.js duration=5 c=50 len=4 benchmarker='wrk' *** 9.92 % ±0.82% ±1.10% ±1.43%
http/end-string.js duration=5 c=50 len=64 benchmarker='wrk' *** 8.43 % ±0.71% ±0.94% ±1.23%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='asc' benchmarker='wrk' *** 2.48 % ±0.47% ±0.62% ±0.81%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='buf' benchmarker='wrk' -0.12 % ±0.43% ±0.57% ±0.74%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='utf' benchmarker='wrk' *** 0.68 % ±0.38% ±0.51% ±0.66%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='asc' benchmarker='wrk' ** 1.19 % ±0.81% ±1.09% ±1.43%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='buf' benchmarker='wrk' *** 1.50 % ±0.59% ±0.78% ±1.01%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='utf' benchmarker='wrk' *** 2.25 % ±0.45% ±0.59% ±0.77%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='asc' benchmarker='wrk' *** 1.18 % ±0.42% ±0.56% ±0.73%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='buf' benchmarker='wrk' *** 0.92 % ±0.48% ±0.63% ±0.83%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='utf' benchmarker='wrk' *** 1.25 % ±0.32% ±0.43% ±0.56%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='asc' benchmarker='wrk' *** 1.60 % ±0.83% ±1.10% ±1.44%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='buf' benchmarker='wrk' *** 2.34 % ±0.88% ±1.18% ±1.53%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='utf' benchmarker='wrk' *** 2.95 % ±0.48% ±0.64% ±0.83%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='asc' benchmarker='wrk' -0.33 % ±0.57% ±0.77% ±1.00%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='buf' benchmarker='wrk' -0.16 % ±0.52% ±0.69% ±0.90%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='utf' benchmarker='wrk' -0.12 % ±0.36% ±0.47% ±0.62%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='asc' benchmarker='wrk' 0.07 % ±0.76% ±1.01% ±1.32%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='buf' benchmarker='wrk' -0.25 % ±0.51% ±0.68% ±0.89%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='utf' benchmarker='wrk' 0.53 % ±1.00% ±1.34% ±1.74%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='asc' benchmarker='wrk' -0.26 % ±0.61% ±0.81% ±1.06%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='buf' benchmarker='wrk' -0.05 % ±0.47% ±0.62% ±0.81%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='utf' benchmarker='wrk' -0.08 % ±0.56% ±0.74% ±0.96%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='asc' benchmarker='wrk' -0.50 % ±0.96% ±1.28% ±1.66%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='buf' benchmarker='wrk' -0.22 % ±0.71% ±0.94% ±1.23%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='utf' benchmarker='wrk' 0.10 % ±0.58% ±0.77% ±1.01%
http/headers.js group='fewHeaders' duration=5 len=1 n=10 benchmarker='wrk' -0.23 % ±0.65% ±0.86% ±1.13%
http/headers.js group='fewHeaders' duration=5 len=5 n=10 benchmarker='wrk' 0.25 % ±0.59% ±0.79% ±1.03%
http/headers.js group='manyHeaders' duration=5 len=1 n=600 benchmarker='wrk' -0.11 % ±0.86% ±1.15% ±1.49%
http/headers.js group='manyHeaders' duration=5 len=100 n=600 benchmarker='wrk' 0.22 % ±1.12% ±1.49% ±1.94%
http/headers.js group='mediumHeaders' duration=5 len=1 n=50 benchmarker='wrk' -0.28 % ±0.51% ±0.67% ±0.88%
http/headers.js group='mediumHeaders' duration=5 len=10 n=50 benchmarker='wrk' 0.04 % ±0.53% ±0.71% ±0.93%
http/http_server_for_chunky_client.js type='send' n=2000 len=1 0.19 % ±0.57% ±0.77% ±1.00%
http/http_server_for_chunky_client.js type='send' n=2000 len=128 -0.12 % ±0.59% ±0.78% ±1.02%
http/http_server_for_chunky_client.js type='send' n=2000 len=16 -0.01 % ±0.60% ±0.79% ±1.03%
http/http_server_for_chunky_client.js type='send' n=2000 len=32 0.15 % ±0.61% ±0.81% ±1.06%
http/http_server_for_chunky_client.js type='send' n=2000 len=4 0.67 % ±0.69% ±0.92% ±1.21%
http/http_server_for_chunky_client.js type='send' n=2000 len=64 -0.30 % ±0.48% ±0.64% ±0.83%
http/http_server_for_chunky_client.js type='send' n=2000 len=8 -0.50 % ±0.55% ±0.73% ±0.95%
http/http_server_for_chunky_client.js type='send' n=5 len=1 -1.39 % ±2.60% ±3.47% ±4.51%
http/http_server_for_chunky_client.js type='send' n=5 len=128 -4.15 % ±13.02% ±17.32% ±22.54%
http/http_server_for_chunky_client.js type='send' n=5 len=16 7.54 % ±10.05% ±13.50% ±17.81%
http/http_server_for_chunky_client.js type='send' n=5 len=32 0.87 % ±11.95% ±15.91% ±20.71%
http/http_server_for_chunky_client.js type='send' n=5 len=4 1.73 % ±10.57% ±14.06% ±18.30%
http/http_server_for_chunky_client.js type='send' n=5 len=64 -5.12 % ±14.17% ±18.86% ±24.56%
http/http_server_for_chunky_client.js type='send' n=5 len=8 -2.55 % ±5.92% ±7.90% ±10.32%
http/http_server_for_chunky_client.js type='send' n=50 len=1 1.27 % ±2.86% ±3.81% ±4.96%
http/http_server_for_chunky_client.js type='send' n=50 len=128 * 5.17 % ±4.13% ±5.49% ±7.15%
http/http_server_for_chunky_client.js type='send' n=50 len=16 -0.71 % ±2.69% ±3.58% ±4.67%
http/http_server_for_chunky_client.js type='send' n=50 len=32 -0.12 % ±2.72% ±3.63% ±4.74%
http/http_server_for_chunky_client.js type='send' n=50 len=4 -1.47 % ±3.06% ±4.07% ±5.29%
http/http_server_for_chunky_client.js type='send' n=50 len=64 2.04 % ±3.51% ±4.67% ±6.09%
http/http_server_for_chunky_client.js type='send' n=50 len=8 -0.08 % ±2.21% ±2.94% ±3.84%
http/http_server_for_chunky_client.js type='send' n=500 len=1 -0.08 % ±0.80% ±1.07% ±1.40%
http/http_server_for_chunky_client.js type='send' n=500 len=128 -0.38 % ±0.70% ±0.93% ±1.21%
http/http_server_for_chunky_client.js type='send' n=500 len=16 * -0.94 % ±0.83% ±1.11% ±1.45%
http/http_server_for_chunky_client.js type='send' n=500 len=32 -0.43 % ±0.83% ±1.11% ±1.45%
http/http_server_for_chunky_client.js type='send' n=500 len=4 -0.02 % ±0.71% ±0.95% ±1.24%
http/http_server_for_chunky_client.js type='send' n=500 len=64 -0.19 % ±0.93% ±1.24% ±1.62%
http/http_server_for_chunky_client.js type='send' n=500 len=8 -0.15 % ±0.71% ±0.95% ±1.23%
http/incoming_headers.js duration=5 w=0 headers=20 connections=50 benchmarker='wrk' 0.04 % ±0.81% ±1.08% ±1.42%
http/incoming_headers.js duration=5 w=6 headers=20 connections=50 benchmarker='wrk' 0.04 % ±0.64% ±0.85% ±1.11%
http/set_header.js n=1000000 value='Connection' ** -2.20 % ±1.65% ±2.19% ±2.85%
http/set_header.js n=1000000 value='Content-Length' 0.29 % ±1.71% ±2.28% ±2.97%
http/set_header.js n=1000000 value='Content-Type' 1.33 % ±1.88% ±2.51% ±3.27%
http/set_header.js n=1000000 value='Set-Cookie' 1.14 % ±1.33% ±1.77% ±2.30%
http/set_header.js n=1000000 value='Transfer-Encoding' 1.06 % ±1.33% ±1.76% ±2.30%
http/set_header.js n=1000000 value='Vary' -0.57 % ±1.72% ±2.29% ±2.99%
http/set_header.js n=1000000 value='X-Powered-By' * 1.49 % ±1.33% ±1.77% ±2.30%
http/set-header.js duration=5 res='normal' benchmarker='wrk' *** 9.74 % ±0.78% ±1.04% ±1.35%
http/set-header.js duration=5 res='setHeader' benchmarker='wrk' *** 9.87 % ±0.83% ±1.10% ±1.44%
http/set-header.js duration=5 res='setHeaderWH' benchmarker='wrk' *** 9.59 % ±0.92% ±1.22% ±1.59%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=1024 type='buffer' benchmarker='wrk' *** 2.60 % ±0.75% ±1.00% ±1.30%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=1024 type='bytes' benchmarker='wrk' *** 9.54 % ±0.74% ±0.99% ±1.28%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=102400 type='buffer' benchmarker='wrk' ** 1.23 % ±0.75% ±0.99% ±1.29%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=102400 type='bytes' benchmarker='wrk' *** 1.98 % ±0.49% ±0.65% ±0.84%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=4 type='buffer' benchmarker='wrk' *** 2.43 % ±0.76% ±1.01% ±1.31%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=4 type='bytes' benchmarker='wrk' *** 9.55 % ±0.71% ±0.95% ±1.24%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=1024 type='buffer' benchmarker='wrk' *** 3.14 % ±0.86% ±1.15% ±1.50%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=1024 type='bytes' benchmarker='wrk' *** 2.94 % ±0.78% ±1.04% ±1.35%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=102400 type='buffer' benchmarker='wrk' *** 1.55 % ±0.62% ±0.82% ±1.07%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=102400 type='bytes' benchmarker='wrk' ** 1.10 % ±0.82% ±1.09% ±1.42%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=4 type='buffer' benchmarker='wrk' *** 3.91 % ±0.83% ±1.10% ±1.44%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=4 type='bytes' benchmarker='wrk' *** 3.47 % ±0.93% ±1.23% ±1.60%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=1024 type='buffer' benchmarker='wrk' *** 3.60 % ±0.96% ±1.27% ±1.66%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=1024 type='bytes' benchmarker='wrk' *** 9.20 % ±0.99% ±1.32% ±1.72%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=102400 type='buffer' benchmarker='wrk' *** 1.28 % ±0.53% ±0.71% ±0.93%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=102400 type='bytes' benchmarker='wrk' *** 1.28 % ±0.65% ±0.87% ±1.13%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=4 type='buffer' benchmarker='wrk' *** 3.59 % ±0.96% ±1.28% ±1.67%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=4 type='bytes' benchmarker='wrk' *** 9.93 % ±1.01% ±1.35% ±1.76%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=1024 type='buffer' benchmarker='wrk' *** 2.04 % ±0.98% ±1.31% ±1.70%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=1024 type='bytes' benchmarker='wrk' *** 2.14 % ±0.82% ±1.08% ±1.41%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=102400 type='buffer' benchmarker='wrk' *** 1.74 % ±0.67% ±0.89% ±1.16%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=102400 type='bytes' benchmarker='wrk' ** 1.10 % ±0.79% ±1.05% ±1.36%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=4 type='buffer' benchmarker='wrk' *** 3.20 % ±0.94% ±1.24% ±1.62%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=4 type='bytes' benchmarker='wrk' *** 3.12 % ±0.76% ±1.01% ±1.32%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=1024 type='buffer' benchmarker='wrk' -0.19 % ±0.80% ±1.06% ±1.38%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=1024 type='bytes' benchmarker='wrk' -0.44 % ±0.95% ±1.26% ±1.65%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=102400 type='buffer' benchmarker='wrk' 0.11 % ±0.61% ±0.81% ±1.06%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=102400 type='bytes' benchmarker='wrk' * -1.19 % ±1.11% ±1.47% ±1.92%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=4 type='buffer' benchmarker='wrk' -0.23 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=4 type='bytes' benchmarker='wrk' 0.10 % ±0.75% ±1.00% ±1.30%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=1024 type='buffer' benchmarker='wrk' -0.55 % ±0.76% ±1.01% ±1.32%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=1024 type='bytes' benchmarker='wrk' 0.19 % ±0.95% ±1.27% ±1.65%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=102400 type='buffer' benchmarker='wrk' ** -1.32 % ±0.79% ±1.06% ±1.37%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=102400 type='bytes' benchmarker='wrk' 0.69 % ±1.07% ±1.42% ±1.85%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=4 type='buffer' benchmarker='wrk' 0.54 % ±0.81% ±1.07% ±1.40%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=4 type='bytes' benchmarker='wrk' 0.56 % ±0.71% ±0.95% ±1.23%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=1024 type='buffer' benchmarker='wrk' -0.48 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=1024 type='bytes' benchmarker='wrk' -0.62 % ±0.85% ±1.13% ±1.48%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=102400 type='buffer' benchmarker='wrk' -0.20 % ±0.69% ±0.92% ±1.20%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=102400 type='bytes' benchmarker='wrk' 0.43 % ±1.18% ±1.56% ±2.04%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=4 type='buffer' benchmarker='wrk' 0.29 % ±0.89% ±1.19% ±1.55%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=4 type='bytes' benchmarker='wrk' * -1.01 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=1024 type='buffer' benchmarker='wrk' -0.18 % ±0.68% ±0.90% ±1.18%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=1024 type='bytes' benchmarker='wrk' 0.09 % ±0.65% ±0.86% ±1.12%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=102400 type='buffer' benchmarker='wrk' * -0.55 % ±0.49% ±0.66% ±0.86%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=102400 type='bytes' benchmarker='wrk' 0.10 % ±0.82% ±1.09% ±1.42%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=4 type='buffer' benchmarker='wrk' 0.35 % ±0.74% ±0.98% ±1.28%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=4 type='bytes' benchmarker='wrk' -0.26 % ±0.65% ±0.86% ±1.12%
http/upgrade.js n=1000 0.73 % ±2.37% ±3.16% ±4.11%
http/upgrade.js n=5 6.72 % ±8.30% ±11.05% ±14.38%

Be aware that when doing many comparisons the risk of a false-positive result increases.
In this case, there are 235 comparisons, you can thus expect the following amount of false-positive results:
11.75 false positives, when considering a 5% risk acceptance (*, **, *),
2.35 false positives, when considering a 1% risk acceptance (
, ),
0.24 false positives, when considering a 0.1% risk acceptance (
)

Looks good I think. Headlines:

  • No notable regressions - each of the small negative cases I can see are low-confidence and fit into an overall pattern of no change considering the tests around them
  • A very consistent 9.59% - 9.87% speed up in http/set-header.js test, which tests headers + res.end(body).
  • For http/simple:
    • Consistent boost around 9.5% with type=bytes, no chunking, and len up to 1024.
    • 3% boost with type=buffer, on the same small non-chunked responses.
    • Both buffer & byte body perf dropping to about 1-2% improvement for larger bodies (1MB).
    • No significant change with chunked encoding.
  • 10.48% boost to http/end-string test with 1KB, dropping to 5.59% with 16KB, down to 2.47% improvement with 1MB.
  • ~2% boost across various http/end-vs-write-end.js cases that call end(data) on different large sizes.

Looks pretty convincing to me! All approved and ready-to-go now and I think this is all just good news, so I'll commit-queue.

@pimterrypimterry added the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 24, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 214cf06 into nodejs:mainAug 24, 2026
85 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 214cf06

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 24, 2026
@pimterry
pimterry deleted the h1-clean-end-perf branch August 25, 2026 15:12
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
aduh95 pushed a commit that referenced this pull request Aug 27, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

httpIssues and PRs related to the http subsystem.needs-benchmark-ciPRs that need a benchmark CI run.needs-ciPRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants

@pimterry@nodejs-github-bot@mcollina@lpinca@anonrig@efekrskl@mertcanaltin@gurgunday@bjohansebas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

http: improve performance for end() with known-length string - #65466

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
pimterry:h1-clean-end-perf
Aug 24, 2026
Merged

http: improve performance for end() with known-length string#65466
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
pimterry:h1-clean-end-perf

Conversation

@pimterry

Copy link
Copy Markdown
Member

When you call end(data) on an outgoing HTTP request, we previously wrote the data, and then ran _send('', ...) just to trigger flushing the headers, which resulted in an extra zero-byte write call and bonus nextTick before 'finish'.

When the length is known and content-length is used (not chunking, so we don't need a terminator) we can skip this completely: prep the content-length header explicitly, and combine the finish into the existing write step.

This drops a nextTick, and goes from 2 write calls to 1 for the very common case of response.end(data) with a string, and for buffer data goes from 3 writes to 2.

In practice, in the tiny benchmark here which I think represents a very common use case (small API responses) I see this boosting HTTP RPS by up to 9% for writes up to 1KB or so. For larger responses the response write time starts to outweigh this, but I still see 3% RPS boost at 16KB. Needs autocannon to hit the rates required, you can test yourself with:

node benchmark/compare.js --old ./node-main --new ./node-pr --runs 20 --set benchmarker=autocannon --filter end-string http

Added a new test confirming the specific details and edge cases this touches, and updated one existing test which specifically asserted that end(data) triggered two writes, including the empty one.

This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/http
  • @nodejs/net
  • @nodejs/performance

@nodejs-github-botnodejs-github-bot added http Issues and PRs related to the http subsystem. needs-ci PRs that need a full CI run. labels Aug 21, 2026

@mcollinamcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@mcollina
mcollina requested a review from anonrigAugust 21, 2026 19:24
@codecov

codecovBot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.13%. Comparing base (15940ef) to head (659d6b9).
⚠️ Report is 61 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #65466 +/- ##
==========================================
- Coverage 90.14% 90.13% -0.01% 
==========================================
Files 751 751 Lines 252298 252333 +35 Branches 47446 47449 +3 ==========================================
+ Hits 227436 227451 +15 - Misses 16175 16186 +11 - Partials 8687 8696 +9 
Files with missing linesCoverage Δ
lib/_http_outgoing.js97.76% <100.00%> (-0.02%)⬇️

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

@pimterrypimterry added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 21, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 22, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@bjohansebasbjohansebas added the needs-benchmark-ci PRs that need a benchmark CI run. label Aug 22, 2026
@pimterry

Copy link
Copy Markdown
MemberAuthor

@bjohansebas benchmark label was a good suggestion. I've done a run here.

Unfortunately it seems like the microbenchmark job is broken generally (cc @nodejs/build) and all recent jobs have failed with:

++ Rscript benchmark/compare.R
Error: package or namespace load failed for ‘ggplot2’ in dyn.load(file, DLLpath = DLLpath, ...):
unable to load shared object '/usr/local/lib/R/site-library/rlang/libs/rlang.so':
/usr/local/lib/R/site-library/rlang/libs/rlang.so: undefined symbol: SETLENGTH
Execution halted

I've manually extracted the CSV from the console output to get some numbers though, and run node-benchmark-compare on the result, which gives:

Details
 confidence improvement accuracy (*) (**) (***)
http/bench-parser-fragmented.js n=100000 frags=2 len=16 -0.20 % ±1.06% ±1.42% ±1.85%
http/bench-parser-fragmented.js n=100000 frags=2 len=8 -0.01 % ±0.94% ±1.25% ±1.63%
http/bench-parser-fragmented.js n=100000 frags=4 len=16 -0.17 % ±0.77% ±1.02% ±1.33%
http/bench-parser-fragmented.js n=100000 frags=4 len=8 -0.57 % ±0.64% ±0.85% ±1.11%
http/bench-parser-fragmented.js n=100000 frags=8 len=16 -0.07 % ±0.84% ±1.12% ±1.45%
http/bench-parser-fragmented.js n=100000 frags=8 len=8 0.43 % ±0.78% ±1.04% ±1.35%
http/bench-parser.js n=100000 len=16 0.20 % ±0.93% ±1.24% ±1.61%
http/bench-parser.js n=100000 len=32 0.03 % ±0.68% ±0.90% ±1.17%
http/bench-parser.js n=100000 len=4 0.60 % ±1.08% ±1.43% ±1.86%
http/bench-parser.js n=100000 len=8 0.32 % ±1.11% ±1.47% ±1.92%
http/check_invalid_header_char.js n=1000000 input='' 1.25 % ±2.48% ±3.30% ±4.30%
http/check_invalid_header_char.js n=1000000 input='\t\t\t\t\t\t\t\t\t\tFoo bar baz' 0.39 % ±1.66% ±2.21% ±2.88%
http/check_invalid_header_char.js n=1000000 input='\x7F' * 4.92 % ±3.90% ±5.19% ±6.75%
http/check_invalid_header_char.js n=1000000 input='1' -0.41 % ±3.47% ±4.62% ±6.02%
http/check_invalid_header_char.js n=1000000 input='20091' -0.50 % ±3.85% ±5.12% ±6.66%
http/check_invalid_header_char.js n=1000000 input='close' 0.49 % ±3.34% ±4.44% ±5.78%
http/check_invalid_header_char.js n=1000000 input='en-US' -0.66 % ±3.59% ±4.77% ±6.21%
http/check_invalid_header_char.js n=1000000 input='foo\nbar' -1.88 % ±2.70% ±3.60% ±4.70%
http/check_invalid_header_char.js n=1000000 input='group_acmeair' 0.85 % ±1.82% ±2.42% ±3.16%
http/check_invalid_header_char.js n=1000000 input='gzip' -0.60 % ±3.29% ±4.37% ±5.70%
http/check_invalid_header_char.js n=1000000 input='keep-alive' -1.28 % ±2.16% ±2.88% ±3.75%
http/check_invalid_header_char.js n=1000000 input='LONG_AND_INVALID' 0.08 % ±1.13% ±1.51% ±1.97%
http/check_invalid_header_char.js n=1000000 input='private' 1.00 % ±2.68% ±3.57% ±4.65%
http/check_invalid_header_char.js n=1000000 input='SAMEORIGIN' 1.36 % ±2.81% ±3.74% ±4.88%
http/check_invalid_header_char.js n=1000000 input='Sat, 07 May 2016 16:54:48 GMT' 0.79 % ±1.41% ±1.87% ±2.44%
http/check_invalid_header_char.js n=1000000 input='text/html; charset=utf-8' -0.12 % ±1.41% ±1.88% ±2.45%
http/check_invalid_header_char.js n=1000000 input='text/plain' -1.49 % ±2.96% ±3.95% ±5.14%
http/check_invalid_header_char.js n=1000000 input='中文呢' 1.95 % ±2.71% ±3.61% ±4.69%
http/check_is_http_token.js n=1000000 key=':' -0.22 % ±2.22% ±2.96% ±3.85%
http/check_is_http_token.js n=1000000 key=':alternate-protocol' 2.82 % ±4.07% ±5.42% ±7.06%
http/check_is_http_token.js n=1000000 key='((((())))' -1.22 % ±2.75% ±3.71% ±4.91%
http/check_is_http_token.js n=1000000 key='@@' 0.52 % ±2.14% ±2.85% ±3.71%
http/check_is_http_token.js n=1000000 key='Accept-Ranges' 0.51 % ±2.25% ±2.99% ±3.90%
http/check_is_http_token.js n=1000000 key='alt-svc' -0.09 % ±2.23% ±2.97% ±3.87%
http/check_is_http_token.js n=1000000 key='alternate-protocol:' -0.94 % ±2.08% ±2.77% ±3.61%
http/check_is_http_token.js n=1000000 key='alternate-protocol' -1.19 % ±2.32% ±3.09% ±4.03%
http/check_is_http_token.js n=1000000 key='Cache-Control' -0.96 % ±2.14% ±2.85% ±3.71%
http/check_is_http_token.js n=1000000 key='Connection' 0.78 % ±2.39% ±3.19% ±4.15%
http/check_is_http_token.js n=1000000 key='Content-Encoding' * -2.76 % ±2.26% ±3.01% ±3.92%
http/check_is_http_token.js n=1000000 key='content-length' 0.93 % ±2.27% ±3.02% ±3.92%
http/check_is_http_token.js n=1000000 key='Content-Location' -0.15 % ±2.52% ±3.35% ±4.36%
http/check_is_http_token.js n=1000000 key='content-type' -0.49 % ±2.55% ±3.39% ±4.41%
http/check_is_http_token.js n=1000000 key='Content-Type' 0.46 % ±2.58% ±3.43% ±4.47%
http/check_is_http_token.js n=1000000 key='date' 0.62 % ±2.42% ±3.22% ±4.19%
http/check_is_http_token.js n=1000000 key='ETag' -2.60 % ±3.97% ±5.32% ±7.01%
http/check_is_http_token.js n=1000000 key='Expires' ** 3.69 % ±2.64% ±3.52% ±4.59%
http/check_is_http_token.js n=1000000 key='Keep-Alive' -0.03 % ±2.59% ±3.45% ±4.48%
http/check_is_http_token.js n=1000000 key='Last-Modified' -0.99 % ±2.34% ±3.12% ±4.07%
http/check_is_http_token.js n=1000000 key='location' 0.79 % ±2.44% ±3.25% ±4.23%
http/check_is_http_token.js n=1000000 key='server' 0.37 % ±2.46% ±3.27% ±4.25%
http/check_is_http_token.js n=1000000 key='Server' * 3.70 % ±3.00% ±4.00% ±5.23%
http/check_is_http_token.js n=1000000 key='status' ** -4.32 % ±3.09% ±4.13% ±5.40%
http/check_is_http_token.js n=1000000 key='TCN' -0.86 % ±1.00% ±1.33% ±1.73%
http/check_is_http_token.js n=1000000 key='Transfer-Encoding' -1.00 % ±2.32% ±3.09% ±4.02%
http/check_is_http_token.js n=1000000 key='Vary' -0.56 % ±1.47% ±1.95% ±2.54%
http/check_is_http_token.js n=1000000 key='version' 1.90 % ±2.74% ±3.65% ±4.75%
http/check_is_http_token.js n=1000000 key='x-frame-options' 0.57 % ±2.05% ±2.73% ±3.55%
http/check_is_http_token.js n=1000000 key='x-xss-protection' -1.39 % ±2.29% ±3.06% ±3.99%
http/check_is_http_token.js n=1000000 key='中文呢' -1.00 % ±4.47% ±6.01% ±7.92%
http/chunked.js duration=5 c=100 len=1 n=1 benchmarker='wrk' -0.19 % ±0.68% ±0.91% ±1.18%
http/chunked.js duration=5 c=100 len=1 n=16 benchmarker='wrk' 0.41 % ±0.78% ±1.03% ±1.35%
http/chunked.js duration=5 c=100 len=1 n=4 benchmarker='wrk' 0.61 % ±2.08% ±2.76% ±3.60%
http/chunked.js duration=5 c=100 len=1 n=8 benchmarker='wrk' 0.13 % ±0.81% ±1.07% ±1.40%
http/chunked.js duration=5 c=100 len=256 n=1 benchmarker='wrk' -0.10 % ±0.70% ±0.93% ±1.21%
http/chunked.js duration=5 c=100 len=256 n=16 benchmarker='wrk' -0.70 % ±0.73% ±0.97% ±1.26%
http/chunked.js duration=5 c=100 len=256 n=4 benchmarker='wrk' -0.58 % ±1.84% ±2.45% ±3.18%
http/chunked.js duration=5 c=100 len=256 n=8 benchmarker='wrk' 0.11 % ±0.87% ±1.16% ±1.51%
http/chunked.js duration=5 c=100 len=64 n=1 benchmarker='wrk' -0.26 % ±0.60% ±0.80% ±1.04%
http/chunked.js duration=5 c=100 len=64 n=16 benchmarker='wrk' 0.56 % ±0.63% ±0.84% ±1.10%
http/chunked.js duration=5 c=100 len=64 n=4 benchmarker='wrk' 0.08 % ±1.81% ±2.41% ±3.15%
http/chunked.js duration=5 c=100 len=64 n=8 benchmarker='wrk' 0.26 % ±0.75% ±1.00% ±1.30%
http/client-request-body.js method='end' len=1024 type='asc' dur=5 -0.06 % ±0.69% ±0.92% ±1.20%
http/client-request-body.js method='end' len=1024 type='buf' dur=5 0.01 % ±0.76% ±1.02% ±1.32%
http/client-request-body.js method='end' len=1024 type='utf' dur=5 -0.28 % ±0.59% ±0.79% ±1.03%
http/client-request-body.js method='end' len=256 type='asc' dur=5 -0.49 % ±0.67% ±0.90% ±1.17%
http/client-request-body.js method='end' len=256 type='buf' dur=5 * -0.75 % ±0.68% ±0.90% ±1.18%
http/client-request-body.js method='end' len=256 type='utf' dur=5 0.03 % ±0.62% ±0.83% ±1.08%
http/client-request-body.js method='end' len=32 type='asc' dur=5 -0.01 % ±0.56% ±0.75% ±0.98%
http/client-request-body.js method='end' len=32 type='buf' dur=5 -0.37 % ±0.60% ±0.79% ±1.03%
http/client-request-body.js method='end' len=32 type='utf' dur=5 -0.16 % ±0.62% ±0.83% ±1.08%
http/client-request-body.js method='write' len=1024 type='asc' dur=5 -0.16 % ±0.78% ±1.03% ±1.34%
http/client-request-body.js method='write' len=1024 type='buf' dur=5 -0.34 % ±0.68% ±0.90% ±1.17%
http/client-request-body.js method='write' len=1024 type='utf' dur=5 0.06 % ±0.78% ±1.04% ±1.35%
http/client-request-body.js method='write' len=256 type='asc' dur=5 0.27 % ±0.70% ±0.93% ±1.21%
http/client-request-body.js method='write' len=256 type='buf' dur=5 0.09 % ±0.76% ±1.02% ±1.32%
http/client-request-body.js method='write' len=256 type='utf' dur=5 0.49 % ±0.59% ±0.79% ±1.03%
http/client-request-body.js method='write' len=32 type='asc' dur=5 -0.40 % ±0.64% ±0.86% ±1.11%
http/client-request-body.js method='write' len=32 type='buf' dur=5 -0.21 % ±0.65% ±0.86% ±1.12%
http/client-request-body.js method='write' len=32 type='utf' dur=5 0.02 % ±0.60% ±0.79% ±1.03%
http/cluster.js duration=5 c=50 len=1024 type='buffer' benchmarker='wrk' 0.13 % ±0.46% ±0.62% ±0.81%
http/cluster.js duration=5 c=50 len=1024 type='bytes' benchmarker='wrk' -0.11 % ±0.38% ±0.50% ±0.66%
http/cluster.js duration=5 c=50 len=102400 type='buffer' benchmarker='wrk' -0.24 % ±0.49% ±0.65% ±0.85%
http/cluster.js duration=5 c=50 len=102400 type='bytes' benchmarker='wrk' 0.14 % ±0.80% ±1.06% ±1.38%
http/cluster.js duration=5 c=50 len=4 type='buffer' benchmarker='wrk' -0.23 % ±0.29% ±0.39% ±0.51%
http/cluster.js duration=5 c=50 len=4 type='bytes' benchmarker='wrk' 0.00 % ±0.51% ±0.67% ±0.88%
http/cluster.js duration=5 c=500 len=1024 type='buffer' benchmarker='wrk' ** -0.77 % ±0.50% ±0.67% ±0.87%
http/cluster.js duration=5 c=500 len=1024 type='bytes' benchmarker='wrk' -0.18 % ±0.65% ±0.86% ±1.12%
http/cluster.js duration=5 c=500 len=102400 type='buffer' benchmarker='wrk' -0.18 % ±0.59% ±0.78% ±1.02%
http/cluster.js duration=5 c=500 len=102400 type='bytes' benchmarker='wrk' 0.28 % ±0.72% ±0.95% ±1.24%
http/cluster.js duration=5 c=500 len=4 type='buffer' benchmarker='wrk' -0.25 % ±0.47% ±0.62% ±0.81%
http/cluster.js duration=5 c=500 len=4 type='bytes' benchmarker='wrk' -0.36 % ±0.52% ±0.70% ±0.91%
http/create-clientrequest.js e=1 arg='options' url='idn' 2.09 % ±7.80% ±10.38% ±13.50%
http/create-clientrequest.js e=1 arg='options' url='long' -9.98 % ±14.10% ±18.77% ±24.46%
http/create-clientrequest.js e=1 arg='options' url='wpt' -4.69 % ±6.75% ±8.98% ±11.70%
http/create-clientrequest.js e=1 arg='string' url='idn' -4.15 % ±10.23% ±13.61% ±17.71%
http/create-clientrequest.js e=1 arg='string' url='long' -0.93 % ±12.77% ±16.99% ±22.12%
http/create-clientrequest.js e=1 arg='string' url='wpt' 0.60 % ±11.36% ±15.12% ±19.68%
http/create-clientrequest.js e=1 arg='URL' url='idn' 0.87 % ±9.17% ±12.20% ±15.88%
http/create-clientrequest.js e=1 arg='URL' url='long' -5.01 % ±10.02% ±13.35% ±17.41%
http/create-clientrequest.js e=1 arg='URL' url='wpt' 1.99 % ±8.00% ±10.64% ±13.85%
http/end-string.js duration=5 c=50 len=1024 benchmarker='wrk' *** 10.48 % ±0.81% ±1.08% ±1.41%
http/end-string.js duration=5 c=50 len=102400 benchmarker='wrk' *** 2.47 % ±0.50% ±0.66% ±0.86%
http/end-string.js duration=5 c=50 len=16384 benchmarker='wrk' *** 5.59 % ±0.89% ±1.19% ±1.55%
http/end-string.js duration=5 c=50 len=4 benchmarker='wrk' *** 9.92 % ±0.82% ±1.10% ±1.43%
http/end-string.js duration=5 c=50 len=64 benchmarker='wrk' *** 8.43 % ±0.71% ±0.94% ±1.23%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='asc' benchmarker='wrk' *** 2.48 % ±0.47% ±0.62% ±0.81%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='buf' benchmarker='wrk' -0.12 % ±0.43% ±0.57% ±0.74%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='utf' benchmarker='wrk' *** 0.68 % ±0.38% ±0.51% ±0.66%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='asc' benchmarker='wrk' ** 1.19 % ±0.81% ±1.09% ±1.43%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='buf' benchmarker='wrk' *** 1.50 % ±0.59% ±0.78% ±1.01%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='utf' benchmarker='wrk' *** 2.25 % ±0.45% ±0.59% ±0.77%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='asc' benchmarker='wrk' *** 1.18 % ±0.42% ±0.56% ±0.73%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='buf' benchmarker='wrk' *** 0.92 % ±0.48% ±0.63% ±0.83%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='utf' benchmarker='wrk' *** 1.25 % ±0.32% ±0.43% ±0.56%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='asc' benchmarker='wrk' *** 1.60 % ±0.83% ±1.10% ±1.44%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='buf' benchmarker='wrk' *** 2.34 % ±0.88% ±1.18% ±1.53%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='utf' benchmarker='wrk' *** 2.95 % ±0.48% ±0.64% ±0.83%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='asc' benchmarker='wrk' -0.33 % ±0.57% ±0.77% ±1.00%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='buf' benchmarker='wrk' -0.16 % ±0.52% ±0.69% ±0.90%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='utf' benchmarker='wrk' -0.12 % ±0.36% ±0.47% ±0.62%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='asc' benchmarker='wrk' 0.07 % ±0.76% ±1.01% ±1.32%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='buf' benchmarker='wrk' -0.25 % ±0.51% ±0.68% ±0.89%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='utf' benchmarker='wrk' 0.53 % ±1.00% ±1.34% ±1.74%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='asc' benchmarker='wrk' -0.26 % ±0.61% ±0.81% ±1.06%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='buf' benchmarker='wrk' -0.05 % ±0.47% ±0.62% ±0.81%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='utf' benchmarker='wrk' -0.08 % ±0.56% ±0.74% ±0.96%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='asc' benchmarker='wrk' -0.50 % ±0.96% ±1.28% ±1.66%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='buf' benchmarker='wrk' -0.22 % ±0.71% ±0.94% ±1.23%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='utf' benchmarker='wrk' 0.10 % ±0.58% ±0.77% ±1.01%
http/headers.js group='fewHeaders' duration=5 len=1 n=10 benchmarker='wrk' -0.23 % ±0.65% ±0.86% ±1.13%
http/headers.js group='fewHeaders' duration=5 len=5 n=10 benchmarker='wrk' 0.25 % ±0.59% ±0.79% ±1.03%
http/headers.js group='manyHeaders' duration=5 len=1 n=600 benchmarker='wrk' -0.11 % ±0.86% ±1.15% ±1.49%
http/headers.js group='manyHeaders' duration=5 len=100 n=600 benchmarker='wrk' 0.22 % ±1.12% ±1.49% ±1.94%
http/headers.js group='mediumHeaders' duration=5 len=1 n=50 benchmarker='wrk' -0.28 % ±0.51% ±0.67% ±0.88%
http/headers.js group='mediumHeaders' duration=5 len=10 n=50 benchmarker='wrk' 0.04 % ±0.53% ±0.71% ±0.93%
http/http_server_for_chunky_client.js type='send' n=2000 len=1 0.19 % ±0.57% ±0.77% ±1.00%
http/http_server_for_chunky_client.js type='send' n=2000 len=128 -0.12 % ±0.59% ±0.78% ±1.02%
http/http_server_for_chunky_client.js type='send' n=2000 len=16 -0.01 % ±0.60% ±0.79% ±1.03%
http/http_server_for_chunky_client.js type='send' n=2000 len=32 0.15 % ±0.61% ±0.81% ±1.06%
http/http_server_for_chunky_client.js type='send' n=2000 len=4 0.67 % ±0.69% ±0.92% ±1.21%
http/http_server_for_chunky_client.js type='send' n=2000 len=64 -0.30 % ±0.48% ±0.64% ±0.83%
http/http_server_for_chunky_client.js type='send' n=2000 len=8 -0.50 % ±0.55% ±0.73% ±0.95%
http/http_server_for_chunky_client.js type='send' n=5 len=1 -1.39 % ±2.60% ±3.47% ±4.51%
http/http_server_for_chunky_client.js type='send' n=5 len=128 -4.15 % ±13.02% ±17.32% ±22.54%
http/http_server_for_chunky_client.js type='send' n=5 len=16 7.54 % ±10.05% ±13.50% ±17.81%
http/http_server_for_chunky_client.js type='send' n=5 len=32 0.87 % ±11.95% ±15.91% ±20.71%
http/http_server_for_chunky_client.js type='send' n=5 len=4 1.73 % ±10.57% ±14.06% ±18.30%
http/http_server_for_chunky_client.js type='send' n=5 len=64 -5.12 % ±14.17% ±18.86% ±24.56%
http/http_server_for_chunky_client.js type='send' n=5 len=8 -2.55 % ±5.92% ±7.90% ±10.32%
http/http_server_for_chunky_client.js type='send' n=50 len=1 1.27 % ±2.86% ±3.81% ±4.96%
http/http_server_for_chunky_client.js type='send' n=50 len=128 * 5.17 % ±4.13% ±5.49% ±7.15%
http/http_server_for_chunky_client.js type='send' n=50 len=16 -0.71 % ±2.69% ±3.58% ±4.67%
http/http_server_for_chunky_client.js type='send' n=50 len=32 -0.12 % ±2.72% ±3.63% ±4.74%
http/http_server_for_chunky_client.js type='send' n=50 len=4 -1.47 % ±3.06% ±4.07% ±5.29%
http/http_server_for_chunky_client.js type='send' n=50 len=64 2.04 % ±3.51% ±4.67% ±6.09%
http/http_server_for_chunky_client.js type='send' n=50 len=8 -0.08 % ±2.21% ±2.94% ±3.84%
http/http_server_for_chunky_client.js type='send' n=500 len=1 -0.08 % ±0.80% ±1.07% ±1.40%
http/http_server_for_chunky_client.js type='send' n=500 len=128 -0.38 % ±0.70% ±0.93% ±1.21%
http/http_server_for_chunky_client.js type='send' n=500 len=16 * -0.94 % ±0.83% ±1.11% ±1.45%
http/http_server_for_chunky_client.js type='send' n=500 len=32 -0.43 % ±0.83% ±1.11% ±1.45%
http/http_server_for_chunky_client.js type='send' n=500 len=4 -0.02 % ±0.71% ±0.95% ±1.24%
http/http_server_for_chunky_client.js type='send' n=500 len=64 -0.19 % ±0.93% ±1.24% ±1.62%
http/http_server_for_chunky_client.js type='send' n=500 len=8 -0.15 % ±0.71% ±0.95% ±1.23%
http/incoming_headers.js duration=5 w=0 headers=20 connections=50 benchmarker='wrk' 0.04 % ±0.81% ±1.08% ±1.42%
http/incoming_headers.js duration=5 w=6 headers=20 connections=50 benchmarker='wrk' 0.04 % ±0.64% ±0.85% ±1.11%
http/set_header.js n=1000000 value='Connection' ** -2.20 % ±1.65% ±2.19% ±2.85%
http/set_header.js n=1000000 value='Content-Length' 0.29 % ±1.71% ±2.28% ±2.97%
http/set_header.js n=1000000 value='Content-Type' 1.33 % ±1.88% ±2.51% ±3.27%
http/set_header.js n=1000000 value='Set-Cookie' 1.14 % ±1.33% ±1.77% ±2.30%
http/set_header.js n=1000000 value='Transfer-Encoding' 1.06 % ±1.33% ±1.76% ±2.30%
http/set_header.js n=1000000 value='Vary' -0.57 % ±1.72% ±2.29% ±2.99%
http/set_header.js n=1000000 value='X-Powered-By' * 1.49 % ±1.33% ±1.77% ±2.30%
http/set-header.js duration=5 res='normal' benchmarker='wrk' *** 9.74 % ±0.78% ±1.04% ±1.35%
http/set-header.js duration=5 res='setHeader' benchmarker='wrk' *** 9.87 % ±0.83% ±1.10% ±1.44%
http/set-header.js duration=5 res='setHeaderWH' benchmarker='wrk' *** 9.59 % ±0.92% ±1.22% ±1.59%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=1024 type='buffer' benchmarker='wrk' *** 2.60 % ±0.75% ±1.00% ±1.30%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=1024 type='bytes' benchmarker='wrk' *** 9.54 % ±0.74% ±0.99% ±1.28%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=102400 type='buffer' benchmarker='wrk' ** 1.23 % ±0.75% ±0.99% ±1.29%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=102400 type='bytes' benchmarker='wrk' *** 1.98 % ±0.49% ±0.65% ±0.84%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=4 type='buffer' benchmarker='wrk' *** 2.43 % ±0.76% ±1.01% ±1.31%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=4 type='bytes' benchmarker='wrk' *** 9.55 % ±0.71% ±0.95% ±1.24%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=1024 type='buffer' benchmarker='wrk' *** 3.14 % ±0.86% ±1.15% ±1.50%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=1024 type='bytes' benchmarker='wrk' *** 2.94 % ±0.78% ±1.04% ±1.35%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=102400 type='buffer' benchmarker='wrk' *** 1.55 % ±0.62% ±0.82% ±1.07%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=102400 type='bytes' benchmarker='wrk' ** 1.10 % ±0.82% ±1.09% ±1.42%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=4 type='buffer' benchmarker='wrk' *** 3.91 % ±0.83% ±1.10% ±1.44%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=4 type='bytes' benchmarker='wrk' *** 3.47 % ±0.93% ±1.23% ±1.60%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=1024 type='buffer' benchmarker='wrk' *** 3.60 % ±0.96% ±1.27% ±1.66%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=1024 type='bytes' benchmarker='wrk' *** 9.20 % ±0.99% ±1.32% ±1.72%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=102400 type='buffer' benchmarker='wrk' *** 1.28 % ±0.53% ±0.71% ±0.93%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=102400 type='bytes' benchmarker='wrk' *** 1.28 % ±0.65% ±0.87% ±1.13%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=4 type='buffer' benchmarker='wrk' *** 3.59 % ±0.96% ±1.28% ±1.67%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=4 type='bytes' benchmarker='wrk' *** 9.93 % ±1.01% ±1.35% ±1.76%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=1024 type='buffer' benchmarker='wrk' *** 2.04 % ±0.98% ±1.31% ±1.70%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=1024 type='bytes' benchmarker='wrk' *** 2.14 % ±0.82% ±1.08% ±1.41%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=102400 type='buffer' benchmarker='wrk' *** 1.74 % ±0.67% ±0.89% ±1.16%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=102400 type='bytes' benchmarker='wrk' ** 1.10 % ±0.79% ±1.05% ±1.36%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=4 type='buffer' benchmarker='wrk' *** 3.20 % ±0.94% ±1.24% ±1.62%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=4 type='bytes' benchmarker='wrk' *** 3.12 % ±0.76% ±1.01% ±1.32%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=1024 type='buffer' benchmarker='wrk' -0.19 % ±0.80% ±1.06% ±1.38%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=1024 type='bytes' benchmarker='wrk' -0.44 % ±0.95% ±1.26% ±1.65%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=102400 type='buffer' benchmarker='wrk' 0.11 % ±0.61% ±0.81% ±1.06%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=102400 type='bytes' benchmarker='wrk' * -1.19 % ±1.11% ±1.47% ±1.92%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=4 type='buffer' benchmarker='wrk' -0.23 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=4 type='bytes' benchmarker='wrk' 0.10 % ±0.75% ±1.00% ±1.30%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=1024 type='buffer' benchmarker='wrk' -0.55 % ±0.76% ±1.01% ±1.32%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=1024 type='bytes' benchmarker='wrk' 0.19 % ±0.95% ±1.27% ±1.65%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=102400 type='buffer' benchmarker='wrk' ** -1.32 % ±0.79% ±1.06% ±1.37%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=102400 type='bytes' benchmarker='wrk' 0.69 % ±1.07% ±1.42% ±1.85%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=4 type='buffer' benchmarker='wrk' 0.54 % ±0.81% ±1.07% ±1.40%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=4 type='bytes' benchmarker='wrk' 0.56 % ±0.71% ±0.95% ±1.23%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=1024 type='buffer' benchmarker='wrk' -0.48 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=1024 type='bytes' benchmarker='wrk' -0.62 % ±0.85% ±1.13% ±1.48%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=102400 type='buffer' benchmarker='wrk' -0.20 % ±0.69% ±0.92% ±1.20%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=102400 type='bytes' benchmarker='wrk' 0.43 % ±1.18% ±1.56% ±2.04%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=4 type='buffer' benchmarker='wrk' 0.29 % ±0.89% ±1.19% ±1.55%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=4 type='bytes' benchmarker='wrk' * -1.01 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=1024 type='buffer' benchmarker='wrk' -0.18 % ±0.68% ±0.90% ±1.18%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=1024 type='bytes' benchmarker='wrk' 0.09 % ±0.65% ±0.86% ±1.12%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=102400 type='buffer' benchmarker='wrk' * -0.55 % ±0.49% ±0.66% ±0.86%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=102400 type='bytes' benchmarker='wrk' 0.10 % ±0.82% ±1.09% ±1.42%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=4 type='buffer' benchmarker='wrk' 0.35 % ±0.74% ±0.98% ±1.28%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=4 type='bytes' benchmarker='wrk' -0.26 % ±0.65% ±0.86% ±1.12%
http/upgrade.js n=1000 0.73 % ±2.37% ±3.16% ±4.11%
http/upgrade.js n=5 6.72 % ±8.30% ±11.05% ±14.38%

Be aware that when doing many comparisons the risk of a false-positive result increases.
In this case, there are 235 comparisons, you can thus expect the following amount of false-positive results:
11.75 false positives, when considering a 5% risk acceptance (*, **, *),
2.35 false positives, when considering a 1% risk acceptance (
, ),
0.24 false positives, when considering a 0.1% risk acceptance (
)

Looks good I think. Headlines:

  • No notable regressions - each of the small negative cases I can see are low-confidence and fit into an overall pattern of no change considering the tests around them
  • A very consistent 9.59% - 9.87% speed up in http/set-header.js test, which tests headers + res.end(body).
  • For http/simple:
    • Consistent boost around 9.5% with type=bytes, no chunking, and len up to 1024.
    • 3% boost with type=buffer, on the same small non-chunked responses.
    • Both buffer & byte body perf dropping to about 1-2% improvement for larger bodies (1MB).
    • No significant change with chunked encoding.
  • 10.48% boost to http/end-string test with 1KB, dropping to 5.59% with 16KB, down to 2.47% improvement with 1MB.
  • ~2% boost across various http/end-vs-write-end.js cases that call end(data) on different large sizes.

Looks pretty convincing to me! All approved and ready-to-go now and I think this is all just good news, so I'll commit-queue.

@pimterrypimterry added the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 24, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 214cf06 into nodejs:mainAug 24, 2026
85 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 214cf06

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 24, 2026
@pimterry
pimterry deleted the h1-clean-end-perf branch August 25, 2026 15:12
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
aduh95 pushed a commit that referenced this pull request Aug 27, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

httpIssues and PRs related to the http subsystem.needs-benchmark-ciPRs that need a benchmark CI run.needs-ciPRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants

@pimterry@nodejs-github-bot@mcollina@lpinca@anonrig@efekrskl@mertcanaltin@gurgunday@bjohansebas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

http: improve performance for end() with known-length string - #65466

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
pimterry:h1-clean-end-perf
Aug 24, 2026
Merged

http: improve performance for end() with known-length string#65466
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
pimterry:h1-clean-end-perf

Conversation

@pimterry

Copy link
Copy Markdown
Member

When you call end(data) on an outgoing HTTP request, we previously wrote the data, and then ran _send('', ...) just to trigger flushing the headers, which resulted in an extra zero-byte write call and bonus nextTick before 'finish'.

When the length is known and content-length is used (not chunking, so we don't need a terminator) we can skip this completely: prep the content-length header explicitly, and combine the finish into the existing write step.

This drops a nextTick, and goes from 2 write calls to 1 for the very common case of response.end(data) with a string, and for buffer data goes from 3 writes to 2.

In practice, in the tiny benchmark here which I think represents a very common use case (small API responses) I see this boosting HTTP RPS by up to 9% for writes up to 1KB or so. For larger responses the response write time starts to outweigh this, but I still see 3% RPS boost at 16KB. Needs autocannon to hit the rates required, you can test yourself with:

node benchmark/compare.js --old ./node-main --new ./node-pr --runs 20 --set benchmarker=autocannon --filter end-string http

Added a new test confirming the specific details and edge cases this touches, and updated one existing test which specifically asserted that end(data) triggered two writes, including the empty one.

This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/http
  • @nodejs/net
  • @nodejs/performance

@nodejs-github-botnodejs-github-bot added http Issues and PRs related to the http subsystem. needs-ci PRs that need a full CI run. labels Aug 21, 2026

@mcollinamcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@mcollina
mcollina requested a review from anonrigAugust 21, 2026 19:24
@codecov

codecovBot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.13%. Comparing base (15940ef) to head (659d6b9).
⚠️ Report is 61 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #65466 +/- ##
==========================================
- Coverage 90.14% 90.13% -0.01% 
==========================================
Files 751 751 Lines 252298 252333 +35 Branches 47446 47449 +3 ==========================================
+ Hits 227436 227451 +15 - Misses 16175 16186 +11 - Partials 8687 8696 +9 
Files with missing linesCoverage Δ
lib/_http_outgoing.js97.76% <100.00%> (-0.02%)⬇️

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

@pimterrypimterry added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 21, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 22, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@bjohansebasbjohansebas added the needs-benchmark-ci PRs that need a benchmark CI run. label Aug 22, 2026
@pimterry

Copy link
Copy Markdown
MemberAuthor

@bjohansebas benchmark label was a good suggestion. I've done a run here.

Unfortunately it seems like the microbenchmark job is broken generally (cc @nodejs/build) and all recent jobs have failed with:

++ Rscript benchmark/compare.R
Error: package or namespace load failed for ‘ggplot2’ in dyn.load(file, DLLpath = DLLpath, ...):
unable to load shared object '/usr/local/lib/R/site-library/rlang/libs/rlang.so':
/usr/local/lib/R/site-library/rlang/libs/rlang.so: undefined symbol: SETLENGTH
Execution halted

I've manually extracted the CSV from the console output to get some numbers though, and run node-benchmark-compare on the result, which gives:

Details
 confidence improvement accuracy (*) (**) (***)
http/bench-parser-fragmented.js n=100000 frags=2 len=16 -0.20 % ±1.06% ±1.42% ±1.85%
http/bench-parser-fragmented.js n=100000 frags=2 len=8 -0.01 % ±0.94% ±1.25% ±1.63%
http/bench-parser-fragmented.js n=100000 frags=4 len=16 -0.17 % ±0.77% ±1.02% ±1.33%
http/bench-parser-fragmented.js n=100000 frags=4 len=8 -0.57 % ±0.64% ±0.85% ±1.11%
http/bench-parser-fragmented.js n=100000 frags=8 len=16 -0.07 % ±0.84% ±1.12% ±1.45%
http/bench-parser-fragmented.js n=100000 frags=8 len=8 0.43 % ±0.78% ±1.04% ±1.35%
http/bench-parser.js n=100000 len=16 0.20 % ±0.93% ±1.24% ±1.61%
http/bench-parser.js n=100000 len=32 0.03 % ±0.68% ±0.90% ±1.17%
http/bench-parser.js n=100000 len=4 0.60 % ±1.08% ±1.43% ±1.86%
http/bench-parser.js n=100000 len=8 0.32 % ±1.11% ±1.47% ±1.92%
http/check_invalid_header_char.js n=1000000 input='' 1.25 % ±2.48% ±3.30% ±4.30%
http/check_invalid_header_char.js n=1000000 input='\t\t\t\t\t\t\t\t\t\tFoo bar baz' 0.39 % ±1.66% ±2.21% ±2.88%
http/check_invalid_header_char.js n=1000000 input='\x7F' * 4.92 % ±3.90% ±5.19% ±6.75%
http/check_invalid_header_char.js n=1000000 input='1' -0.41 % ±3.47% ±4.62% ±6.02%
http/check_invalid_header_char.js n=1000000 input='20091' -0.50 % ±3.85% ±5.12% ±6.66%
http/check_invalid_header_char.js n=1000000 input='close' 0.49 % ±3.34% ±4.44% ±5.78%
http/check_invalid_header_char.js n=1000000 input='en-US' -0.66 % ±3.59% ±4.77% ±6.21%
http/check_invalid_header_char.js n=1000000 input='foo\nbar' -1.88 % ±2.70% ±3.60% ±4.70%
http/check_invalid_header_char.js n=1000000 input='group_acmeair' 0.85 % ±1.82% ±2.42% ±3.16%
http/check_invalid_header_char.js n=1000000 input='gzip' -0.60 % ±3.29% ±4.37% ±5.70%
http/check_invalid_header_char.js n=1000000 input='keep-alive' -1.28 % ±2.16% ±2.88% ±3.75%
http/check_invalid_header_char.js n=1000000 input='LONG_AND_INVALID' 0.08 % ±1.13% ±1.51% ±1.97%
http/check_invalid_header_char.js n=1000000 input='private' 1.00 % ±2.68% ±3.57% ±4.65%
http/check_invalid_header_char.js n=1000000 input='SAMEORIGIN' 1.36 % ±2.81% ±3.74% ±4.88%
http/check_invalid_header_char.js n=1000000 input='Sat, 07 May 2016 16:54:48 GMT' 0.79 % ±1.41% ±1.87% ±2.44%
http/check_invalid_header_char.js n=1000000 input='text/html; charset=utf-8' -0.12 % ±1.41% ±1.88% ±2.45%
http/check_invalid_header_char.js n=1000000 input='text/plain' -1.49 % ±2.96% ±3.95% ±5.14%
http/check_invalid_header_char.js n=1000000 input='中文呢' 1.95 % ±2.71% ±3.61% ±4.69%
http/check_is_http_token.js n=1000000 key=':' -0.22 % ±2.22% ±2.96% ±3.85%
http/check_is_http_token.js n=1000000 key=':alternate-protocol' 2.82 % ±4.07% ±5.42% ±7.06%
http/check_is_http_token.js n=1000000 key='((((())))' -1.22 % ±2.75% ±3.71% ±4.91%
http/check_is_http_token.js n=1000000 key='@@' 0.52 % ±2.14% ±2.85% ±3.71%
http/check_is_http_token.js n=1000000 key='Accept-Ranges' 0.51 % ±2.25% ±2.99% ±3.90%
http/check_is_http_token.js n=1000000 key='alt-svc' -0.09 % ±2.23% ±2.97% ±3.87%
http/check_is_http_token.js n=1000000 key='alternate-protocol:' -0.94 % ±2.08% ±2.77% ±3.61%
http/check_is_http_token.js n=1000000 key='alternate-protocol' -1.19 % ±2.32% ±3.09% ±4.03%
http/check_is_http_token.js n=1000000 key='Cache-Control' -0.96 % ±2.14% ±2.85% ±3.71%
http/check_is_http_token.js n=1000000 key='Connection' 0.78 % ±2.39% ±3.19% ±4.15%
http/check_is_http_token.js n=1000000 key='Content-Encoding' * -2.76 % ±2.26% ±3.01% ±3.92%
http/check_is_http_token.js n=1000000 key='content-length' 0.93 % ±2.27% ±3.02% ±3.92%
http/check_is_http_token.js n=1000000 key='Content-Location' -0.15 % ±2.52% ±3.35% ±4.36%
http/check_is_http_token.js n=1000000 key='content-type' -0.49 % ±2.55% ±3.39% ±4.41%
http/check_is_http_token.js n=1000000 key='Content-Type' 0.46 % ±2.58% ±3.43% ±4.47%
http/check_is_http_token.js n=1000000 key='date' 0.62 % ±2.42% ±3.22% ±4.19%
http/check_is_http_token.js n=1000000 key='ETag' -2.60 % ±3.97% ±5.32% ±7.01%
http/check_is_http_token.js n=1000000 key='Expires' ** 3.69 % ±2.64% ±3.52% ±4.59%
http/check_is_http_token.js n=1000000 key='Keep-Alive' -0.03 % ±2.59% ±3.45% ±4.48%
http/check_is_http_token.js n=1000000 key='Last-Modified' -0.99 % ±2.34% ±3.12% ±4.07%
http/check_is_http_token.js n=1000000 key='location' 0.79 % ±2.44% ±3.25% ±4.23%
http/check_is_http_token.js n=1000000 key='server' 0.37 % ±2.46% ±3.27% ±4.25%
http/check_is_http_token.js n=1000000 key='Server' * 3.70 % ±3.00% ±4.00% ±5.23%
http/check_is_http_token.js n=1000000 key='status' ** -4.32 % ±3.09% ±4.13% ±5.40%
http/check_is_http_token.js n=1000000 key='TCN' -0.86 % ±1.00% ±1.33% ±1.73%
http/check_is_http_token.js n=1000000 key='Transfer-Encoding' -1.00 % ±2.32% ±3.09% ±4.02%
http/check_is_http_token.js n=1000000 key='Vary' -0.56 % ±1.47% ±1.95% ±2.54%
http/check_is_http_token.js n=1000000 key='version' 1.90 % ±2.74% ±3.65% ±4.75%
http/check_is_http_token.js n=1000000 key='x-frame-options' 0.57 % ±2.05% ±2.73% ±3.55%
http/check_is_http_token.js n=1000000 key='x-xss-protection' -1.39 % ±2.29% ±3.06% ±3.99%
http/check_is_http_token.js n=1000000 key='中文呢' -1.00 % ±4.47% ±6.01% ±7.92%
http/chunked.js duration=5 c=100 len=1 n=1 benchmarker='wrk' -0.19 % ±0.68% ±0.91% ±1.18%
http/chunked.js duration=5 c=100 len=1 n=16 benchmarker='wrk' 0.41 % ±0.78% ±1.03% ±1.35%
http/chunked.js duration=5 c=100 len=1 n=4 benchmarker='wrk' 0.61 % ±2.08% ±2.76% ±3.60%
http/chunked.js duration=5 c=100 len=1 n=8 benchmarker='wrk' 0.13 % ±0.81% ±1.07% ±1.40%
http/chunked.js duration=5 c=100 len=256 n=1 benchmarker='wrk' -0.10 % ±0.70% ±0.93% ±1.21%
http/chunked.js duration=5 c=100 len=256 n=16 benchmarker='wrk' -0.70 % ±0.73% ±0.97% ±1.26%
http/chunked.js duration=5 c=100 len=256 n=4 benchmarker='wrk' -0.58 % ±1.84% ±2.45% ±3.18%
http/chunked.js duration=5 c=100 len=256 n=8 benchmarker='wrk' 0.11 % ±0.87% ±1.16% ±1.51%
http/chunked.js duration=5 c=100 len=64 n=1 benchmarker='wrk' -0.26 % ±0.60% ±0.80% ±1.04%
http/chunked.js duration=5 c=100 len=64 n=16 benchmarker='wrk' 0.56 % ±0.63% ±0.84% ±1.10%
http/chunked.js duration=5 c=100 len=64 n=4 benchmarker='wrk' 0.08 % ±1.81% ±2.41% ±3.15%
http/chunked.js duration=5 c=100 len=64 n=8 benchmarker='wrk' 0.26 % ±0.75% ±1.00% ±1.30%
http/client-request-body.js method='end' len=1024 type='asc' dur=5 -0.06 % ±0.69% ±0.92% ±1.20%
http/client-request-body.js method='end' len=1024 type='buf' dur=5 0.01 % ±0.76% ±1.02% ±1.32%
http/client-request-body.js method='end' len=1024 type='utf' dur=5 -0.28 % ±0.59% ±0.79% ±1.03%
http/client-request-body.js method='end' len=256 type='asc' dur=5 -0.49 % ±0.67% ±0.90% ±1.17%
http/client-request-body.js method='end' len=256 type='buf' dur=5 * -0.75 % ±0.68% ±0.90% ±1.18%
http/client-request-body.js method='end' len=256 type='utf' dur=5 0.03 % ±0.62% ±0.83% ±1.08%
http/client-request-body.js method='end' len=32 type='asc' dur=5 -0.01 % ±0.56% ±0.75% ±0.98%
http/client-request-body.js method='end' len=32 type='buf' dur=5 -0.37 % ±0.60% ±0.79% ±1.03%
http/client-request-body.js method='end' len=32 type='utf' dur=5 -0.16 % ±0.62% ±0.83% ±1.08%
http/client-request-body.js method='write' len=1024 type='asc' dur=5 -0.16 % ±0.78% ±1.03% ±1.34%
http/client-request-body.js method='write' len=1024 type='buf' dur=5 -0.34 % ±0.68% ±0.90% ±1.17%
http/client-request-body.js method='write' len=1024 type='utf' dur=5 0.06 % ±0.78% ±1.04% ±1.35%
http/client-request-body.js method='write' len=256 type='asc' dur=5 0.27 % ±0.70% ±0.93% ±1.21%
http/client-request-body.js method='write' len=256 type='buf' dur=5 0.09 % ±0.76% ±1.02% ±1.32%
http/client-request-body.js method='write' len=256 type='utf' dur=5 0.49 % ±0.59% ±0.79% ±1.03%
http/client-request-body.js method='write' len=32 type='asc' dur=5 -0.40 % ±0.64% ±0.86% ±1.11%
http/client-request-body.js method='write' len=32 type='buf' dur=5 -0.21 % ±0.65% ±0.86% ±1.12%
http/client-request-body.js method='write' len=32 type='utf' dur=5 0.02 % ±0.60% ±0.79% ±1.03%
http/cluster.js duration=5 c=50 len=1024 type='buffer' benchmarker='wrk' 0.13 % ±0.46% ±0.62% ±0.81%
http/cluster.js duration=5 c=50 len=1024 type='bytes' benchmarker='wrk' -0.11 % ±0.38% ±0.50% ±0.66%
http/cluster.js duration=5 c=50 len=102400 type='buffer' benchmarker='wrk' -0.24 % ±0.49% ±0.65% ±0.85%
http/cluster.js duration=5 c=50 len=102400 type='bytes' benchmarker='wrk' 0.14 % ±0.80% ±1.06% ±1.38%
http/cluster.js duration=5 c=50 len=4 type='buffer' benchmarker='wrk' -0.23 % ±0.29% ±0.39% ±0.51%
http/cluster.js duration=5 c=50 len=4 type='bytes' benchmarker='wrk' 0.00 % ±0.51% ±0.67% ±0.88%
http/cluster.js duration=5 c=500 len=1024 type='buffer' benchmarker='wrk' ** -0.77 % ±0.50% ±0.67% ±0.87%
http/cluster.js duration=5 c=500 len=1024 type='bytes' benchmarker='wrk' -0.18 % ±0.65% ±0.86% ±1.12%
http/cluster.js duration=5 c=500 len=102400 type='buffer' benchmarker='wrk' -0.18 % ±0.59% ±0.78% ±1.02%
http/cluster.js duration=5 c=500 len=102400 type='bytes' benchmarker='wrk' 0.28 % ±0.72% ±0.95% ±1.24%
http/cluster.js duration=5 c=500 len=4 type='buffer' benchmarker='wrk' -0.25 % ±0.47% ±0.62% ±0.81%
http/cluster.js duration=5 c=500 len=4 type='bytes' benchmarker='wrk' -0.36 % ±0.52% ±0.70% ±0.91%
http/create-clientrequest.js e=1 arg='options' url='idn' 2.09 % ±7.80% ±10.38% ±13.50%
http/create-clientrequest.js e=1 arg='options' url='long' -9.98 % ±14.10% ±18.77% ±24.46%
http/create-clientrequest.js e=1 arg='options' url='wpt' -4.69 % ±6.75% ±8.98% ±11.70%
http/create-clientrequest.js e=1 arg='string' url='idn' -4.15 % ±10.23% ±13.61% ±17.71%
http/create-clientrequest.js e=1 arg='string' url='long' -0.93 % ±12.77% ±16.99% ±22.12%
http/create-clientrequest.js e=1 arg='string' url='wpt' 0.60 % ±11.36% ±15.12% ±19.68%
http/create-clientrequest.js e=1 arg='URL' url='idn' 0.87 % ±9.17% ±12.20% ±15.88%
http/create-clientrequest.js e=1 arg='URL' url='long' -5.01 % ±10.02% ±13.35% ±17.41%
http/create-clientrequest.js e=1 arg='URL' url='wpt' 1.99 % ±8.00% ±10.64% ±13.85%
http/end-string.js duration=5 c=50 len=1024 benchmarker='wrk' *** 10.48 % ±0.81% ±1.08% ±1.41%
http/end-string.js duration=5 c=50 len=102400 benchmarker='wrk' *** 2.47 % ±0.50% ±0.66% ±0.86%
http/end-string.js duration=5 c=50 len=16384 benchmarker='wrk' *** 5.59 % ±0.89% ±1.19% ±1.55%
http/end-string.js duration=5 c=50 len=4 benchmarker='wrk' *** 9.92 % ±0.82% ±1.10% ±1.43%
http/end-string.js duration=5 c=50 len=64 benchmarker='wrk' *** 8.43 % ±0.71% ±0.94% ±1.23%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='asc' benchmarker='wrk' *** 2.48 % ±0.47% ±0.62% ±0.81%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='buf' benchmarker='wrk' -0.12 % ±0.43% ±0.57% ±0.74%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='utf' benchmarker='wrk' *** 0.68 % ±0.38% ±0.51% ±0.66%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='asc' benchmarker='wrk' ** 1.19 % ±0.81% ±1.09% ±1.43%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='buf' benchmarker='wrk' *** 1.50 % ±0.59% ±0.78% ±1.01%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='utf' benchmarker='wrk' *** 2.25 % ±0.45% ±0.59% ±0.77%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='asc' benchmarker='wrk' *** 1.18 % ±0.42% ±0.56% ±0.73%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='buf' benchmarker='wrk' *** 0.92 % ±0.48% ±0.63% ±0.83%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='utf' benchmarker='wrk' *** 1.25 % ±0.32% ±0.43% ±0.56%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='asc' benchmarker='wrk' *** 1.60 % ±0.83% ±1.10% ±1.44%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='buf' benchmarker='wrk' *** 2.34 % ±0.88% ±1.18% ±1.53%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='utf' benchmarker='wrk' *** 2.95 % ±0.48% ±0.64% ±0.83%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='asc' benchmarker='wrk' -0.33 % ±0.57% ±0.77% ±1.00%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='buf' benchmarker='wrk' -0.16 % ±0.52% ±0.69% ±0.90%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='utf' benchmarker='wrk' -0.12 % ±0.36% ±0.47% ±0.62%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='asc' benchmarker='wrk' 0.07 % ±0.76% ±1.01% ±1.32%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='buf' benchmarker='wrk' -0.25 % ±0.51% ±0.68% ±0.89%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='utf' benchmarker='wrk' 0.53 % ±1.00% ±1.34% ±1.74%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='asc' benchmarker='wrk' -0.26 % ±0.61% ±0.81% ±1.06%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='buf' benchmarker='wrk' -0.05 % ±0.47% ±0.62% ±0.81%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='utf' benchmarker='wrk' -0.08 % ±0.56% ±0.74% ±0.96%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='asc' benchmarker='wrk' -0.50 % ±0.96% ±1.28% ±1.66%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='buf' benchmarker='wrk' -0.22 % ±0.71% ±0.94% ±1.23%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='utf' benchmarker='wrk' 0.10 % ±0.58% ±0.77% ±1.01%
http/headers.js group='fewHeaders' duration=5 len=1 n=10 benchmarker='wrk' -0.23 % ±0.65% ±0.86% ±1.13%
http/headers.js group='fewHeaders' duration=5 len=5 n=10 benchmarker='wrk' 0.25 % ±0.59% ±0.79% ±1.03%
http/headers.js group='manyHeaders' duration=5 len=1 n=600 benchmarker='wrk' -0.11 % ±0.86% ±1.15% ±1.49%
http/headers.js group='manyHeaders' duration=5 len=100 n=600 benchmarker='wrk' 0.22 % ±1.12% ±1.49% ±1.94%
http/headers.js group='mediumHeaders' duration=5 len=1 n=50 benchmarker='wrk' -0.28 % ±0.51% ±0.67% ±0.88%
http/headers.js group='mediumHeaders' duration=5 len=10 n=50 benchmarker='wrk' 0.04 % ±0.53% ±0.71% ±0.93%
http/http_server_for_chunky_client.js type='send' n=2000 len=1 0.19 % ±0.57% ±0.77% ±1.00%
http/http_server_for_chunky_client.js type='send' n=2000 len=128 -0.12 % ±0.59% ±0.78% ±1.02%
http/http_server_for_chunky_client.js type='send' n=2000 len=16 -0.01 % ±0.60% ±0.79% ±1.03%
http/http_server_for_chunky_client.js type='send' n=2000 len=32 0.15 % ±0.61% ±0.81% ±1.06%
http/http_server_for_chunky_client.js type='send' n=2000 len=4 0.67 % ±0.69% ±0.92% ±1.21%
http/http_server_for_chunky_client.js type='send' n=2000 len=64 -0.30 % ±0.48% ±0.64% ±0.83%
http/http_server_for_chunky_client.js type='send' n=2000 len=8 -0.50 % ±0.55% ±0.73% ±0.95%
http/http_server_for_chunky_client.js type='send' n=5 len=1 -1.39 % ±2.60% ±3.47% ±4.51%
http/http_server_for_chunky_client.js type='send' n=5 len=128 -4.15 % ±13.02% ±17.32% ±22.54%
http/http_server_for_chunky_client.js type='send' n=5 len=16 7.54 % ±10.05% ±13.50% ±17.81%
http/http_server_for_chunky_client.js type='send' n=5 len=32 0.87 % ±11.95% ±15.91% ±20.71%
http/http_server_for_chunky_client.js type='send' n=5 len=4 1.73 % ±10.57% ±14.06% ±18.30%
http/http_server_for_chunky_client.js type='send' n=5 len=64 -5.12 % ±14.17% ±18.86% ±24.56%
http/http_server_for_chunky_client.js type='send' n=5 len=8 -2.55 % ±5.92% ±7.90% ±10.32%
http/http_server_for_chunky_client.js type='send' n=50 len=1 1.27 % ±2.86% ±3.81% ±4.96%
http/http_server_for_chunky_client.js type='send' n=50 len=128 * 5.17 % ±4.13% ±5.49% ±7.15%
http/http_server_for_chunky_client.js type='send' n=50 len=16 -0.71 % ±2.69% ±3.58% ±4.67%
http/http_server_for_chunky_client.js type='send' n=50 len=32 -0.12 % ±2.72% ±3.63% ±4.74%
http/http_server_for_chunky_client.js type='send' n=50 len=4 -1.47 % ±3.06% ±4.07% ±5.29%
http/http_server_for_chunky_client.js type='send' n=50 len=64 2.04 % ±3.51% ±4.67% ±6.09%
http/http_server_for_chunky_client.js type='send' n=50 len=8 -0.08 % ±2.21% ±2.94% ±3.84%
http/http_server_for_chunky_client.js type='send' n=500 len=1 -0.08 % ±0.80% ±1.07% ±1.40%
http/http_server_for_chunky_client.js type='send' n=500 len=128 -0.38 % ±0.70% ±0.93% ±1.21%
http/http_server_for_chunky_client.js type='send' n=500 len=16 * -0.94 % ±0.83% ±1.11% ±1.45%
http/http_server_for_chunky_client.js type='send' n=500 len=32 -0.43 % ±0.83% ±1.11% ±1.45%
http/http_server_for_chunky_client.js type='send' n=500 len=4 -0.02 % ±0.71% ±0.95% ±1.24%
http/http_server_for_chunky_client.js type='send' n=500 len=64 -0.19 % ±0.93% ±1.24% ±1.62%
http/http_server_for_chunky_client.js type='send' n=500 len=8 -0.15 % ±0.71% ±0.95% ±1.23%
http/incoming_headers.js duration=5 w=0 headers=20 connections=50 benchmarker='wrk' 0.04 % ±0.81% ±1.08% ±1.42%
http/incoming_headers.js duration=5 w=6 headers=20 connections=50 benchmarker='wrk' 0.04 % ±0.64% ±0.85% ±1.11%
http/set_header.js n=1000000 value='Connection' ** -2.20 % ±1.65% ±2.19% ±2.85%
http/set_header.js n=1000000 value='Content-Length' 0.29 % ±1.71% ±2.28% ±2.97%
http/set_header.js n=1000000 value='Content-Type' 1.33 % ±1.88% ±2.51% ±3.27%
http/set_header.js n=1000000 value='Set-Cookie' 1.14 % ±1.33% ±1.77% ±2.30%
http/set_header.js n=1000000 value='Transfer-Encoding' 1.06 % ±1.33% ±1.76% ±2.30%
http/set_header.js n=1000000 value='Vary' -0.57 % ±1.72% ±2.29% ±2.99%
http/set_header.js n=1000000 value='X-Powered-By' * 1.49 % ±1.33% ±1.77% ±2.30%
http/set-header.js duration=5 res='normal' benchmarker='wrk' *** 9.74 % ±0.78% ±1.04% ±1.35%
http/set-header.js duration=5 res='setHeader' benchmarker='wrk' *** 9.87 % ±0.83% ±1.10% ±1.44%
http/set-header.js duration=5 res='setHeaderWH' benchmarker='wrk' *** 9.59 % ±0.92% ±1.22% ±1.59%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=1024 type='buffer' benchmarker='wrk' *** 2.60 % ±0.75% ±1.00% ±1.30%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=1024 type='bytes' benchmarker='wrk' *** 9.54 % ±0.74% ±0.99% ±1.28%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=102400 type='buffer' benchmarker='wrk' ** 1.23 % ±0.75% ±0.99% ±1.29%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=102400 type='bytes' benchmarker='wrk' *** 1.98 % ±0.49% ±0.65% ±0.84%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=4 type='buffer' benchmarker='wrk' *** 2.43 % ±0.76% ±1.01% ±1.31%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=4 type='bytes' benchmarker='wrk' *** 9.55 % ±0.71% ±0.95% ±1.24%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=1024 type='buffer' benchmarker='wrk' *** 3.14 % ±0.86% ±1.15% ±1.50%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=1024 type='bytes' benchmarker='wrk' *** 2.94 % ±0.78% ±1.04% ±1.35%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=102400 type='buffer' benchmarker='wrk' *** 1.55 % ±0.62% ±0.82% ±1.07%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=102400 type='bytes' benchmarker='wrk' ** 1.10 % ±0.82% ±1.09% ±1.42%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=4 type='buffer' benchmarker='wrk' *** 3.91 % ±0.83% ±1.10% ±1.44%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=4 type='bytes' benchmarker='wrk' *** 3.47 % ±0.93% ±1.23% ±1.60%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=1024 type='buffer' benchmarker='wrk' *** 3.60 % ±0.96% ±1.27% ±1.66%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=1024 type='bytes' benchmarker='wrk' *** 9.20 % ±0.99% ±1.32% ±1.72%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=102400 type='buffer' benchmarker='wrk' *** 1.28 % ±0.53% ±0.71% ±0.93%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=102400 type='bytes' benchmarker='wrk' *** 1.28 % ±0.65% ±0.87% ±1.13%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=4 type='buffer' benchmarker='wrk' *** 3.59 % ±0.96% ±1.28% ±1.67%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=4 type='bytes' benchmarker='wrk' *** 9.93 % ±1.01% ±1.35% ±1.76%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=1024 type='buffer' benchmarker='wrk' *** 2.04 % ±0.98% ±1.31% ±1.70%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=1024 type='bytes' benchmarker='wrk' *** 2.14 % ±0.82% ±1.08% ±1.41%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=102400 type='buffer' benchmarker='wrk' *** 1.74 % ±0.67% ±0.89% ±1.16%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=102400 type='bytes' benchmarker='wrk' ** 1.10 % ±0.79% ±1.05% ±1.36%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=4 type='buffer' benchmarker='wrk' *** 3.20 % ±0.94% ±1.24% ±1.62%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=4 type='bytes' benchmarker='wrk' *** 3.12 % ±0.76% ±1.01% ±1.32%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=1024 type='buffer' benchmarker='wrk' -0.19 % ±0.80% ±1.06% ±1.38%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=1024 type='bytes' benchmarker='wrk' -0.44 % ±0.95% ±1.26% ±1.65%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=102400 type='buffer' benchmarker='wrk' 0.11 % ±0.61% ±0.81% ±1.06%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=102400 type='bytes' benchmarker='wrk' * -1.19 % ±1.11% ±1.47% ±1.92%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=4 type='buffer' benchmarker='wrk' -0.23 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=4 type='bytes' benchmarker='wrk' 0.10 % ±0.75% ±1.00% ±1.30%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=1024 type='buffer' benchmarker='wrk' -0.55 % ±0.76% ±1.01% ±1.32%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=1024 type='bytes' benchmarker='wrk' 0.19 % ±0.95% ±1.27% ±1.65%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=102400 type='buffer' benchmarker='wrk' ** -1.32 % ±0.79% ±1.06% ±1.37%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=102400 type='bytes' benchmarker='wrk' 0.69 % ±1.07% ±1.42% ±1.85%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=4 type='buffer' benchmarker='wrk' 0.54 % ±0.81% ±1.07% ±1.40%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=4 type='bytes' benchmarker='wrk' 0.56 % ±0.71% ±0.95% ±1.23%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=1024 type='buffer' benchmarker='wrk' -0.48 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=1024 type='bytes' benchmarker='wrk' -0.62 % ±0.85% ±1.13% ±1.48%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=102400 type='buffer' benchmarker='wrk' -0.20 % ±0.69% ±0.92% ±1.20%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=102400 type='bytes' benchmarker='wrk' 0.43 % ±1.18% ±1.56% ±2.04%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=4 type='buffer' benchmarker='wrk' 0.29 % ±0.89% ±1.19% ±1.55%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=4 type='bytes' benchmarker='wrk' * -1.01 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=1024 type='buffer' benchmarker='wrk' -0.18 % ±0.68% ±0.90% ±1.18%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=1024 type='bytes' benchmarker='wrk' 0.09 % ±0.65% ±0.86% ±1.12%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=102400 type='buffer' benchmarker='wrk' * -0.55 % ±0.49% ±0.66% ±0.86%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=102400 type='bytes' benchmarker='wrk' 0.10 % ±0.82% ±1.09% ±1.42%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=4 type='buffer' benchmarker='wrk' 0.35 % ±0.74% ±0.98% ±1.28%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=4 type='bytes' benchmarker='wrk' -0.26 % ±0.65% ±0.86% ±1.12%
http/upgrade.js n=1000 0.73 % ±2.37% ±3.16% ±4.11%
http/upgrade.js n=5 6.72 % ±8.30% ±11.05% ±14.38%

Be aware that when doing many comparisons the risk of a false-positive result increases.
In this case, there are 235 comparisons, you can thus expect the following amount of false-positive results:
11.75 false positives, when considering a 5% risk acceptance (*, **, *),
2.35 false positives, when considering a 1% risk acceptance (
, ),
0.24 false positives, when considering a 0.1% risk acceptance (
)

Looks good I think. Headlines:

  • No notable regressions - each of the small negative cases I can see are low-confidence and fit into an overall pattern of no change considering the tests around them
  • A very consistent 9.59% - 9.87% speed up in http/set-header.js test, which tests headers + res.end(body).
  • For http/simple:
    • Consistent boost around 9.5% with type=bytes, no chunking, and len up to 1024.
    • 3% boost with type=buffer, on the same small non-chunked responses.
    • Both buffer & byte body perf dropping to about 1-2% improvement for larger bodies (1MB).
    • No significant change with chunked encoding.
  • 10.48% boost to http/end-string test with 1KB, dropping to 5.59% with 16KB, down to 2.47% improvement with 1MB.
  • ~2% boost across various http/end-vs-write-end.js cases that call end(data) on different large sizes.

Looks pretty convincing to me! All approved and ready-to-go now and I think this is all just good news, so I'll commit-queue.

@pimterrypimterry added the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 24, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 214cf06 into nodejs:mainAug 24, 2026
85 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 214cf06

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 24, 2026
@pimterry
pimterry deleted the h1-clean-end-perf branch August 25, 2026 15:12
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
aduh95 pushed a commit that referenced this pull request Aug 27, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

httpIssues and PRs related to the http subsystem.needs-benchmark-ciPRs that need a benchmark CI run.needs-ciPRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants

@pimterry@nodejs-github-bot@mcollina@lpinca@anonrig@efekrskl@mertcanaltin@gurgunday@bjohansebas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

http: improve performance for end() with known-length string - #65466

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
pimterry:h1-clean-end-perf
Aug 24, 2026
Merged

http: improve performance for end() with known-length string#65466
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
pimterry:h1-clean-end-perf

Conversation

@pimterry

Copy link
Copy Markdown
Member

When you call end(data) on an outgoing HTTP request, we previously wrote the data, and then ran _send('', ...) just to trigger flushing the headers, which resulted in an extra zero-byte write call and bonus nextTick before 'finish'.

When the length is known and content-length is used (not chunking, so we don't need a terminator) we can skip this completely: prep the content-length header explicitly, and combine the finish into the existing write step.

This drops a nextTick, and goes from 2 write calls to 1 for the very common case of response.end(data) with a string, and for buffer data goes from 3 writes to 2.

In practice, in the tiny benchmark here which I think represents a very common use case (small API responses) I see this boosting HTTP RPS by up to 9% for writes up to 1KB or so. For larger responses the response write time starts to outweigh this, but I still see 3% RPS boost at 16KB. Needs autocannon to hit the rates required, you can test yourself with:

node benchmark/compare.js --old ./node-main --new ./node-pr --runs 20 --set benchmarker=autocannon --filter end-string http

Added a new test confirming the specific details and edge cases this touches, and updated one existing test which specifically asserted that end(data) triggered two writes, including the empty one.

This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/http
  • @nodejs/net
  • @nodejs/performance

@nodejs-github-botnodejs-github-bot added http Issues and PRs related to the http subsystem. needs-ci PRs that need a full CI run. labels Aug 21, 2026

@mcollinamcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@mcollina
mcollina requested a review from anonrigAugust 21, 2026 19:24
@codecov

codecovBot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.13%. Comparing base (15940ef) to head (659d6b9).
⚠️ Report is 61 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #65466 +/- ##
==========================================
- Coverage 90.14% 90.13% -0.01% 
==========================================
Files 751 751 Lines 252298 252333 +35 Branches 47446 47449 +3 ==========================================
+ Hits 227436 227451 +15 - Misses 16175 16186 +11 - Partials 8687 8696 +9 
Files with missing linesCoverage Δ
lib/_http_outgoing.js97.76% <100.00%> (-0.02%)⬇️

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

@pimterrypimterry added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 21, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 22, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@bjohansebasbjohansebas added the needs-benchmark-ci PRs that need a benchmark CI run. label Aug 22, 2026
@pimterry

Copy link
Copy Markdown
MemberAuthor

@bjohansebas benchmark label was a good suggestion. I've done a run here.

Unfortunately it seems like the microbenchmark job is broken generally (cc @nodejs/build) and all recent jobs have failed with:

++ Rscript benchmark/compare.R
Error: package or namespace load failed for ‘ggplot2’ in dyn.load(file, DLLpath = DLLpath, ...):
unable to load shared object '/usr/local/lib/R/site-library/rlang/libs/rlang.so':
/usr/local/lib/R/site-library/rlang/libs/rlang.so: undefined symbol: SETLENGTH
Execution halted

I've manually extracted the CSV from the console output to get some numbers though, and run node-benchmark-compare on the result, which gives:

Details
 confidence improvement accuracy (*) (**) (***)
http/bench-parser-fragmented.js n=100000 frags=2 len=16 -0.20 % ±1.06% ±1.42% ±1.85%
http/bench-parser-fragmented.js n=100000 frags=2 len=8 -0.01 % ±0.94% ±1.25% ±1.63%
http/bench-parser-fragmented.js n=100000 frags=4 len=16 -0.17 % ±0.77% ±1.02% ±1.33%
http/bench-parser-fragmented.js n=100000 frags=4 len=8 -0.57 % ±0.64% ±0.85% ±1.11%
http/bench-parser-fragmented.js n=100000 frags=8 len=16 -0.07 % ±0.84% ±1.12% ±1.45%
http/bench-parser-fragmented.js n=100000 frags=8 len=8 0.43 % ±0.78% ±1.04% ±1.35%
http/bench-parser.js n=100000 len=16 0.20 % ±0.93% ±1.24% ±1.61%
http/bench-parser.js n=100000 len=32 0.03 % ±0.68% ±0.90% ±1.17%
http/bench-parser.js n=100000 len=4 0.60 % ±1.08% ±1.43% ±1.86%
http/bench-parser.js n=100000 len=8 0.32 % ±1.11% ±1.47% ±1.92%
http/check_invalid_header_char.js n=1000000 input='' 1.25 % ±2.48% ±3.30% ±4.30%
http/check_invalid_header_char.js n=1000000 input='\t\t\t\t\t\t\t\t\t\tFoo bar baz' 0.39 % ±1.66% ±2.21% ±2.88%
http/check_invalid_header_char.js n=1000000 input='\x7F' * 4.92 % ±3.90% ±5.19% ±6.75%
http/check_invalid_header_char.js n=1000000 input='1' -0.41 % ±3.47% ±4.62% ±6.02%
http/check_invalid_header_char.js n=1000000 input='20091' -0.50 % ±3.85% ±5.12% ±6.66%
http/check_invalid_header_char.js n=1000000 input='close' 0.49 % ±3.34% ±4.44% ±5.78%
http/check_invalid_header_char.js n=1000000 input='en-US' -0.66 % ±3.59% ±4.77% ±6.21%
http/check_invalid_header_char.js n=1000000 input='foo\nbar' -1.88 % ±2.70% ±3.60% ±4.70%
http/check_invalid_header_char.js n=1000000 input='group_acmeair' 0.85 % ±1.82% ±2.42% ±3.16%
http/check_invalid_header_char.js n=1000000 input='gzip' -0.60 % ±3.29% ±4.37% ±5.70%
http/check_invalid_header_char.js n=1000000 input='keep-alive' -1.28 % ±2.16% ±2.88% ±3.75%
http/check_invalid_header_char.js n=1000000 input='LONG_AND_INVALID' 0.08 % ±1.13% ±1.51% ±1.97%
http/check_invalid_header_char.js n=1000000 input='private' 1.00 % ±2.68% ±3.57% ±4.65%
http/check_invalid_header_char.js n=1000000 input='SAMEORIGIN' 1.36 % ±2.81% ±3.74% ±4.88%
http/check_invalid_header_char.js n=1000000 input='Sat, 07 May 2016 16:54:48 GMT' 0.79 % ±1.41% ±1.87% ±2.44%
http/check_invalid_header_char.js n=1000000 input='text/html; charset=utf-8' -0.12 % ±1.41% ±1.88% ±2.45%
http/check_invalid_header_char.js n=1000000 input='text/plain' -1.49 % ±2.96% ±3.95% ±5.14%
http/check_invalid_header_char.js n=1000000 input='中文呢' 1.95 % ±2.71% ±3.61% ±4.69%
http/check_is_http_token.js n=1000000 key=':' -0.22 % ±2.22% ±2.96% ±3.85%
http/check_is_http_token.js n=1000000 key=':alternate-protocol' 2.82 % ±4.07% ±5.42% ±7.06%
http/check_is_http_token.js n=1000000 key='((((())))' -1.22 % ±2.75% ±3.71% ±4.91%
http/check_is_http_token.js n=1000000 key='@@' 0.52 % ±2.14% ±2.85% ±3.71%
http/check_is_http_token.js n=1000000 key='Accept-Ranges' 0.51 % ±2.25% ±2.99% ±3.90%
http/check_is_http_token.js n=1000000 key='alt-svc' -0.09 % ±2.23% ±2.97% ±3.87%
http/check_is_http_token.js n=1000000 key='alternate-protocol:' -0.94 % ±2.08% ±2.77% ±3.61%
http/check_is_http_token.js n=1000000 key='alternate-protocol' -1.19 % ±2.32% ±3.09% ±4.03%
http/check_is_http_token.js n=1000000 key='Cache-Control' -0.96 % ±2.14% ±2.85% ±3.71%
http/check_is_http_token.js n=1000000 key='Connection' 0.78 % ±2.39% ±3.19% ±4.15%
http/check_is_http_token.js n=1000000 key='Content-Encoding' * -2.76 % ±2.26% ±3.01% ±3.92%
http/check_is_http_token.js n=1000000 key='content-length' 0.93 % ±2.27% ±3.02% ±3.92%
http/check_is_http_token.js n=1000000 key='Content-Location' -0.15 % ±2.52% ±3.35% ±4.36%
http/check_is_http_token.js n=1000000 key='content-type' -0.49 % ±2.55% ±3.39% ±4.41%
http/check_is_http_token.js n=1000000 key='Content-Type' 0.46 % ±2.58% ±3.43% ±4.47%
http/check_is_http_token.js n=1000000 key='date' 0.62 % ±2.42% ±3.22% ±4.19%
http/check_is_http_token.js n=1000000 key='ETag' -2.60 % ±3.97% ±5.32% ±7.01%
http/check_is_http_token.js n=1000000 key='Expires' ** 3.69 % ±2.64% ±3.52% ±4.59%
http/check_is_http_token.js n=1000000 key='Keep-Alive' -0.03 % ±2.59% ±3.45% ±4.48%
http/check_is_http_token.js n=1000000 key='Last-Modified' -0.99 % ±2.34% ±3.12% ±4.07%
http/check_is_http_token.js n=1000000 key='location' 0.79 % ±2.44% ±3.25% ±4.23%
http/check_is_http_token.js n=1000000 key='server' 0.37 % ±2.46% ±3.27% ±4.25%
http/check_is_http_token.js n=1000000 key='Server' * 3.70 % ±3.00% ±4.00% ±5.23%
http/check_is_http_token.js n=1000000 key='status' ** -4.32 % ±3.09% ±4.13% ±5.40%
http/check_is_http_token.js n=1000000 key='TCN' -0.86 % ±1.00% ±1.33% ±1.73%
http/check_is_http_token.js n=1000000 key='Transfer-Encoding' -1.00 % ±2.32% ±3.09% ±4.02%
http/check_is_http_token.js n=1000000 key='Vary' -0.56 % ±1.47% ±1.95% ±2.54%
http/check_is_http_token.js n=1000000 key='version' 1.90 % ±2.74% ±3.65% ±4.75%
http/check_is_http_token.js n=1000000 key='x-frame-options' 0.57 % ±2.05% ±2.73% ±3.55%
http/check_is_http_token.js n=1000000 key='x-xss-protection' -1.39 % ±2.29% ±3.06% ±3.99%
http/check_is_http_token.js n=1000000 key='中文呢' -1.00 % ±4.47% ±6.01% ±7.92%
http/chunked.js duration=5 c=100 len=1 n=1 benchmarker='wrk' -0.19 % ±0.68% ±0.91% ±1.18%
http/chunked.js duration=5 c=100 len=1 n=16 benchmarker='wrk' 0.41 % ±0.78% ±1.03% ±1.35%
http/chunked.js duration=5 c=100 len=1 n=4 benchmarker='wrk' 0.61 % ±2.08% ±2.76% ±3.60%
http/chunked.js duration=5 c=100 len=1 n=8 benchmarker='wrk' 0.13 % ±0.81% ±1.07% ±1.40%
http/chunked.js duration=5 c=100 len=256 n=1 benchmarker='wrk' -0.10 % ±0.70% ±0.93% ±1.21%
http/chunked.js duration=5 c=100 len=256 n=16 benchmarker='wrk' -0.70 % ±0.73% ±0.97% ±1.26%
http/chunked.js duration=5 c=100 len=256 n=4 benchmarker='wrk' -0.58 % ±1.84% ±2.45% ±3.18%
http/chunked.js duration=5 c=100 len=256 n=8 benchmarker='wrk' 0.11 % ±0.87% ±1.16% ±1.51%
http/chunked.js duration=5 c=100 len=64 n=1 benchmarker='wrk' -0.26 % ±0.60% ±0.80% ±1.04%
http/chunked.js duration=5 c=100 len=64 n=16 benchmarker='wrk' 0.56 % ±0.63% ±0.84% ±1.10%
http/chunked.js duration=5 c=100 len=64 n=4 benchmarker='wrk' 0.08 % ±1.81% ±2.41% ±3.15%
http/chunked.js duration=5 c=100 len=64 n=8 benchmarker='wrk' 0.26 % ±0.75% ±1.00% ±1.30%
http/client-request-body.js method='end' len=1024 type='asc' dur=5 -0.06 % ±0.69% ±0.92% ±1.20%
http/client-request-body.js method='end' len=1024 type='buf' dur=5 0.01 % ±0.76% ±1.02% ±1.32%
http/client-request-body.js method='end' len=1024 type='utf' dur=5 -0.28 % ±0.59% ±0.79% ±1.03%
http/client-request-body.js method='end' len=256 type='asc' dur=5 -0.49 % ±0.67% ±0.90% ±1.17%
http/client-request-body.js method='end' len=256 type='buf' dur=5 * -0.75 % ±0.68% ±0.90% ±1.18%
http/client-request-body.js method='end' len=256 type='utf' dur=5 0.03 % ±0.62% ±0.83% ±1.08%
http/client-request-body.js method='end' len=32 type='asc' dur=5 -0.01 % ±0.56% ±0.75% ±0.98%
http/client-request-body.js method='end' len=32 type='buf' dur=5 -0.37 % ±0.60% ±0.79% ±1.03%
http/client-request-body.js method='end' len=32 type='utf' dur=5 -0.16 % ±0.62% ±0.83% ±1.08%
http/client-request-body.js method='write' len=1024 type='asc' dur=5 -0.16 % ±0.78% ±1.03% ±1.34%
http/client-request-body.js method='write' len=1024 type='buf' dur=5 -0.34 % ±0.68% ±0.90% ±1.17%
http/client-request-body.js method='write' len=1024 type='utf' dur=5 0.06 % ±0.78% ±1.04% ±1.35%
http/client-request-body.js method='write' len=256 type='asc' dur=5 0.27 % ±0.70% ±0.93% ±1.21%
http/client-request-body.js method='write' len=256 type='buf' dur=5 0.09 % ±0.76% ±1.02% ±1.32%
http/client-request-body.js method='write' len=256 type='utf' dur=5 0.49 % ±0.59% ±0.79% ±1.03%
http/client-request-body.js method='write' len=32 type='asc' dur=5 -0.40 % ±0.64% ±0.86% ±1.11%
http/client-request-body.js method='write' len=32 type='buf' dur=5 -0.21 % ±0.65% ±0.86% ±1.12%
http/client-request-body.js method='write' len=32 type='utf' dur=5 0.02 % ±0.60% ±0.79% ±1.03%
http/cluster.js duration=5 c=50 len=1024 type='buffer' benchmarker='wrk' 0.13 % ±0.46% ±0.62% ±0.81%
http/cluster.js duration=5 c=50 len=1024 type='bytes' benchmarker='wrk' -0.11 % ±0.38% ±0.50% ±0.66%
http/cluster.js duration=5 c=50 len=102400 type='buffer' benchmarker='wrk' -0.24 % ±0.49% ±0.65% ±0.85%
http/cluster.js duration=5 c=50 len=102400 type='bytes' benchmarker='wrk' 0.14 % ±0.80% ±1.06% ±1.38%
http/cluster.js duration=5 c=50 len=4 type='buffer' benchmarker='wrk' -0.23 % ±0.29% ±0.39% ±0.51%
http/cluster.js duration=5 c=50 len=4 type='bytes' benchmarker='wrk' 0.00 % ±0.51% ±0.67% ±0.88%
http/cluster.js duration=5 c=500 len=1024 type='buffer' benchmarker='wrk' ** -0.77 % ±0.50% ±0.67% ±0.87%
http/cluster.js duration=5 c=500 len=1024 type='bytes' benchmarker='wrk' -0.18 % ±0.65% ±0.86% ±1.12%
http/cluster.js duration=5 c=500 len=102400 type='buffer' benchmarker='wrk' -0.18 % ±0.59% ±0.78% ±1.02%
http/cluster.js duration=5 c=500 len=102400 type='bytes' benchmarker='wrk' 0.28 % ±0.72% ±0.95% ±1.24%
http/cluster.js duration=5 c=500 len=4 type='buffer' benchmarker='wrk' -0.25 % ±0.47% ±0.62% ±0.81%
http/cluster.js duration=5 c=500 len=4 type='bytes' benchmarker='wrk' -0.36 % ±0.52% ±0.70% ±0.91%
http/create-clientrequest.js e=1 arg='options' url='idn' 2.09 % ±7.80% ±10.38% ±13.50%
http/create-clientrequest.js e=1 arg='options' url='long' -9.98 % ±14.10% ±18.77% ±24.46%
http/create-clientrequest.js e=1 arg='options' url='wpt' -4.69 % ±6.75% ±8.98% ±11.70%
http/create-clientrequest.js e=1 arg='string' url='idn' -4.15 % ±10.23% ±13.61% ±17.71%
http/create-clientrequest.js e=1 arg='string' url='long' -0.93 % ±12.77% ±16.99% ±22.12%
http/create-clientrequest.js e=1 arg='string' url='wpt' 0.60 % ±11.36% ±15.12% ±19.68%
http/create-clientrequest.js e=1 arg='URL' url='idn' 0.87 % ±9.17% ±12.20% ±15.88%
http/create-clientrequest.js e=1 arg='URL' url='long' -5.01 % ±10.02% ±13.35% ±17.41%
http/create-clientrequest.js e=1 arg='URL' url='wpt' 1.99 % ±8.00% ±10.64% ±13.85%
http/end-string.js duration=5 c=50 len=1024 benchmarker='wrk' *** 10.48 % ±0.81% ±1.08% ±1.41%
http/end-string.js duration=5 c=50 len=102400 benchmarker='wrk' *** 2.47 % ±0.50% ±0.66% ±0.86%
http/end-string.js duration=5 c=50 len=16384 benchmarker='wrk' *** 5.59 % ±0.89% ±1.19% ±1.55%
http/end-string.js duration=5 c=50 len=4 benchmarker='wrk' *** 9.92 % ±0.82% ±1.10% ±1.43%
http/end-string.js duration=5 c=50 len=64 benchmarker='wrk' *** 8.43 % ±0.71% ±0.94% ±1.23%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='asc' benchmarker='wrk' *** 2.48 % ±0.47% ±0.62% ±0.81%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='buf' benchmarker='wrk' -0.12 % ±0.43% ±0.57% ±0.74%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='utf' benchmarker='wrk' *** 0.68 % ±0.38% ±0.51% ±0.66%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='asc' benchmarker='wrk' ** 1.19 % ±0.81% ±1.09% ±1.43%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='buf' benchmarker='wrk' *** 1.50 % ±0.59% ±0.78% ±1.01%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='utf' benchmarker='wrk' *** 2.25 % ±0.45% ±0.59% ±0.77%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='asc' benchmarker='wrk' *** 1.18 % ±0.42% ±0.56% ±0.73%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='buf' benchmarker='wrk' *** 0.92 % ±0.48% ±0.63% ±0.83%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='utf' benchmarker='wrk' *** 1.25 % ±0.32% ±0.43% ±0.56%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='asc' benchmarker='wrk' *** 1.60 % ±0.83% ±1.10% ±1.44%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='buf' benchmarker='wrk' *** 2.34 % ±0.88% ±1.18% ±1.53%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='utf' benchmarker='wrk' *** 2.95 % ±0.48% ±0.64% ±0.83%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='asc' benchmarker='wrk' -0.33 % ±0.57% ±0.77% ±1.00%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='buf' benchmarker='wrk' -0.16 % ±0.52% ±0.69% ±0.90%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='utf' benchmarker='wrk' -0.12 % ±0.36% ±0.47% ±0.62%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='asc' benchmarker='wrk' 0.07 % ±0.76% ±1.01% ±1.32%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='buf' benchmarker='wrk' -0.25 % ±0.51% ±0.68% ±0.89%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='utf' benchmarker='wrk' 0.53 % ±1.00% ±1.34% ±1.74%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='asc' benchmarker='wrk' -0.26 % ±0.61% ±0.81% ±1.06%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='buf' benchmarker='wrk' -0.05 % ±0.47% ±0.62% ±0.81%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='utf' benchmarker='wrk' -0.08 % ±0.56% ±0.74% ±0.96%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='asc' benchmarker='wrk' -0.50 % ±0.96% ±1.28% ±1.66%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='buf' benchmarker='wrk' -0.22 % ±0.71% ±0.94% ±1.23%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='utf' benchmarker='wrk' 0.10 % ±0.58% ±0.77% ±1.01%
http/headers.js group='fewHeaders' duration=5 len=1 n=10 benchmarker='wrk' -0.23 % ±0.65% ±0.86% ±1.13%
http/headers.js group='fewHeaders' duration=5 len=5 n=10 benchmarker='wrk' 0.25 % ±0.59% ±0.79% ±1.03%
http/headers.js group='manyHeaders' duration=5 len=1 n=600 benchmarker='wrk' -0.11 % ±0.86% ±1.15% ±1.49%
http/headers.js group='manyHeaders' duration=5 len=100 n=600 benchmarker='wrk' 0.22 % ±1.12% ±1.49% ±1.94%
http/headers.js group='mediumHeaders' duration=5 len=1 n=50 benchmarker='wrk' -0.28 % ±0.51% ±0.67% ±0.88%
http/headers.js group='mediumHeaders' duration=5 len=10 n=50 benchmarker='wrk' 0.04 % ±0.53% ±0.71% ±0.93%
http/http_server_for_chunky_client.js type='send' n=2000 len=1 0.19 % ±0.57% ±0.77% ±1.00%
http/http_server_for_chunky_client.js type='send' n=2000 len=128 -0.12 % ±0.59% ±0.78% ±1.02%
http/http_server_for_chunky_client.js type='send' n=2000 len=16 -0.01 % ±0.60% ±0.79% ±1.03%
http/http_server_for_chunky_client.js type='send' n=2000 len=32 0.15 % ±0.61% ±0.81% ±1.06%
http/http_server_for_chunky_client.js type='send' n=2000 len=4 0.67 % ±0.69% ±0.92% ±1.21%
http/http_server_for_chunky_client.js type='send' n=2000 len=64 -0.30 % ±0.48% ±0.64% ±0.83%
http/http_server_for_chunky_client.js type='send' n=2000 len=8 -0.50 % ±0.55% ±0.73% ±0.95%
http/http_server_for_chunky_client.js type='send' n=5 len=1 -1.39 % ±2.60% ±3.47% ±4.51%
http/http_server_for_chunky_client.js type='send' n=5 len=128 -4.15 % ±13.02% ±17.32% ±22.54%
http/http_server_for_chunky_client.js type='send' n=5 len=16 7.54 % ±10.05% ±13.50% ±17.81%
http/http_server_for_chunky_client.js type='send' n=5 len=32 0.87 % ±11.95% ±15.91% ±20.71%
http/http_server_for_chunky_client.js type='send' n=5 len=4 1.73 % ±10.57% ±14.06% ±18.30%
http/http_server_for_chunky_client.js type='send' n=5 len=64 -5.12 % ±14.17% ±18.86% ±24.56%
http/http_server_for_chunky_client.js type='send' n=5 len=8 -2.55 % ±5.92% ±7.90% ±10.32%
http/http_server_for_chunky_client.js type='send' n=50 len=1 1.27 % ±2.86% ±3.81% ±4.96%
http/http_server_for_chunky_client.js type='send' n=50 len=128 * 5.17 % ±4.13% ±5.49% ±7.15%
http/http_server_for_chunky_client.js type='send' n=50 len=16 -0.71 % ±2.69% ±3.58% ±4.67%
http/http_server_for_chunky_client.js type='send' n=50 len=32 -0.12 % ±2.72% ±3.63% ±4.74%
http/http_server_for_chunky_client.js type='send' n=50 len=4 -1.47 % ±3.06% ±4.07% ±5.29%
http/http_server_for_chunky_client.js type='send' n=50 len=64 2.04 % ±3.51% ±4.67% ±6.09%
http/http_server_for_chunky_client.js type='send' n=50 len=8 -0.08 % ±2.21% ±2.94% ±3.84%
http/http_server_for_chunky_client.js type='send' n=500 len=1 -0.08 % ±0.80% ±1.07% ±1.40%
http/http_server_for_chunky_client.js type='send' n=500 len=128 -0.38 % ±0.70% ±0.93% ±1.21%
http/http_server_for_chunky_client.js type='send' n=500 len=16 * -0.94 % ±0.83% ±1.11% ±1.45%
http/http_server_for_chunky_client.js type='send' n=500 len=32 -0.43 % ±0.83% ±1.11% ±1.45%
http/http_server_for_chunky_client.js type='send' n=500 len=4 -0.02 % ±0.71% ±0.95% ±1.24%
http/http_server_for_chunky_client.js type='send' n=500 len=64 -0.19 % ±0.93% ±1.24% ±1.62%
http/http_server_for_chunky_client.js type='send' n=500 len=8 -0.15 % ±0.71% ±0.95% ±1.23%
http/incoming_headers.js duration=5 w=0 headers=20 connections=50 benchmarker='wrk' 0.04 % ±0.81% ±1.08% ±1.42%
http/incoming_headers.js duration=5 w=6 headers=20 connections=50 benchmarker='wrk' 0.04 % ±0.64% ±0.85% ±1.11%
http/set_header.js n=1000000 value='Connection' ** -2.20 % ±1.65% ±2.19% ±2.85%
http/set_header.js n=1000000 value='Content-Length' 0.29 % ±1.71% ±2.28% ±2.97%
http/set_header.js n=1000000 value='Content-Type' 1.33 % ±1.88% ±2.51% ±3.27%
http/set_header.js n=1000000 value='Set-Cookie' 1.14 % ±1.33% ±1.77% ±2.30%
http/set_header.js n=1000000 value='Transfer-Encoding' 1.06 % ±1.33% ±1.76% ±2.30%
http/set_header.js n=1000000 value='Vary' -0.57 % ±1.72% ±2.29% ±2.99%
http/set_header.js n=1000000 value='X-Powered-By' * 1.49 % ±1.33% ±1.77% ±2.30%
http/set-header.js duration=5 res='normal' benchmarker='wrk' *** 9.74 % ±0.78% ±1.04% ±1.35%
http/set-header.js duration=5 res='setHeader' benchmarker='wrk' *** 9.87 % ±0.83% ±1.10% ±1.44%
http/set-header.js duration=5 res='setHeaderWH' benchmarker='wrk' *** 9.59 % ±0.92% ±1.22% ±1.59%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=1024 type='buffer' benchmarker='wrk' *** 2.60 % ±0.75% ±1.00% ±1.30%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=1024 type='bytes' benchmarker='wrk' *** 9.54 % ±0.74% ±0.99% ±1.28%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=102400 type='buffer' benchmarker='wrk' ** 1.23 % ±0.75% ±0.99% ±1.29%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=102400 type='bytes' benchmarker='wrk' *** 1.98 % ±0.49% ±0.65% ±0.84%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=4 type='buffer' benchmarker='wrk' *** 2.43 % ±0.76% ±1.01% ±1.31%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=4 type='bytes' benchmarker='wrk' *** 9.55 % ±0.71% ±0.95% ±1.24%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=1024 type='buffer' benchmarker='wrk' *** 3.14 % ±0.86% ±1.15% ±1.50%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=1024 type='bytes' benchmarker='wrk' *** 2.94 % ±0.78% ±1.04% ±1.35%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=102400 type='buffer' benchmarker='wrk' *** 1.55 % ±0.62% ±0.82% ±1.07%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=102400 type='bytes' benchmarker='wrk' ** 1.10 % ±0.82% ±1.09% ±1.42%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=4 type='buffer' benchmarker='wrk' *** 3.91 % ±0.83% ±1.10% ±1.44%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=4 type='bytes' benchmarker='wrk' *** 3.47 % ±0.93% ±1.23% ±1.60%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=1024 type='buffer' benchmarker='wrk' *** 3.60 % ±0.96% ±1.27% ±1.66%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=1024 type='bytes' benchmarker='wrk' *** 9.20 % ±0.99% ±1.32% ±1.72%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=102400 type='buffer' benchmarker='wrk' *** 1.28 % ±0.53% ±0.71% ±0.93%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=102400 type='bytes' benchmarker='wrk' *** 1.28 % ±0.65% ±0.87% ±1.13%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=4 type='buffer' benchmarker='wrk' *** 3.59 % ±0.96% ±1.28% ±1.67%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=4 type='bytes' benchmarker='wrk' *** 9.93 % ±1.01% ±1.35% ±1.76%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=1024 type='buffer' benchmarker='wrk' *** 2.04 % ±0.98% ±1.31% ±1.70%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=1024 type='bytes' benchmarker='wrk' *** 2.14 % ±0.82% ±1.08% ±1.41%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=102400 type='buffer' benchmarker='wrk' *** 1.74 % ±0.67% ±0.89% ±1.16%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=102400 type='bytes' benchmarker='wrk' ** 1.10 % ±0.79% ±1.05% ±1.36%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=4 type='buffer' benchmarker='wrk' *** 3.20 % ±0.94% ±1.24% ±1.62%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=4 type='bytes' benchmarker='wrk' *** 3.12 % ±0.76% ±1.01% ±1.32%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=1024 type='buffer' benchmarker='wrk' -0.19 % ±0.80% ±1.06% ±1.38%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=1024 type='bytes' benchmarker='wrk' -0.44 % ±0.95% ±1.26% ±1.65%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=102400 type='buffer' benchmarker='wrk' 0.11 % ±0.61% ±0.81% ±1.06%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=102400 type='bytes' benchmarker='wrk' * -1.19 % ±1.11% ±1.47% ±1.92%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=4 type='buffer' benchmarker='wrk' -0.23 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=4 type='bytes' benchmarker='wrk' 0.10 % ±0.75% ±1.00% ±1.30%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=1024 type='buffer' benchmarker='wrk' -0.55 % ±0.76% ±1.01% ±1.32%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=1024 type='bytes' benchmarker='wrk' 0.19 % ±0.95% ±1.27% ±1.65%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=102400 type='buffer' benchmarker='wrk' ** -1.32 % ±0.79% ±1.06% ±1.37%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=102400 type='bytes' benchmarker='wrk' 0.69 % ±1.07% ±1.42% ±1.85%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=4 type='buffer' benchmarker='wrk' 0.54 % ±0.81% ±1.07% ±1.40%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=4 type='bytes' benchmarker='wrk' 0.56 % ±0.71% ±0.95% ±1.23%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=1024 type='buffer' benchmarker='wrk' -0.48 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=1024 type='bytes' benchmarker='wrk' -0.62 % ±0.85% ±1.13% ±1.48%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=102400 type='buffer' benchmarker='wrk' -0.20 % ±0.69% ±0.92% ±1.20%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=102400 type='bytes' benchmarker='wrk' 0.43 % ±1.18% ±1.56% ±2.04%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=4 type='buffer' benchmarker='wrk' 0.29 % ±0.89% ±1.19% ±1.55%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=4 type='bytes' benchmarker='wrk' * -1.01 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=1024 type='buffer' benchmarker='wrk' -0.18 % ±0.68% ±0.90% ±1.18%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=1024 type='bytes' benchmarker='wrk' 0.09 % ±0.65% ±0.86% ±1.12%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=102400 type='buffer' benchmarker='wrk' * -0.55 % ±0.49% ±0.66% ±0.86%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=102400 type='bytes' benchmarker='wrk' 0.10 % ±0.82% ±1.09% ±1.42%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=4 type='buffer' benchmarker='wrk' 0.35 % ±0.74% ±0.98% ±1.28%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=4 type='bytes' benchmarker='wrk' -0.26 % ±0.65% ±0.86% ±1.12%
http/upgrade.js n=1000 0.73 % ±2.37% ±3.16% ±4.11%
http/upgrade.js n=5 6.72 % ±8.30% ±11.05% ±14.38%

Be aware that when doing many comparisons the risk of a false-positive result increases.
In this case, there are 235 comparisons, you can thus expect the following amount of false-positive results:
11.75 false positives, when considering a 5% risk acceptance (*, **, *),
2.35 false positives, when considering a 1% risk acceptance (
, ),
0.24 false positives, when considering a 0.1% risk acceptance (
)

Looks good I think. Headlines:

  • No notable regressions - each of the small negative cases I can see are low-confidence and fit into an overall pattern of no change considering the tests around them
  • A very consistent 9.59% - 9.87% speed up in http/set-header.js test, which tests headers + res.end(body).
  • For http/simple:
    • Consistent boost around 9.5% with type=bytes, no chunking, and len up to 1024.
    • 3% boost with type=buffer, on the same small non-chunked responses.
    • Both buffer & byte body perf dropping to about 1-2% improvement for larger bodies (1MB).
    • No significant change with chunked encoding.
  • 10.48% boost to http/end-string test with 1KB, dropping to 5.59% with 16KB, down to 2.47% improvement with 1MB.
  • ~2% boost across various http/end-vs-write-end.js cases that call end(data) on different large sizes.

Looks pretty convincing to me! All approved and ready-to-go now and I think this is all just good news, so I'll commit-queue.

@pimterrypimterry added the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 24, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 214cf06 into nodejs:mainAug 24, 2026
85 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 214cf06

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 24, 2026
@pimterry
pimterry deleted the h1-clean-end-perf branch August 25, 2026 15:12
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
aduh95 pushed a commit that referenced this pull request Aug 27, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

httpIssues and PRs related to the http subsystem.needs-benchmark-ciPRs that need a benchmark CI run.needs-ciPRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants

@pimterry@nodejs-github-bot@mcollina@lpinca@anonrig@efekrskl@mertcanaltin@gurgunday@bjohansebas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

http: improve performance for end() with known-length string - #65466

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
pimterry:h1-clean-end-perf
Aug 24, 2026
Merged

http: improve performance for end() with known-length string#65466
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
pimterry:h1-clean-end-perf

Conversation

@pimterry

Copy link
Copy Markdown
Member

When you call end(data) on an outgoing HTTP request, we previously wrote the data, and then ran _send('', ...) just to trigger flushing the headers, which resulted in an extra zero-byte write call and bonus nextTick before 'finish'.

When the length is known and content-length is used (not chunking, so we don't need a terminator) we can skip this completely: prep the content-length header explicitly, and combine the finish into the existing write step.

This drops a nextTick, and goes from 2 write calls to 1 for the very common case of response.end(data) with a string, and for buffer data goes from 3 writes to 2.

In practice, in the tiny benchmark here which I think represents a very common use case (small API responses) I see this boosting HTTP RPS by up to 9% for writes up to 1KB or so. For larger responses the response write time starts to outweigh this, but I still see 3% RPS boost at 16KB. Needs autocannon to hit the rates required, you can test yourself with:

node benchmark/compare.js --old ./node-main --new ./node-pr --runs 20 --set benchmarker=autocannon --filter end-string http

Added a new test confirming the specific details and edge cases this touches, and updated one existing test which specifically asserted that end(data) triggered two writes, including the empty one.

This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/http
  • @nodejs/net
  • @nodejs/performance

@nodejs-github-botnodejs-github-bot added http Issues and PRs related to the http subsystem. needs-ci PRs that need a full CI run. labels Aug 21, 2026

@mcollinamcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@mcollina
mcollina requested a review from anonrigAugust 21, 2026 19:24
@codecov

codecovBot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.13%. Comparing base (15940ef) to head (659d6b9).
⚠️ Report is 61 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #65466 +/- ##
==========================================
- Coverage 90.14% 90.13% -0.01% 
==========================================
Files 751 751 Lines 252298 252333 +35 Branches 47446 47449 +3 ==========================================
+ Hits 227436 227451 +15 - Misses 16175 16186 +11 - Partials 8687 8696 +9 
Files with missing linesCoverage Δ
lib/_http_outgoing.js97.76% <100.00%> (-0.02%)⬇️

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

@pimterrypimterry added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 21, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 22, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@bjohansebasbjohansebas added the needs-benchmark-ci PRs that need a benchmark CI run. label Aug 22, 2026
@pimterry

Copy link
Copy Markdown
MemberAuthor

@bjohansebas benchmark label was a good suggestion. I've done a run here.

Unfortunately it seems like the microbenchmark job is broken generally (cc @nodejs/build) and all recent jobs have failed with:

++ Rscript benchmark/compare.R
Error: package or namespace load failed for ‘ggplot2’ in dyn.load(file, DLLpath = DLLpath, ...):
unable to load shared object '/usr/local/lib/R/site-library/rlang/libs/rlang.so':
/usr/local/lib/R/site-library/rlang/libs/rlang.so: undefined symbol: SETLENGTH
Execution halted

I've manually extracted the CSV from the console output to get some numbers though, and run node-benchmark-compare on the result, which gives:

Details
 confidence improvement accuracy (*) (**) (***)
http/bench-parser-fragmented.js n=100000 frags=2 len=16 -0.20 % ±1.06% ±1.42% ±1.85%
http/bench-parser-fragmented.js n=100000 frags=2 len=8 -0.01 % ±0.94% ±1.25% ±1.63%
http/bench-parser-fragmented.js n=100000 frags=4 len=16 -0.17 % ±0.77% ±1.02% ±1.33%
http/bench-parser-fragmented.js n=100000 frags=4 len=8 -0.57 % ±0.64% ±0.85% ±1.11%
http/bench-parser-fragmented.js n=100000 frags=8 len=16 -0.07 % ±0.84% ±1.12% ±1.45%
http/bench-parser-fragmented.js n=100000 frags=8 len=8 0.43 % ±0.78% ±1.04% ±1.35%
http/bench-parser.js n=100000 len=16 0.20 % ±0.93% ±1.24% ±1.61%
http/bench-parser.js n=100000 len=32 0.03 % ±0.68% ±0.90% ±1.17%
http/bench-parser.js n=100000 len=4 0.60 % ±1.08% ±1.43% ±1.86%
http/bench-parser.js n=100000 len=8 0.32 % ±1.11% ±1.47% ±1.92%
http/check_invalid_header_char.js n=1000000 input='' 1.25 % ±2.48% ±3.30% ±4.30%
http/check_invalid_header_char.js n=1000000 input='\t\t\t\t\t\t\t\t\t\tFoo bar baz' 0.39 % ±1.66% ±2.21% ±2.88%
http/check_invalid_header_char.js n=1000000 input='\x7F' * 4.92 % ±3.90% ±5.19% ±6.75%
http/check_invalid_header_char.js n=1000000 input='1' -0.41 % ±3.47% ±4.62% ±6.02%
http/check_invalid_header_char.js n=1000000 input='20091' -0.50 % ±3.85% ±5.12% ±6.66%
http/check_invalid_header_char.js n=1000000 input='close' 0.49 % ±3.34% ±4.44% ±5.78%
http/check_invalid_header_char.js n=1000000 input='en-US' -0.66 % ±3.59% ±4.77% ±6.21%
http/check_invalid_header_char.js n=1000000 input='foo\nbar' -1.88 % ±2.70% ±3.60% ±4.70%
http/check_invalid_header_char.js n=1000000 input='group_acmeair' 0.85 % ±1.82% ±2.42% ±3.16%
http/check_invalid_header_char.js n=1000000 input='gzip' -0.60 % ±3.29% ±4.37% ±5.70%
http/check_invalid_header_char.js n=1000000 input='keep-alive' -1.28 % ±2.16% ±2.88% ±3.75%
http/check_invalid_header_char.js n=1000000 input='LONG_AND_INVALID' 0.08 % ±1.13% ±1.51% ±1.97%
http/check_invalid_header_char.js n=1000000 input='private' 1.00 % ±2.68% ±3.57% ±4.65%
http/check_invalid_header_char.js n=1000000 input='SAMEORIGIN' 1.36 % ±2.81% ±3.74% ±4.88%
http/check_invalid_header_char.js n=1000000 input='Sat, 07 May 2016 16:54:48 GMT' 0.79 % ±1.41% ±1.87% ±2.44%
http/check_invalid_header_char.js n=1000000 input='text/html; charset=utf-8' -0.12 % ±1.41% ±1.88% ±2.45%
http/check_invalid_header_char.js n=1000000 input='text/plain' -1.49 % ±2.96% ±3.95% ±5.14%
http/check_invalid_header_char.js n=1000000 input='中文呢' 1.95 % ±2.71% ±3.61% ±4.69%
http/check_is_http_token.js n=1000000 key=':' -0.22 % ±2.22% ±2.96% ±3.85%
http/check_is_http_token.js n=1000000 key=':alternate-protocol' 2.82 % ±4.07% ±5.42% ±7.06%
http/check_is_http_token.js n=1000000 key='((((())))' -1.22 % ±2.75% ±3.71% ±4.91%
http/check_is_http_token.js n=1000000 key='@@' 0.52 % ±2.14% ±2.85% ±3.71%
http/check_is_http_token.js n=1000000 key='Accept-Ranges' 0.51 % ±2.25% ±2.99% ±3.90%
http/check_is_http_token.js n=1000000 key='alt-svc' -0.09 % ±2.23% ±2.97% ±3.87%
http/check_is_http_token.js n=1000000 key='alternate-protocol:' -0.94 % ±2.08% ±2.77% ±3.61%
http/check_is_http_token.js n=1000000 key='alternate-protocol' -1.19 % ±2.32% ±3.09% ±4.03%
http/check_is_http_token.js n=1000000 key='Cache-Control' -0.96 % ±2.14% ±2.85% ±3.71%
http/check_is_http_token.js n=1000000 key='Connection' 0.78 % ±2.39% ±3.19% ±4.15%
http/check_is_http_token.js n=1000000 key='Content-Encoding' * -2.76 % ±2.26% ±3.01% ±3.92%
http/check_is_http_token.js n=1000000 key='content-length' 0.93 % ±2.27% ±3.02% ±3.92%
http/check_is_http_token.js n=1000000 key='Content-Location' -0.15 % ±2.52% ±3.35% ±4.36%
http/check_is_http_token.js n=1000000 key='content-type' -0.49 % ±2.55% ±3.39% ±4.41%
http/check_is_http_token.js n=1000000 key='Content-Type' 0.46 % ±2.58% ±3.43% ±4.47%
http/check_is_http_token.js n=1000000 key='date' 0.62 % ±2.42% ±3.22% ±4.19%
http/check_is_http_token.js n=1000000 key='ETag' -2.60 % ±3.97% ±5.32% ±7.01%
http/check_is_http_token.js n=1000000 key='Expires' ** 3.69 % ±2.64% ±3.52% ±4.59%
http/check_is_http_token.js n=1000000 key='Keep-Alive' -0.03 % ±2.59% ±3.45% ±4.48%
http/check_is_http_token.js n=1000000 key='Last-Modified' -0.99 % ±2.34% ±3.12% ±4.07%
http/check_is_http_token.js n=1000000 key='location' 0.79 % ±2.44% ±3.25% ±4.23%
http/check_is_http_token.js n=1000000 key='server' 0.37 % ±2.46% ±3.27% ±4.25%
http/check_is_http_token.js n=1000000 key='Server' * 3.70 % ±3.00% ±4.00% ±5.23%
http/check_is_http_token.js n=1000000 key='status' ** -4.32 % ±3.09% ±4.13% ±5.40%
http/check_is_http_token.js n=1000000 key='TCN' -0.86 % ±1.00% ±1.33% ±1.73%
http/check_is_http_token.js n=1000000 key='Transfer-Encoding' -1.00 % ±2.32% ±3.09% ±4.02%
http/check_is_http_token.js n=1000000 key='Vary' -0.56 % ±1.47% ±1.95% ±2.54%
http/check_is_http_token.js n=1000000 key='version' 1.90 % ±2.74% ±3.65% ±4.75%
http/check_is_http_token.js n=1000000 key='x-frame-options' 0.57 % ±2.05% ±2.73% ±3.55%
http/check_is_http_token.js n=1000000 key='x-xss-protection' -1.39 % ±2.29% ±3.06% ±3.99%
http/check_is_http_token.js n=1000000 key='中文呢' -1.00 % ±4.47% ±6.01% ±7.92%
http/chunked.js duration=5 c=100 len=1 n=1 benchmarker='wrk' -0.19 % ±0.68% ±0.91% ±1.18%
http/chunked.js duration=5 c=100 len=1 n=16 benchmarker='wrk' 0.41 % ±0.78% ±1.03% ±1.35%
http/chunked.js duration=5 c=100 len=1 n=4 benchmarker='wrk' 0.61 % ±2.08% ±2.76% ±3.60%
http/chunked.js duration=5 c=100 len=1 n=8 benchmarker='wrk' 0.13 % ±0.81% ±1.07% ±1.40%
http/chunked.js duration=5 c=100 len=256 n=1 benchmarker='wrk' -0.10 % ±0.70% ±0.93% ±1.21%
http/chunked.js duration=5 c=100 len=256 n=16 benchmarker='wrk' -0.70 % ±0.73% ±0.97% ±1.26%
http/chunked.js duration=5 c=100 len=256 n=4 benchmarker='wrk' -0.58 % ±1.84% ±2.45% ±3.18%
http/chunked.js duration=5 c=100 len=256 n=8 benchmarker='wrk' 0.11 % ±0.87% ±1.16% ±1.51%
http/chunked.js duration=5 c=100 len=64 n=1 benchmarker='wrk' -0.26 % ±0.60% ±0.80% ±1.04%
http/chunked.js duration=5 c=100 len=64 n=16 benchmarker='wrk' 0.56 % ±0.63% ±0.84% ±1.10%
http/chunked.js duration=5 c=100 len=64 n=4 benchmarker='wrk' 0.08 % ±1.81% ±2.41% ±3.15%
http/chunked.js duration=5 c=100 len=64 n=8 benchmarker='wrk' 0.26 % ±0.75% ±1.00% ±1.30%
http/client-request-body.js method='end' len=1024 type='asc' dur=5 -0.06 % ±0.69% ±0.92% ±1.20%
http/client-request-body.js method='end' len=1024 type='buf' dur=5 0.01 % ±0.76% ±1.02% ±1.32%
http/client-request-body.js method='end' len=1024 type='utf' dur=5 -0.28 % ±0.59% ±0.79% ±1.03%
http/client-request-body.js method='end' len=256 type='asc' dur=5 -0.49 % ±0.67% ±0.90% ±1.17%
http/client-request-body.js method='end' len=256 type='buf' dur=5 * -0.75 % ±0.68% ±0.90% ±1.18%
http/client-request-body.js method='end' len=256 type='utf' dur=5 0.03 % ±0.62% ±0.83% ±1.08%
http/client-request-body.js method='end' len=32 type='asc' dur=5 -0.01 % ±0.56% ±0.75% ±0.98%
http/client-request-body.js method='end' len=32 type='buf' dur=5 -0.37 % ±0.60% ±0.79% ±1.03%
http/client-request-body.js method='end' len=32 type='utf' dur=5 -0.16 % ±0.62% ±0.83% ±1.08%
http/client-request-body.js method='write' len=1024 type='asc' dur=5 -0.16 % ±0.78% ±1.03% ±1.34%
http/client-request-body.js method='write' len=1024 type='buf' dur=5 -0.34 % ±0.68% ±0.90% ±1.17%
http/client-request-body.js method='write' len=1024 type='utf' dur=5 0.06 % ±0.78% ±1.04% ±1.35%
http/client-request-body.js method='write' len=256 type='asc' dur=5 0.27 % ±0.70% ±0.93% ±1.21%
http/client-request-body.js method='write' len=256 type='buf' dur=5 0.09 % ±0.76% ±1.02% ±1.32%
http/client-request-body.js method='write' len=256 type='utf' dur=5 0.49 % ±0.59% ±0.79% ±1.03%
http/client-request-body.js method='write' len=32 type='asc' dur=5 -0.40 % ±0.64% ±0.86% ±1.11%
http/client-request-body.js method='write' len=32 type='buf' dur=5 -0.21 % ±0.65% ±0.86% ±1.12%
http/client-request-body.js method='write' len=32 type='utf' dur=5 0.02 % ±0.60% ±0.79% ±1.03%
http/cluster.js duration=5 c=50 len=1024 type='buffer' benchmarker='wrk' 0.13 % ±0.46% ±0.62% ±0.81%
http/cluster.js duration=5 c=50 len=1024 type='bytes' benchmarker='wrk' -0.11 % ±0.38% ±0.50% ±0.66%
http/cluster.js duration=5 c=50 len=102400 type='buffer' benchmarker='wrk' -0.24 % ±0.49% ±0.65% ±0.85%
http/cluster.js duration=5 c=50 len=102400 type='bytes' benchmarker='wrk' 0.14 % ±0.80% ±1.06% ±1.38%
http/cluster.js duration=5 c=50 len=4 type='buffer' benchmarker='wrk' -0.23 % ±0.29% ±0.39% ±0.51%
http/cluster.js duration=5 c=50 len=4 type='bytes' benchmarker='wrk' 0.00 % ±0.51% ±0.67% ±0.88%
http/cluster.js duration=5 c=500 len=1024 type='buffer' benchmarker='wrk' ** -0.77 % ±0.50% ±0.67% ±0.87%
http/cluster.js duration=5 c=500 len=1024 type='bytes' benchmarker='wrk' -0.18 % ±0.65% ±0.86% ±1.12%
http/cluster.js duration=5 c=500 len=102400 type='buffer' benchmarker='wrk' -0.18 % ±0.59% ±0.78% ±1.02%
http/cluster.js duration=5 c=500 len=102400 type='bytes' benchmarker='wrk' 0.28 % ±0.72% ±0.95% ±1.24%
http/cluster.js duration=5 c=500 len=4 type='buffer' benchmarker='wrk' -0.25 % ±0.47% ±0.62% ±0.81%
http/cluster.js duration=5 c=500 len=4 type='bytes' benchmarker='wrk' -0.36 % ±0.52% ±0.70% ±0.91%
http/create-clientrequest.js e=1 arg='options' url='idn' 2.09 % ±7.80% ±10.38% ±13.50%
http/create-clientrequest.js e=1 arg='options' url='long' -9.98 % ±14.10% ±18.77% ±24.46%
http/create-clientrequest.js e=1 arg='options' url='wpt' -4.69 % ±6.75% ±8.98% ±11.70%
http/create-clientrequest.js e=1 arg='string' url='idn' -4.15 % ±10.23% ±13.61% ±17.71%
http/create-clientrequest.js e=1 arg='string' url='long' -0.93 % ±12.77% ±16.99% ±22.12%
http/create-clientrequest.js e=1 arg='string' url='wpt' 0.60 % ±11.36% ±15.12% ±19.68%
http/create-clientrequest.js e=1 arg='URL' url='idn' 0.87 % ±9.17% ±12.20% ±15.88%
http/create-clientrequest.js e=1 arg='URL' url='long' -5.01 % ±10.02% ±13.35% ±17.41%
http/create-clientrequest.js e=1 arg='URL' url='wpt' 1.99 % ±8.00% ±10.64% ±13.85%
http/end-string.js duration=5 c=50 len=1024 benchmarker='wrk' *** 10.48 % ±0.81% ±1.08% ±1.41%
http/end-string.js duration=5 c=50 len=102400 benchmarker='wrk' *** 2.47 % ±0.50% ±0.66% ±0.86%
http/end-string.js duration=5 c=50 len=16384 benchmarker='wrk' *** 5.59 % ±0.89% ±1.19% ±1.55%
http/end-string.js duration=5 c=50 len=4 benchmarker='wrk' *** 9.92 % ±0.82% ±1.10% ±1.43%
http/end-string.js duration=5 c=50 len=64 benchmarker='wrk' *** 8.43 % ±0.71% ±0.94% ±1.23%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='asc' benchmarker='wrk' *** 2.48 % ±0.47% ±0.62% ±0.81%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='buf' benchmarker='wrk' -0.12 % ±0.43% ±0.57% ±0.74%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='utf' benchmarker='wrk' *** 0.68 % ±0.38% ±0.51% ±0.66%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='asc' benchmarker='wrk' ** 1.19 % ±0.81% ±1.09% ±1.43%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='buf' benchmarker='wrk' *** 1.50 % ±0.59% ±0.78% ±1.01%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='utf' benchmarker='wrk' *** 2.25 % ±0.45% ±0.59% ±0.77%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='asc' benchmarker='wrk' *** 1.18 % ±0.42% ±0.56% ±0.73%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='buf' benchmarker='wrk' *** 0.92 % ±0.48% ±0.63% ±0.83%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='utf' benchmarker='wrk' *** 1.25 % ±0.32% ±0.43% ±0.56%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='asc' benchmarker='wrk' *** 1.60 % ±0.83% ±1.10% ±1.44%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='buf' benchmarker='wrk' *** 2.34 % ±0.88% ±1.18% ±1.53%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='utf' benchmarker='wrk' *** 2.95 % ±0.48% ±0.64% ±0.83%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='asc' benchmarker='wrk' -0.33 % ±0.57% ±0.77% ±1.00%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='buf' benchmarker='wrk' -0.16 % ±0.52% ±0.69% ±0.90%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='utf' benchmarker='wrk' -0.12 % ±0.36% ±0.47% ±0.62%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='asc' benchmarker='wrk' 0.07 % ±0.76% ±1.01% ±1.32%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='buf' benchmarker='wrk' -0.25 % ±0.51% ±0.68% ±0.89%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='utf' benchmarker='wrk' 0.53 % ±1.00% ±1.34% ±1.74%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='asc' benchmarker='wrk' -0.26 % ±0.61% ±0.81% ±1.06%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='buf' benchmarker='wrk' -0.05 % ±0.47% ±0.62% ±0.81%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='utf' benchmarker='wrk' -0.08 % ±0.56% ±0.74% ±0.96%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='asc' benchmarker='wrk' -0.50 % ±0.96% ±1.28% ±1.66%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='buf' benchmarker='wrk' -0.22 % ±0.71% ±0.94% ±1.23%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='utf' benchmarker='wrk' 0.10 % ±0.58% ±0.77% ±1.01%
http/headers.js group='fewHeaders' duration=5 len=1 n=10 benchmarker='wrk' -0.23 % ±0.65% ±0.86% ±1.13%
http/headers.js group='fewHeaders' duration=5 len=5 n=10 benchmarker='wrk' 0.25 % ±0.59% ±0.79% ±1.03%
http/headers.js group='manyHeaders' duration=5 len=1 n=600 benchmarker='wrk' -0.11 % ±0.86% ±1.15% ±1.49%
http/headers.js group='manyHeaders' duration=5 len=100 n=600 benchmarker='wrk' 0.22 % ±1.12% ±1.49% ±1.94%
http/headers.js group='mediumHeaders' duration=5 len=1 n=50 benchmarker='wrk' -0.28 % ±0.51% ±0.67% ±0.88%
http/headers.js group='mediumHeaders' duration=5 len=10 n=50 benchmarker='wrk' 0.04 % ±0.53% ±0.71% ±0.93%
http/http_server_for_chunky_client.js type='send' n=2000 len=1 0.19 % ±0.57% ±0.77% ±1.00%
http/http_server_for_chunky_client.js type='send' n=2000 len=128 -0.12 % ±0.59% ±0.78% ±1.02%
http/http_server_for_chunky_client.js type='send' n=2000 len=16 -0.01 % ±0.60% ±0.79% ±1.03%
http/http_server_for_chunky_client.js type='send' n=2000 len=32 0.15 % ±0.61% ±0.81% ±1.06%
http/http_server_for_chunky_client.js type='send' n=2000 len=4 0.67 % ±0.69% ±0.92% ±1.21%
http/http_server_for_chunky_client.js type='send' n=2000 len=64 -0.30 % ±0.48% ±0.64% ±0.83%
http/http_server_for_chunky_client.js type='send' n=2000 len=8 -0.50 % ±0.55% ±0.73% ±0.95%
http/http_server_for_chunky_client.js type='send' n=5 len=1 -1.39 % ±2.60% ±3.47% ±4.51%
http/http_server_for_chunky_client.js type='send' n=5 len=128 -4.15 % ±13.02% ±17.32% ±22.54%
http/http_server_for_chunky_client.js type='send' n=5 len=16 7.54 % ±10.05% ±13.50% ±17.81%
http/http_server_for_chunky_client.js type='send' n=5 len=32 0.87 % ±11.95% ±15.91% ±20.71%
http/http_server_for_chunky_client.js type='send' n=5 len=4 1.73 % ±10.57% ±14.06% ±18.30%
http/http_server_for_chunky_client.js type='send' n=5 len=64 -5.12 % ±14.17% ±18.86% ±24.56%
http/http_server_for_chunky_client.js type='send' n=5 len=8 -2.55 % ±5.92% ±7.90% ±10.32%
http/http_server_for_chunky_client.js type='send' n=50 len=1 1.27 % ±2.86% ±3.81% ±4.96%
http/http_server_for_chunky_client.js type='send' n=50 len=128 * 5.17 % ±4.13% ±5.49% ±7.15%
http/http_server_for_chunky_client.js type='send' n=50 len=16 -0.71 % ±2.69% ±3.58% ±4.67%
http/http_server_for_chunky_client.js type='send' n=50 len=32 -0.12 % ±2.72% ±3.63% ±4.74%
http/http_server_for_chunky_client.js type='send' n=50 len=4 -1.47 % ±3.06% ±4.07% ±5.29%
http/http_server_for_chunky_client.js type='send' n=50 len=64 2.04 % ±3.51% ±4.67% ±6.09%
http/http_server_for_chunky_client.js type='send' n=50 len=8 -0.08 % ±2.21% ±2.94% ±3.84%
http/http_server_for_chunky_client.js type='send' n=500 len=1 -0.08 % ±0.80% ±1.07% ±1.40%
http/http_server_for_chunky_client.js type='send' n=500 len=128 -0.38 % ±0.70% ±0.93% ±1.21%
http/http_server_for_chunky_client.js type='send' n=500 len=16 * -0.94 % ±0.83% ±1.11% ±1.45%
http/http_server_for_chunky_client.js type='send' n=500 len=32 -0.43 % ±0.83% ±1.11% ±1.45%
http/http_server_for_chunky_client.js type='send' n=500 len=4 -0.02 % ±0.71% ±0.95% ±1.24%
http/http_server_for_chunky_client.js type='send' n=500 len=64 -0.19 % ±0.93% ±1.24% ±1.62%
http/http_server_for_chunky_client.js type='send' n=500 len=8 -0.15 % ±0.71% ±0.95% ±1.23%
http/incoming_headers.js duration=5 w=0 headers=20 connections=50 benchmarker='wrk' 0.04 % ±0.81% ±1.08% ±1.42%
http/incoming_headers.js duration=5 w=6 headers=20 connections=50 benchmarker='wrk' 0.04 % ±0.64% ±0.85% ±1.11%
http/set_header.js n=1000000 value='Connection' ** -2.20 % ±1.65% ±2.19% ±2.85%
http/set_header.js n=1000000 value='Content-Length' 0.29 % ±1.71% ±2.28% ±2.97%
http/set_header.js n=1000000 value='Content-Type' 1.33 % ±1.88% ±2.51% ±3.27%
http/set_header.js n=1000000 value='Set-Cookie' 1.14 % ±1.33% ±1.77% ±2.30%
http/set_header.js n=1000000 value='Transfer-Encoding' 1.06 % ±1.33% ±1.76% ±2.30%
http/set_header.js n=1000000 value='Vary' -0.57 % ±1.72% ±2.29% ±2.99%
http/set_header.js n=1000000 value='X-Powered-By' * 1.49 % ±1.33% ±1.77% ±2.30%
http/set-header.js duration=5 res='normal' benchmarker='wrk' *** 9.74 % ±0.78% ±1.04% ±1.35%
http/set-header.js duration=5 res='setHeader' benchmarker='wrk' *** 9.87 % ±0.83% ±1.10% ±1.44%
http/set-header.js duration=5 res='setHeaderWH' benchmarker='wrk' *** 9.59 % ±0.92% ±1.22% ±1.59%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=1024 type='buffer' benchmarker='wrk' *** 2.60 % ±0.75% ±1.00% ±1.30%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=1024 type='bytes' benchmarker='wrk' *** 9.54 % ±0.74% ±0.99% ±1.28%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=102400 type='buffer' benchmarker='wrk' ** 1.23 % ±0.75% ±0.99% ±1.29%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=102400 type='bytes' benchmarker='wrk' *** 1.98 % ±0.49% ±0.65% ±0.84%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=4 type='buffer' benchmarker='wrk' *** 2.43 % ±0.76% ±1.01% ±1.31%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=4 type='bytes' benchmarker='wrk' *** 9.55 % ±0.71% ±0.95% ±1.24%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=1024 type='buffer' benchmarker='wrk' *** 3.14 % ±0.86% ±1.15% ±1.50%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=1024 type='bytes' benchmarker='wrk' *** 2.94 % ±0.78% ±1.04% ±1.35%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=102400 type='buffer' benchmarker='wrk' *** 1.55 % ±0.62% ±0.82% ±1.07%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=102400 type='bytes' benchmarker='wrk' ** 1.10 % ±0.82% ±1.09% ±1.42%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=4 type='buffer' benchmarker='wrk' *** 3.91 % ±0.83% ±1.10% ±1.44%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=4 type='bytes' benchmarker='wrk' *** 3.47 % ±0.93% ±1.23% ±1.60%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=1024 type='buffer' benchmarker='wrk' *** 3.60 % ±0.96% ±1.27% ±1.66%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=1024 type='bytes' benchmarker='wrk' *** 9.20 % ±0.99% ±1.32% ±1.72%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=102400 type='buffer' benchmarker='wrk' *** 1.28 % ±0.53% ±0.71% ±0.93%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=102400 type='bytes' benchmarker='wrk' *** 1.28 % ±0.65% ±0.87% ±1.13%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=4 type='buffer' benchmarker='wrk' *** 3.59 % ±0.96% ±1.28% ±1.67%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=4 type='bytes' benchmarker='wrk' *** 9.93 % ±1.01% ±1.35% ±1.76%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=1024 type='buffer' benchmarker='wrk' *** 2.04 % ±0.98% ±1.31% ±1.70%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=1024 type='bytes' benchmarker='wrk' *** 2.14 % ±0.82% ±1.08% ±1.41%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=102400 type='buffer' benchmarker='wrk' *** 1.74 % ±0.67% ±0.89% ±1.16%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=102400 type='bytes' benchmarker='wrk' ** 1.10 % ±0.79% ±1.05% ±1.36%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=4 type='buffer' benchmarker='wrk' *** 3.20 % ±0.94% ±1.24% ±1.62%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=4 type='bytes' benchmarker='wrk' *** 3.12 % ±0.76% ±1.01% ±1.32%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=1024 type='buffer' benchmarker='wrk' -0.19 % ±0.80% ±1.06% ±1.38%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=1024 type='bytes' benchmarker='wrk' -0.44 % ±0.95% ±1.26% ±1.65%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=102400 type='buffer' benchmarker='wrk' 0.11 % ±0.61% ±0.81% ±1.06%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=102400 type='bytes' benchmarker='wrk' * -1.19 % ±1.11% ±1.47% ±1.92%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=4 type='buffer' benchmarker='wrk' -0.23 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=4 type='bytes' benchmarker='wrk' 0.10 % ±0.75% ±1.00% ±1.30%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=1024 type='buffer' benchmarker='wrk' -0.55 % ±0.76% ±1.01% ±1.32%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=1024 type='bytes' benchmarker='wrk' 0.19 % ±0.95% ±1.27% ±1.65%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=102400 type='buffer' benchmarker='wrk' ** -1.32 % ±0.79% ±1.06% ±1.37%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=102400 type='bytes' benchmarker='wrk' 0.69 % ±1.07% ±1.42% ±1.85%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=4 type='buffer' benchmarker='wrk' 0.54 % ±0.81% ±1.07% ±1.40%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=4 type='bytes' benchmarker='wrk' 0.56 % ±0.71% ±0.95% ±1.23%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=1024 type='buffer' benchmarker='wrk' -0.48 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=1024 type='bytes' benchmarker='wrk' -0.62 % ±0.85% ±1.13% ±1.48%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=102400 type='buffer' benchmarker='wrk' -0.20 % ±0.69% ±0.92% ±1.20%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=102400 type='bytes' benchmarker='wrk' 0.43 % ±1.18% ±1.56% ±2.04%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=4 type='buffer' benchmarker='wrk' 0.29 % ±0.89% ±1.19% ±1.55%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=4 type='bytes' benchmarker='wrk' * -1.01 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=1024 type='buffer' benchmarker='wrk' -0.18 % ±0.68% ±0.90% ±1.18%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=1024 type='bytes' benchmarker='wrk' 0.09 % ±0.65% ±0.86% ±1.12%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=102400 type='buffer' benchmarker='wrk' * -0.55 % ±0.49% ±0.66% ±0.86%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=102400 type='bytes' benchmarker='wrk' 0.10 % ±0.82% ±1.09% ±1.42%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=4 type='buffer' benchmarker='wrk' 0.35 % ±0.74% ±0.98% ±1.28%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=4 type='bytes' benchmarker='wrk' -0.26 % ±0.65% ±0.86% ±1.12%
http/upgrade.js n=1000 0.73 % ±2.37% ±3.16% ±4.11%
http/upgrade.js n=5 6.72 % ±8.30% ±11.05% ±14.38%

Be aware that when doing many comparisons the risk of a false-positive result increases.
In this case, there are 235 comparisons, you can thus expect the following amount of false-positive results:
11.75 false positives, when considering a 5% risk acceptance (*, **, *),
2.35 false positives, when considering a 1% risk acceptance (
, ),
0.24 false positives, when considering a 0.1% risk acceptance (
)

Looks good I think. Headlines:

  • No notable regressions - each of the small negative cases I can see are low-confidence and fit into an overall pattern of no change considering the tests around them
  • A very consistent 9.59% - 9.87% speed up in http/set-header.js test, which tests headers + res.end(body).
  • For http/simple:
    • Consistent boost around 9.5% with type=bytes, no chunking, and len up to 1024.
    • 3% boost with type=buffer, on the same small non-chunked responses.
    • Both buffer & byte body perf dropping to about 1-2% improvement for larger bodies (1MB).
    • No significant change with chunked encoding.
  • 10.48% boost to http/end-string test with 1KB, dropping to 5.59% with 16KB, down to 2.47% improvement with 1MB.
  • ~2% boost across various http/end-vs-write-end.js cases that call end(data) on different large sizes.

Looks pretty convincing to me! All approved and ready-to-go now and I think this is all just good news, so I'll commit-queue.

@pimterrypimterry added the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 24, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 214cf06 into nodejs:mainAug 24, 2026
85 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 214cf06

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 24, 2026
@pimterry
pimterry deleted the h1-clean-end-perf branch August 25, 2026 15:12
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
aduh95 pushed a commit that referenced this pull request Aug 27, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

httpIssues and PRs related to the http subsystem.needs-benchmark-ciPRs that need a benchmark CI run.needs-ciPRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants

@pimterry@nodejs-github-bot@mcollina@lpinca@anonrig@efekrskl@mertcanaltin@gurgunday@bjohansebas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

http: improve performance for end() with known-length string - #65466

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
pimterry:h1-clean-end-perf
Aug 24, 2026
Merged

http: improve performance for end() with known-length string#65466
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
pimterry:h1-clean-end-perf

Conversation

@pimterry

Copy link
Copy Markdown
Member

When you call end(data) on an outgoing HTTP request, we previously wrote the data, and then ran _send('', ...) just to trigger flushing the headers, which resulted in an extra zero-byte write call and bonus nextTick before 'finish'.

When the length is known and content-length is used (not chunking, so we don't need a terminator) we can skip this completely: prep the content-length header explicitly, and combine the finish into the existing write step.

This drops a nextTick, and goes from 2 write calls to 1 for the very common case of response.end(data) with a string, and for buffer data goes from 3 writes to 2.

In practice, in the tiny benchmark here which I think represents a very common use case (small API responses) I see this boosting HTTP RPS by up to 9% for writes up to 1KB or so. For larger responses the response write time starts to outweigh this, but I still see 3% RPS boost at 16KB. Needs autocannon to hit the rates required, you can test yourself with:

node benchmark/compare.js --old ./node-main --new ./node-pr --runs 20 --set benchmarker=autocannon --filter end-string http

Added a new test confirming the specific details and edge cases this touches, and updated one existing test which specifically asserted that end(data) triggered two writes, including the empty one.

This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/http
  • @nodejs/net
  • @nodejs/performance

@nodejs-github-botnodejs-github-bot added http Issues and PRs related to the http subsystem. needs-ci PRs that need a full CI run. labels Aug 21, 2026

@mcollinamcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@mcollina
mcollina requested a review from anonrigAugust 21, 2026 19:24
@codecov

codecovBot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.13%. Comparing base (15940ef) to head (659d6b9).
⚠️ Report is 61 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #65466 +/- ##
==========================================
- Coverage 90.14% 90.13% -0.01% 
==========================================
Files 751 751 Lines 252298 252333 +35 Branches 47446 47449 +3 ==========================================
+ Hits 227436 227451 +15 - Misses 16175 16186 +11 - Partials 8687 8696 +9 
Files with missing linesCoverage Δ
lib/_http_outgoing.js97.76% <100.00%> (-0.02%)⬇️

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

@pimterrypimterry added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 21, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 22, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@bjohansebasbjohansebas added the needs-benchmark-ci PRs that need a benchmark CI run. label Aug 22, 2026
@pimterry

Copy link
Copy Markdown
MemberAuthor

@bjohansebas benchmark label was a good suggestion. I've done a run here.

Unfortunately it seems like the microbenchmark job is broken generally (cc @nodejs/build) and all recent jobs have failed with:

++ Rscript benchmark/compare.R
Error: package or namespace load failed for ‘ggplot2’ in dyn.load(file, DLLpath = DLLpath, ...):
unable to load shared object '/usr/local/lib/R/site-library/rlang/libs/rlang.so':
/usr/local/lib/R/site-library/rlang/libs/rlang.so: undefined symbol: SETLENGTH
Execution halted

I've manually extracted the CSV from the console output to get some numbers though, and run node-benchmark-compare on the result, which gives:

Details
 confidence improvement accuracy (*) (**) (***)
http/bench-parser-fragmented.js n=100000 frags=2 len=16 -0.20 % ±1.06% ±1.42% ±1.85%
http/bench-parser-fragmented.js n=100000 frags=2 len=8 -0.01 % ±0.94% ±1.25% ±1.63%
http/bench-parser-fragmented.js n=100000 frags=4 len=16 -0.17 % ±0.77% ±1.02% ±1.33%
http/bench-parser-fragmented.js n=100000 frags=4 len=8 -0.57 % ±0.64% ±0.85% ±1.11%
http/bench-parser-fragmented.js n=100000 frags=8 len=16 -0.07 % ±0.84% ±1.12% ±1.45%
http/bench-parser-fragmented.js n=100000 frags=8 len=8 0.43 % ±0.78% ±1.04% ±1.35%
http/bench-parser.js n=100000 len=16 0.20 % ±0.93% ±1.24% ±1.61%
http/bench-parser.js n=100000 len=32 0.03 % ±0.68% ±0.90% ±1.17%
http/bench-parser.js n=100000 len=4 0.60 % ±1.08% ±1.43% ±1.86%
http/bench-parser.js n=100000 len=8 0.32 % ±1.11% ±1.47% ±1.92%
http/check_invalid_header_char.js n=1000000 input='' 1.25 % ±2.48% ±3.30% ±4.30%
http/check_invalid_header_char.js n=1000000 input='\t\t\t\t\t\t\t\t\t\tFoo bar baz' 0.39 % ±1.66% ±2.21% ±2.88%
http/check_invalid_header_char.js n=1000000 input='\x7F' * 4.92 % ±3.90% ±5.19% ±6.75%
http/check_invalid_header_char.js n=1000000 input='1' -0.41 % ±3.47% ±4.62% ±6.02%
http/check_invalid_header_char.js n=1000000 input='20091' -0.50 % ±3.85% ±5.12% ±6.66%
http/check_invalid_header_char.js n=1000000 input='close' 0.49 % ±3.34% ±4.44% ±5.78%
http/check_invalid_header_char.js n=1000000 input='en-US' -0.66 % ±3.59% ±4.77% ±6.21%
http/check_invalid_header_char.js n=1000000 input='foo\nbar' -1.88 % ±2.70% ±3.60% ±4.70%
http/check_invalid_header_char.js n=1000000 input='group_acmeair' 0.85 % ±1.82% ±2.42% ±3.16%
http/check_invalid_header_char.js n=1000000 input='gzip' -0.60 % ±3.29% ±4.37% ±5.70%
http/check_invalid_header_char.js n=1000000 input='keep-alive' -1.28 % ±2.16% ±2.88% ±3.75%
http/check_invalid_header_char.js n=1000000 input='LONG_AND_INVALID' 0.08 % ±1.13% ±1.51% ±1.97%
http/check_invalid_header_char.js n=1000000 input='private' 1.00 % ±2.68% ±3.57% ±4.65%
http/check_invalid_header_char.js n=1000000 input='SAMEORIGIN' 1.36 % ±2.81% ±3.74% ±4.88%
http/check_invalid_header_char.js n=1000000 input='Sat, 07 May 2016 16:54:48 GMT' 0.79 % ±1.41% ±1.87% ±2.44%
http/check_invalid_header_char.js n=1000000 input='text/html; charset=utf-8' -0.12 % ±1.41% ±1.88% ±2.45%
http/check_invalid_header_char.js n=1000000 input='text/plain' -1.49 % ±2.96% ±3.95% ±5.14%
http/check_invalid_header_char.js n=1000000 input='中文呢' 1.95 % ±2.71% ±3.61% ±4.69%
http/check_is_http_token.js n=1000000 key=':' -0.22 % ±2.22% ±2.96% ±3.85%
http/check_is_http_token.js n=1000000 key=':alternate-protocol' 2.82 % ±4.07% ±5.42% ±7.06%
http/check_is_http_token.js n=1000000 key='((((())))' -1.22 % ±2.75% ±3.71% ±4.91%
http/check_is_http_token.js n=1000000 key='@@' 0.52 % ±2.14% ±2.85% ±3.71%
http/check_is_http_token.js n=1000000 key='Accept-Ranges' 0.51 % ±2.25% ±2.99% ±3.90%
http/check_is_http_token.js n=1000000 key='alt-svc' -0.09 % ±2.23% ±2.97% ±3.87%
http/check_is_http_token.js n=1000000 key='alternate-protocol:' -0.94 % ±2.08% ±2.77% ±3.61%
http/check_is_http_token.js n=1000000 key='alternate-protocol' -1.19 % ±2.32% ±3.09% ±4.03%
http/check_is_http_token.js n=1000000 key='Cache-Control' -0.96 % ±2.14% ±2.85% ±3.71%
http/check_is_http_token.js n=1000000 key='Connection' 0.78 % ±2.39% ±3.19% ±4.15%
http/check_is_http_token.js n=1000000 key='Content-Encoding' * -2.76 % ±2.26% ±3.01% ±3.92%
http/check_is_http_token.js n=1000000 key='content-length' 0.93 % ±2.27% ±3.02% ±3.92%
http/check_is_http_token.js n=1000000 key='Content-Location' -0.15 % ±2.52% ±3.35% ±4.36%
http/check_is_http_token.js n=1000000 key='content-type' -0.49 % ±2.55% ±3.39% ±4.41%
http/check_is_http_token.js n=1000000 key='Content-Type' 0.46 % ±2.58% ±3.43% ±4.47%
http/check_is_http_token.js n=1000000 key='date' 0.62 % ±2.42% ±3.22% ±4.19%
http/check_is_http_token.js n=1000000 key='ETag' -2.60 % ±3.97% ±5.32% ±7.01%
http/check_is_http_token.js n=1000000 key='Expires' ** 3.69 % ±2.64% ±3.52% ±4.59%
http/check_is_http_token.js n=1000000 key='Keep-Alive' -0.03 % ±2.59% ±3.45% ±4.48%
http/check_is_http_token.js n=1000000 key='Last-Modified' -0.99 % ±2.34% ±3.12% ±4.07%
http/check_is_http_token.js n=1000000 key='location' 0.79 % ±2.44% ±3.25% ±4.23%
http/check_is_http_token.js n=1000000 key='server' 0.37 % ±2.46% ±3.27% ±4.25%
http/check_is_http_token.js n=1000000 key='Server' * 3.70 % ±3.00% ±4.00% ±5.23%
http/check_is_http_token.js n=1000000 key='status' ** -4.32 % ±3.09% ±4.13% ±5.40%
http/check_is_http_token.js n=1000000 key='TCN' -0.86 % ±1.00% ±1.33% ±1.73%
http/check_is_http_token.js n=1000000 key='Transfer-Encoding' -1.00 % ±2.32% ±3.09% ±4.02%
http/check_is_http_token.js n=1000000 key='Vary' -0.56 % ±1.47% ±1.95% ±2.54%
http/check_is_http_token.js n=1000000 key='version' 1.90 % ±2.74% ±3.65% ±4.75%
http/check_is_http_token.js n=1000000 key='x-frame-options' 0.57 % ±2.05% ±2.73% ±3.55%
http/check_is_http_token.js n=1000000 key='x-xss-protection' -1.39 % ±2.29% ±3.06% ±3.99%
http/check_is_http_token.js n=1000000 key='中文呢' -1.00 % ±4.47% ±6.01% ±7.92%
http/chunked.js duration=5 c=100 len=1 n=1 benchmarker='wrk' -0.19 % ±0.68% ±0.91% ±1.18%
http/chunked.js duration=5 c=100 len=1 n=16 benchmarker='wrk' 0.41 % ±0.78% ±1.03% ±1.35%
http/chunked.js duration=5 c=100 len=1 n=4 benchmarker='wrk' 0.61 % ±2.08% ±2.76% ±3.60%
http/chunked.js duration=5 c=100 len=1 n=8 benchmarker='wrk' 0.13 % ±0.81% ±1.07% ±1.40%
http/chunked.js duration=5 c=100 len=256 n=1 benchmarker='wrk' -0.10 % ±0.70% ±0.93% ±1.21%
http/chunked.js duration=5 c=100 len=256 n=16 benchmarker='wrk' -0.70 % ±0.73% ±0.97% ±1.26%
http/chunked.js duration=5 c=100 len=256 n=4 benchmarker='wrk' -0.58 % ±1.84% ±2.45% ±3.18%
http/chunked.js duration=5 c=100 len=256 n=8 benchmarker='wrk' 0.11 % ±0.87% ±1.16% ±1.51%
http/chunked.js duration=5 c=100 len=64 n=1 benchmarker='wrk' -0.26 % ±0.60% ±0.80% ±1.04%
http/chunked.js duration=5 c=100 len=64 n=16 benchmarker='wrk' 0.56 % ±0.63% ±0.84% ±1.10%
http/chunked.js duration=5 c=100 len=64 n=4 benchmarker='wrk' 0.08 % ±1.81% ±2.41% ±3.15%
http/chunked.js duration=5 c=100 len=64 n=8 benchmarker='wrk' 0.26 % ±0.75% ±1.00% ±1.30%
http/client-request-body.js method='end' len=1024 type='asc' dur=5 -0.06 % ±0.69% ±0.92% ±1.20%
http/client-request-body.js method='end' len=1024 type='buf' dur=5 0.01 % ±0.76% ±1.02% ±1.32%
http/client-request-body.js method='end' len=1024 type='utf' dur=5 -0.28 % ±0.59% ±0.79% ±1.03%
http/client-request-body.js method='end' len=256 type='asc' dur=5 -0.49 % ±0.67% ±0.90% ±1.17%
http/client-request-body.js method='end' len=256 type='buf' dur=5 * -0.75 % ±0.68% ±0.90% ±1.18%
http/client-request-body.js method='end' len=256 type='utf' dur=5 0.03 % ±0.62% ±0.83% ±1.08%
http/client-request-body.js method='end' len=32 type='asc' dur=5 -0.01 % ±0.56% ±0.75% ±0.98%
http/client-request-body.js method='end' len=32 type='buf' dur=5 -0.37 % ±0.60% ±0.79% ±1.03%
http/client-request-body.js method='end' len=32 type='utf' dur=5 -0.16 % ±0.62% ±0.83% ±1.08%
http/client-request-body.js method='write' len=1024 type='asc' dur=5 -0.16 % ±0.78% ±1.03% ±1.34%
http/client-request-body.js method='write' len=1024 type='buf' dur=5 -0.34 % ±0.68% ±0.90% ±1.17%
http/client-request-body.js method='write' len=1024 type='utf' dur=5 0.06 % ±0.78% ±1.04% ±1.35%
http/client-request-body.js method='write' len=256 type='asc' dur=5 0.27 % ±0.70% ±0.93% ±1.21%
http/client-request-body.js method='write' len=256 type='buf' dur=5 0.09 % ±0.76% ±1.02% ±1.32%
http/client-request-body.js method='write' len=256 type='utf' dur=5 0.49 % ±0.59% ±0.79% ±1.03%
http/client-request-body.js method='write' len=32 type='asc' dur=5 -0.40 % ±0.64% ±0.86% ±1.11%
http/client-request-body.js method='write' len=32 type='buf' dur=5 -0.21 % ±0.65% ±0.86% ±1.12%
http/client-request-body.js method='write' len=32 type='utf' dur=5 0.02 % ±0.60% ±0.79% ±1.03%
http/cluster.js duration=5 c=50 len=1024 type='buffer' benchmarker='wrk' 0.13 % ±0.46% ±0.62% ±0.81%
http/cluster.js duration=5 c=50 len=1024 type='bytes' benchmarker='wrk' -0.11 % ±0.38% ±0.50% ±0.66%
http/cluster.js duration=5 c=50 len=102400 type='buffer' benchmarker='wrk' -0.24 % ±0.49% ±0.65% ±0.85%
http/cluster.js duration=5 c=50 len=102400 type='bytes' benchmarker='wrk' 0.14 % ±0.80% ±1.06% ±1.38%
http/cluster.js duration=5 c=50 len=4 type='buffer' benchmarker='wrk' -0.23 % ±0.29% ±0.39% ±0.51%
http/cluster.js duration=5 c=50 len=4 type='bytes' benchmarker='wrk' 0.00 % ±0.51% ±0.67% ±0.88%
http/cluster.js duration=5 c=500 len=1024 type='buffer' benchmarker='wrk' ** -0.77 % ±0.50% ±0.67% ±0.87%
http/cluster.js duration=5 c=500 len=1024 type='bytes' benchmarker='wrk' -0.18 % ±0.65% ±0.86% ±1.12%
http/cluster.js duration=5 c=500 len=102400 type='buffer' benchmarker='wrk' -0.18 % ±0.59% ±0.78% ±1.02%
http/cluster.js duration=5 c=500 len=102400 type='bytes' benchmarker='wrk' 0.28 % ±0.72% ±0.95% ±1.24%
http/cluster.js duration=5 c=500 len=4 type='buffer' benchmarker='wrk' -0.25 % ±0.47% ±0.62% ±0.81%
http/cluster.js duration=5 c=500 len=4 type='bytes' benchmarker='wrk' -0.36 % ±0.52% ±0.70% ±0.91%
http/create-clientrequest.js e=1 arg='options' url='idn' 2.09 % ±7.80% ±10.38% ±13.50%
http/create-clientrequest.js e=1 arg='options' url='long' -9.98 % ±14.10% ±18.77% ±24.46%
http/create-clientrequest.js e=1 arg='options' url='wpt' -4.69 % ±6.75% ±8.98% ±11.70%
http/create-clientrequest.js e=1 arg='string' url='idn' -4.15 % ±10.23% ±13.61% ±17.71%
http/create-clientrequest.js e=1 arg='string' url='long' -0.93 % ±12.77% ±16.99% ±22.12%
http/create-clientrequest.js e=1 arg='string' url='wpt' 0.60 % ±11.36% ±15.12% ±19.68%
http/create-clientrequest.js e=1 arg='URL' url='idn' 0.87 % ±9.17% ±12.20% ±15.88%
http/create-clientrequest.js e=1 arg='URL' url='long' -5.01 % ±10.02% ±13.35% ±17.41%
http/create-clientrequest.js e=1 arg='URL' url='wpt' 1.99 % ±8.00% ±10.64% ±13.85%
http/end-string.js duration=5 c=50 len=1024 benchmarker='wrk' *** 10.48 % ±0.81% ±1.08% ±1.41%
http/end-string.js duration=5 c=50 len=102400 benchmarker='wrk' *** 2.47 % ±0.50% ±0.66% ±0.86%
http/end-string.js duration=5 c=50 len=16384 benchmarker='wrk' *** 5.59 % ±0.89% ±1.19% ±1.55%
http/end-string.js duration=5 c=50 len=4 benchmarker='wrk' *** 9.92 % ±0.82% ±1.10% ±1.43%
http/end-string.js duration=5 c=50 len=64 benchmarker='wrk' *** 8.43 % ±0.71% ±0.94% ±1.23%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='asc' benchmarker='wrk' *** 2.48 % ±0.47% ±0.62% ±0.81%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='buf' benchmarker='wrk' -0.12 % ±0.43% ±0.57% ±0.74%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='utf' benchmarker='wrk' *** 0.68 % ±0.38% ±0.51% ±0.66%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='asc' benchmarker='wrk' ** 1.19 % ±0.81% ±1.09% ±1.43%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='buf' benchmarker='wrk' *** 1.50 % ±0.59% ±0.78% ±1.01%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='utf' benchmarker='wrk' *** 2.25 % ±0.45% ±0.59% ±0.77%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='asc' benchmarker='wrk' *** 1.18 % ±0.42% ±0.56% ±0.73%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='buf' benchmarker='wrk' *** 0.92 % ±0.48% ±0.63% ±0.83%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='utf' benchmarker='wrk' *** 1.25 % ±0.32% ±0.43% ±0.56%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='asc' benchmarker='wrk' *** 1.60 % ±0.83% ±1.10% ±1.44%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='buf' benchmarker='wrk' *** 2.34 % ±0.88% ±1.18% ±1.53%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='utf' benchmarker='wrk' *** 2.95 % ±0.48% ±0.64% ±0.83%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='asc' benchmarker='wrk' -0.33 % ±0.57% ±0.77% ±1.00%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='buf' benchmarker='wrk' -0.16 % ±0.52% ±0.69% ±0.90%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='utf' benchmarker='wrk' -0.12 % ±0.36% ±0.47% ±0.62%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='asc' benchmarker='wrk' 0.07 % ±0.76% ±1.01% ±1.32%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='buf' benchmarker='wrk' -0.25 % ±0.51% ±0.68% ±0.89%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='utf' benchmarker='wrk' 0.53 % ±1.00% ±1.34% ±1.74%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='asc' benchmarker='wrk' -0.26 % ±0.61% ±0.81% ±1.06%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='buf' benchmarker='wrk' -0.05 % ±0.47% ±0.62% ±0.81%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='utf' benchmarker='wrk' -0.08 % ±0.56% ±0.74% ±0.96%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='asc' benchmarker='wrk' -0.50 % ±0.96% ±1.28% ±1.66%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='buf' benchmarker='wrk' -0.22 % ±0.71% ±0.94% ±1.23%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='utf' benchmarker='wrk' 0.10 % ±0.58% ±0.77% ±1.01%
http/headers.js group='fewHeaders' duration=5 len=1 n=10 benchmarker='wrk' -0.23 % ±0.65% ±0.86% ±1.13%
http/headers.js group='fewHeaders' duration=5 len=5 n=10 benchmarker='wrk' 0.25 % ±0.59% ±0.79% ±1.03%
http/headers.js group='manyHeaders' duration=5 len=1 n=600 benchmarker='wrk' -0.11 % ±0.86% ±1.15% ±1.49%
http/headers.js group='manyHeaders' duration=5 len=100 n=600 benchmarker='wrk' 0.22 % ±1.12% ±1.49% ±1.94%
http/headers.js group='mediumHeaders' duration=5 len=1 n=50 benchmarker='wrk' -0.28 % ±0.51% ±0.67% ±0.88%
http/headers.js group='mediumHeaders' duration=5 len=10 n=50 benchmarker='wrk' 0.04 % ±0.53% ±0.71% ±0.93%
http/http_server_for_chunky_client.js type='send' n=2000 len=1 0.19 % ±0.57% ±0.77% ±1.00%
http/http_server_for_chunky_client.js type='send' n=2000 len=128 -0.12 % ±0.59% ±0.78% ±1.02%
http/http_server_for_chunky_client.js type='send' n=2000 len=16 -0.01 % ±0.60% ±0.79% ±1.03%
http/http_server_for_chunky_client.js type='send' n=2000 len=32 0.15 % ±0.61% ±0.81% ±1.06%
http/http_server_for_chunky_client.js type='send' n=2000 len=4 0.67 % ±0.69% ±0.92% ±1.21%
http/http_server_for_chunky_client.js type='send' n=2000 len=64 -0.30 % ±0.48% ±0.64% ±0.83%
http/http_server_for_chunky_client.js type='send' n=2000 len=8 -0.50 % ±0.55% ±0.73% ±0.95%
http/http_server_for_chunky_client.js type='send' n=5 len=1 -1.39 % ±2.60% ±3.47% ±4.51%
http/http_server_for_chunky_client.js type='send' n=5 len=128 -4.15 % ±13.02% ±17.32% ±22.54%
http/http_server_for_chunky_client.js type='send' n=5 len=16 7.54 % ±10.05% ±13.50% ±17.81%
http/http_server_for_chunky_client.js type='send' n=5 len=32 0.87 % ±11.95% ±15.91% ±20.71%
http/http_server_for_chunky_client.js type='send' n=5 len=4 1.73 % ±10.57% ±14.06% ±18.30%
http/http_server_for_chunky_client.js type='send' n=5 len=64 -5.12 % ±14.17% ±18.86% ±24.56%
http/http_server_for_chunky_client.js type='send' n=5 len=8 -2.55 % ±5.92% ±7.90% ±10.32%
http/http_server_for_chunky_client.js type='send' n=50 len=1 1.27 % ±2.86% ±3.81% ±4.96%
http/http_server_for_chunky_client.js type='send' n=50 len=128 * 5.17 % ±4.13% ±5.49% ±7.15%
http/http_server_for_chunky_client.js type='send' n=50 len=16 -0.71 % ±2.69% ±3.58% ±4.67%
http/http_server_for_chunky_client.js type='send' n=50 len=32 -0.12 % ±2.72% ±3.63% ±4.74%
http/http_server_for_chunky_client.js type='send' n=50 len=4 -1.47 % ±3.06% ±4.07% ±5.29%
http/http_server_for_chunky_client.js type='send' n=50 len=64 2.04 % ±3.51% ±4.67% ±6.09%
http/http_server_for_chunky_client.js type='send' n=50 len=8 -0.08 % ±2.21% ±2.94% ±3.84%
http/http_server_for_chunky_client.js type='send' n=500 len=1 -0.08 % ±0.80% ±1.07% ±1.40%
http/http_server_for_chunky_client.js type='send' n=500 len=128 -0.38 % ±0.70% ±0.93% ±1.21%
http/http_server_for_chunky_client.js type='send' n=500 len=16 * -0.94 % ±0.83% ±1.11% ±1.45%
http/http_server_for_chunky_client.js type='send' n=500 len=32 -0.43 % ±0.83% ±1.11% ±1.45%
http/http_server_for_chunky_client.js type='send' n=500 len=4 -0.02 % ±0.71% ±0.95% ±1.24%
http/http_server_for_chunky_client.js type='send' n=500 len=64 -0.19 % ±0.93% ±1.24% ±1.62%
http/http_server_for_chunky_client.js type='send' n=500 len=8 -0.15 % ±0.71% ±0.95% ±1.23%
http/incoming_headers.js duration=5 w=0 headers=20 connections=50 benchmarker='wrk' 0.04 % ±0.81% ±1.08% ±1.42%
http/incoming_headers.js duration=5 w=6 headers=20 connections=50 benchmarker='wrk' 0.04 % ±0.64% ±0.85% ±1.11%
http/set_header.js n=1000000 value='Connection' ** -2.20 % ±1.65% ±2.19% ±2.85%
http/set_header.js n=1000000 value='Content-Length' 0.29 % ±1.71% ±2.28% ±2.97%
http/set_header.js n=1000000 value='Content-Type' 1.33 % ±1.88% ±2.51% ±3.27%
http/set_header.js n=1000000 value='Set-Cookie' 1.14 % ±1.33% ±1.77% ±2.30%
http/set_header.js n=1000000 value='Transfer-Encoding' 1.06 % ±1.33% ±1.76% ±2.30%
http/set_header.js n=1000000 value='Vary' -0.57 % ±1.72% ±2.29% ±2.99%
http/set_header.js n=1000000 value='X-Powered-By' * 1.49 % ±1.33% ±1.77% ±2.30%
http/set-header.js duration=5 res='normal' benchmarker='wrk' *** 9.74 % ±0.78% ±1.04% ±1.35%
http/set-header.js duration=5 res='setHeader' benchmarker='wrk' *** 9.87 % ±0.83% ±1.10% ±1.44%
http/set-header.js duration=5 res='setHeaderWH' benchmarker='wrk' *** 9.59 % ±0.92% ±1.22% ±1.59%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=1024 type='buffer' benchmarker='wrk' *** 2.60 % ±0.75% ±1.00% ±1.30%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=1024 type='bytes' benchmarker='wrk' *** 9.54 % ±0.74% ±0.99% ±1.28%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=102400 type='buffer' benchmarker='wrk' ** 1.23 % ±0.75% ±0.99% ±1.29%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=102400 type='bytes' benchmarker='wrk' *** 1.98 % ±0.49% ±0.65% ±0.84%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=4 type='buffer' benchmarker='wrk' *** 2.43 % ±0.76% ±1.01% ±1.31%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=4 type='bytes' benchmarker='wrk' *** 9.55 % ±0.71% ±0.95% ±1.24%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=1024 type='buffer' benchmarker='wrk' *** 3.14 % ±0.86% ±1.15% ±1.50%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=1024 type='bytes' benchmarker='wrk' *** 2.94 % ±0.78% ±1.04% ±1.35%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=102400 type='buffer' benchmarker='wrk' *** 1.55 % ±0.62% ±0.82% ±1.07%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=102400 type='bytes' benchmarker='wrk' ** 1.10 % ±0.82% ±1.09% ±1.42%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=4 type='buffer' benchmarker='wrk' *** 3.91 % ±0.83% ±1.10% ±1.44%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=4 type='bytes' benchmarker='wrk' *** 3.47 % ±0.93% ±1.23% ±1.60%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=1024 type='buffer' benchmarker='wrk' *** 3.60 % ±0.96% ±1.27% ±1.66%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=1024 type='bytes' benchmarker='wrk' *** 9.20 % ±0.99% ±1.32% ±1.72%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=102400 type='buffer' benchmarker='wrk' *** 1.28 % ±0.53% ±0.71% ±0.93%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=102400 type='bytes' benchmarker='wrk' *** 1.28 % ±0.65% ±0.87% ±1.13%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=4 type='buffer' benchmarker='wrk' *** 3.59 % ±0.96% ±1.28% ±1.67%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=4 type='bytes' benchmarker='wrk' *** 9.93 % ±1.01% ±1.35% ±1.76%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=1024 type='buffer' benchmarker='wrk' *** 2.04 % ±0.98% ±1.31% ±1.70%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=1024 type='bytes' benchmarker='wrk' *** 2.14 % ±0.82% ±1.08% ±1.41%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=102400 type='buffer' benchmarker='wrk' *** 1.74 % ±0.67% ±0.89% ±1.16%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=102400 type='bytes' benchmarker='wrk' ** 1.10 % ±0.79% ±1.05% ±1.36%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=4 type='buffer' benchmarker='wrk' *** 3.20 % ±0.94% ±1.24% ±1.62%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=4 type='bytes' benchmarker='wrk' *** 3.12 % ±0.76% ±1.01% ±1.32%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=1024 type='buffer' benchmarker='wrk' -0.19 % ±0.80% ±1.06% ±1.38%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=1024 type='bytes' benchmarker='wrk' -0.44 % ±0.95% ±1.26% ±1.65%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=102400 type='buffer' benchmarker='wrk' 0.11 % ±0.61% ±0.81% ±1.06%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=102400 type='bytes' benchmarker='wrk' * -1.19 % ±1.11% ±1.47% ±1.92%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=4 type='buffer' benchmarker='wrk' -0.23 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=4 type='bytes' benchmarker='wrk' 0.10 % ±0.75% ±1.00% ±1.30%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=1024 type='buffer' benchmarker='wrk' -0.55 % ±0.76% ±1.01% ±1.32%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=1024 type='bytes' benchmarker='wrk' 0.19 % ±0.95% ±1.27% ±1.65%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=102400 type='buffer' benchmarker='wrk' ** -1.32 % ±0.79% ±1.06% ±1.37%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=102400 type='bytes' benchmarker='wrk' 0.69 % ±1.07% ±1.42% ±1.85%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=4 type='buffer' benchmarker='wrk' 0.54 % ±0.81% ±1.07% ±1.40%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=4 type='bytes' benchmarker='wrk' 0.56 % ±0.71% ±0.95% ±1.23%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=1024 type='buffer' benchmarker='wrk' -0.48 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=1024 type='bytes' benchmarker='wrk' -0.62 % ±0.85% ±1.13% ±1.48%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=102400 type='buffer' benchmarker='wrk' -0.20 % ±0.69% ±0.92% ±1.20%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=102400 type='bytes' benchmarker='wrk' 0.43 % ±1.18% ±1.56% ±2.04%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=4 type='buffer' benchmarker='wrk' 0.29 % ±0.89% ±1.19% ±1.55%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=4 type='bytes' benchmarker='wrk' * -1.01 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=1024 type='buffer' benchmarker='wrk' -0.18 % ±0.68% ±0.90% ±1.18%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=1024 type='bytes' benchmarker='wrk' 0.09 % ±0.65% ±0.86% ±1.12%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=102400 type='buffer' benchmarker='wrk' * -0.55 % ±0.49% ±0.66% ±0.86%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=102400 type='bytes' benchmarker='wrk' 0.10 % ±0.82% ±1.09% ±1.42%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=4 type='buffer' benchmarker='wrk' 0.35 % ±0.74% ±0.98% ±1.28%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=4 type='bytes' benchmarker='wrk' -0.26 % ±0.65% ±0.86% ±1.12%
http/upgrade.js n=1000 0.73 % ±2.37% ±3.16% ±4.11%
http/upgrade.js n=5 6.72 % ±8.30% ±11.05% ±14.38%

Be aware that when doing many comparisons the risk of a false-positive result increases.
In this case, there are 235 comparisons, you can thus expect the following amount of false-positive results:
11.75 false positives, when considering a 5% risk acceptance (*, **, *),
2.35 false positives, when considering a 1% risk acceptance (
, ),
0.24 false positives, when considering a 0.1% risk acceptance (
)

Looks good I think. Headlines:

  • No notable regressions - each of the small negative cases I can see are low-confidence and fit into an overall pattern of no change considering the tests around them
  • A very consistent 9.59% - 9.87% speed up in http/set-header.js test, which tests headers + res.end(body).
  • For http/simple:
    • Consistent boost around 9.5% with type=bytes, no chunking, and len up to 1024.
    • 3% boost with type=buffer, on the same small non-chunked responses.
    • Both buffer & byte body perf dropping to about 1-2% improvement for larger bodies (1MB).
    • No significant change with chunked encoding.
  • 10.48% boost to http/end-string test with 1KB, dropping to 5.59% with 16KB, down to 2.47% improvement with 1MB.
  • ~2% boost across various http/end-vs-write-end.js cases that call end(data) on different large sizes.

Looks pretty convincing to me! All approved and ready-to-go now and I think this is all just good news, so I'll commit-queue.

@pimterrypimterry added the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 24, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 214cf06 into nodejs:mainAug 24, 2026
85 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 214cf06

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 24, 2026
@pimterry
pimterry deleted the h1-clean-end-perf branch August 25, 2026 15:12
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
aduh95 pushed a commit that referenced this pull request Aug 27, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

httpIssues and PRs related to the http subsystem.needs-benchmark-ciPRs that need a benchmark CI run.needs-ciPRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants

@pimterry@nodejs-github-bot@mcollina@lpinca@anonrig@efekrskl@mertcanaltin@gurgunday@bjohansebas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

http: improve performance for end() with known-length string - #65466

Merged
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
pimterry:h1-clean-end-perf
Aug 24, 2026
Merged

http: improve performance for end() with known-length string#65466
nodejs-github-bot merged 1 commit into
nodejs:mainfrom
pimterry:h1-clean-end-perf

Conversation

@pimterry

Copy link
Copy Markdown
Member

When you call end(data) on an outgoing HTTP request, we previously wrote the data, and then ran _send('', ...) just to trigger flushing the headers, which resulted in an extra zero-byte write call and bonus nextTick before 'finish'.

When the length is known and content-length is used (not chunking, so we don't need a terminator) we can skip this completely: prep the content-length header explicitly, and combine the finish into the existing write step.

This drops a nextTick, and goes from 2 write calls to 1 for the very common case of response.end(data) with a string, and for buffer data goes from 3 writes to 2.

In practice, in the tiny benchmark here which I think represents a very common use case (small API responses) I see this boosting HTTP RPS by up to 9% for writes up to 1KB or so. For larger responses the response write time starts to outweigh this, but I still see 3% RPS boost at 16KB. Needs autocannon to hit the rates required, you can test yourself with:

node benchmark/compare.js --old ./node-main --new ./node-pr --runs 20 --set benchmarker=autocannon --filter end-string http

Added a new test confirming the specific details and edge cases this touches, and updated one existing test which specifically asserted that end(data) triggered two writes, including the empty one.

This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/http
  • @nodejs/net
  • @nodejs/performance

@nodejs-github-botnodejs-github-bot added http Issues and PRs related to the http subsystem. needs-ci PRs that need a full CI run. labels Aug 21, 2026

@mcollinamcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@mcollina
mcollina requested a review from anonrigAugust 21, 2026 19:24
@codecov

codecovBot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.13%. Comparing base (15940ef) to head (659d6b9).
⚠️ Report is 61 commits behind head on main.

Additional details and impacted files
@@ Coverage Diff @@## main #65466 +/- ##
==========================================
- Coverage 90.14% 90.13% -0.01% 
==========================================
Files 751 751 Lines 252298 252333 +35 Branches 47446 47449 +3 ==========================================
+ Hits 227436 227451 +15 - Misses 16175 16186 +11 - Partials 8687 8696 +9 
Files with missing linesCoverage Δ
lib/_http_outgoing.js97.76% <100.00%> (-0.02%)⬇️

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

@pimterrypimterry added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 21, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 22, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@bjohansebasbjohansebas added the needs-benchmark-ci PRs that need a benchmark CI run. label Aug 22, 2026
@pimterry

Copy link
Copy Markdown
MemberAuthor

@bjohansebas benchmark label was a good suggestion. I've done a run here.

Unfortunately it seems like the microbenchmark job is broken generally (cc @nodejs/build) and all recent jobs have failed with:

++ Rscript benchmark/compare.R
Error: package or namespace load failed for ‘ggplot2’ in dyn.load(file, DLLpath = DLLpath, ...):
unable to load shared object '/usr/local/lib/R/site-library/rlang/libs/rlang.so':
/usr/local/lib/R/site-library/rlang/libs/rlang.so: undefined symbol: SETLENGTH
Execution halted

I've manually extracted the CSV from the console output to get some numbers though, and run node-benchmark-compare on the result, which gives:

Details
 confidence improvement accuracy (*) (**) (***)
http/bench-parser-fragmented.js n=100000 frags=2 len=16 -0.20 % ±1.06% ±1.42% ±1.85%
http/bench-parser-fragmented.js n=100000 frags=2 len=8 -0.01 % ±0.94% ±1.25% ±1.63%
http/bench-parser-fragmented.js n=100000 frags=4 len=16 -0.17 % ±0.77% ±1.02% ±1.33%
http/bench-parser-fragmented.js n=100000 frags=4 len=8 -0.57 % ±0.64% ±0.85% ±1.11%
http/bench-parser-fragmented.js n=100000 frags=8 len=16 -0.07 % ±0.84% ±1.12% ±1.45%
http/bench-parser-fragmented.js n=100000 frags=8 len=8 0.43 % ±0.78% ±1.04% ±1.35%
http/bench-parser.js n=100000 len=16 0.20 % ±0.93% ±1.24% ±1.61%
http/bench-parser.js n=100000 len=32 0.03 % ±0.68% ±0.90% ±1.17%
http/bench-parser.js n=100000 len=4 0.60 % ±1.08% ±1.43% ±1.86%
http/bench-parser.js n=100000 len=8 0.32 % ±1.11% ±1.47% ±1.92%
http/check_invalid_header_char.js n=1000000 input='' 1.25 % ±2.48% ±3.30% ±4.30%
http/check_invalid_header_char.js n=1000000 input='\t\t\t\t\t\t\t\t\t\tFoo bar baz' 0.39 % ±1.66% ±2.21% ±2.88%
http/check_invalid_header_char.js n=1000000 input='\x7F' * 4.92 % ±3.90% ±5.19% ±6.75%
http/check_invalid_header_char.js n=1000000 input='1' -0.41 % ±3.47% ±4.62% ±6.02%
http/check_invalid_header_char.js n=1000000 input='20091' -0.50 % ±3.85% ±5.12% ±6.66%
http/check_invalid_header_char.js n=1000000 input='close' 0.49 % ±3.34% ±4.44% ±5.78%
http/check_invalid_header_char.js n=1000000 input='en-US' -0.66 % ±3.59% ±4.77% ±6.21%
http/check_invalid_header_char.js n=1000000 input='foo\nbar' -1.88 % ±2.70% ±3.60% ±4.70%
http/check_invalid_header_char.js n=1000000 input='group_acmeair' 0.85 % ±1.82% ±2.42% ±3.16%
http/check_invalid_header_char.js n=1000000 input='gzip' -0.60 % ±3.29% ±4.37% ±5.70%
http/check_invalid_header_char.js n=1000000 input='keep-alive' -1.28 % ±2.16% ±2.88% ±3.75%
http/check_invalid_header_char.js n=1000000 input='LONG_AND_INVALID' 0.08 % ±1.13% ±1.51% ±1.97%
http/check_invalid_header_char.js n=1000000 input='private' 1.00 % ±2.68% ±3.57% ±4.65%
http/check_invalid_header_char.js n=1000000 input='SAMEORIGIN' 1.36 % ±2.81% ±3.74% ±4.88%
http/check_invalid_header_char.js n=1000000 input='Sat, 07 May 2016 16:54:48 GMT' 0.79 % ±1.41% ±1.87% ±2.44%
http/check_invalid_header_char.js n=1000000 input='text/html; charset=utf-8' -0.12 % ±1.41% ±1.88% ±2.45%
http/check_invalid_header_char.js n=1000000 input='text/plain' -1.49 % ±2.96% ±3.95% ±5.14%
http/check_invalid_header_char.js n=1000000 input='中文呢' 1.95 % ±2.71% ±3.61% ±4.69%
http/check_is_http_token.js n=1000000 key=':' -0.22 % ±2.22% ±2.96% ±3.85%
http/check_is_http_token.js n=1000000 key=':alternate-protocol' 2.82 % ±4.07% ±5.42% ±7.06%
http/check_is_http_token.js n=1000000 key='((((())))' -1.22 % ±2.75% ±3.71% ±4.91%
http/check_is_http_token.js n=1000000 key='@@' 0.52 % ±2.14% ±2.85% ±3.71%
http/check_is_http_token.js n=1000000 key='Accept-Ranges' 0.51 % ±2.25% ±2.99% ±3.90%
http/check_is_http_token.js n=1000000 key='alt-svc' -0.09 % ±2.23% ±2.97% ±3.87%
http/check_is_http_token.js n=1000000 key='alternate-protocol:' -0.94 % ±2.08% ±2.77% ±3.61%
http/check_is_http_token.js n=1000000 key='alternate-protocol' -1.19 % ±2.32% ±3.09% ±4.03%
http/check_is_http_token.js n=1000000 key='Cache-Control' -0.96 % ±2.14% ±2.85% ±3.71%
http/check_is_http_token.js n=1000000 key='Connection' 0.78 % ±2.39% ±3.19% ±4.15%
http/check_is_http_token.js n=1000000 key='Content-Encoding' * -2.76 % ±2.26% ±3.01% ±3.92%
http/check_is_http_token.js n=1000000 key='content-length' 0.93 % ±2.27% ±3.02% ±3.92%
http/check_is_http_token.js n=1000000 key='Content-Location' -0.15 % ±2.52% ±3.35% ±4.36%
http/check_is_http_token.js n=1000000 key='content-type' -0.49 % ±2.55% ±3.39% ±4.41%
http/check_is_http_token.js n=1000000 key='Content-Type' 0.46 % ±2.58% ±3.43% ±4.47%
http/check_is_http_token.js n=1000000 key='date' 0.62 % ±2.42% ±3.22% ±4.19%
http/check_is_http_token.js n=1000000 key='ETag' -2.60 % ±3.97% ±5.32% ±7.01%
http/check_is_http_token.js n=1000000 key='Expires' ** 3.69 % ±2.64% ±3.52% ±4.59%
http/check_is_http_token.js n=1000000 key='Keep-Alive' -0.03 % ±2.59% ±3.45% ±4.48%
http/check_is_http_token.js n=1000000 key='Last-Modified' -0.99 % ±2.34% ±3.12% ±4.07%
http/check_is_http_token.js n=1000000 key='location' 0.79 % ±2.44% ±3.25% ±4.23%
http/check_is_http_token.js n=1000000 key='server' 0.37 % ±2.46% ±3.27% ±4.25%
http/check_is_http_token.js n=1000000 key='Server' * 3.70 % ±3.00% ±4.00% ±5.23%
http/check_is_http_token.js n=1000000 key='status' ** -4.32 % ±3.09% ±4.13% ±5.40%
http/check_is_http_token.js n=1000000 key='TCN' -0.86 % ±1.00% ±1.33% ±1.73%
http/check_is_http_token.js n=1000000 key='Transfer-Encoding' -1.00 % ±2.32% ±3.09% ±4.02%
http/check_is_http_token.js n=1000000 key='Vary' -0.56 % ±1.47% ±1.95% ±2.54%
http/check_is_http_token.js n=1000000 key='version' 1.90 % ±2.74% ±3.65% ±4.75%
http/check_is_http_token.js n=1000000 key='x-frame-options' 0.57 % ±2.05% ±2.73% ±3.55%
http/check_is_http_token.js n=1000000 key='x-xss-protection' -1.39 % ±2.29% ±3.06% ±3.99%
http/check_is_http_token.js n=1000000 key='中文呢' -1.00 % ±4.47% ±6.01% ±7.92%
http/chunked.js duration=5 c=100 len=1 n=1 benchmarker='wrk' -0.19 % ±0.68% ±0.91% ±1.18%
http/chunked.js duration=5 c=100 len=1 n=16 benchmarker='wrk' 0.41 % ±0.78% ±1.03% ±1.35%
http/chunked.js duration=5 c=100 len=1 n=4 benchmarker='wrk' 0.61 % ±2.08% ±2.76% ±3.60%
http/chunked.js duration=5 c=100 len=1 n=8 benchmarker='wrk' 0.13 % ±0.81% ±1.07% ±1.40%
http/chunked.js duration=5 c=100 len=256 n=1 benchmarker='wrk' -0.10 % ±0.70% ±0.93% ±1.21%
http/chunked.js duration=5 c=100 len=256 n=16 benchmarker='wrk' -0.70 % ±0.73% ±0.97% ±1.26%
http/chunked.js duration=5 c=100 len=256 n=4 benchmarker='wrk' -0.58 % ±1.84% ±2.45% ±3.18%
http/chunked.js duration=5 c=100 len=256 n=8 benchmarker='wrk' 0.11 % ±0.87% ±1.16% ±1.51%
http/chunked.js duration=5 c=100 len=64 n=1 benchmarker='wrk' -0.26 % ±0.60% ±0.80% ±1.04%
http/chunked.js duration=5 c=100 len=64 n=16 benchmarker='wrk' 0.56 % ±0.63% ±0.84% ±1.10%
http/chunked.js duration=5 c=100 len=64 n=4 benchmarker='wrk' 0.08 % ±1.81% ±2.41% ±3.15%
http/chunked.js duration=5 c=100 len=64 n=8 benchmarker='wrk' 0.26 % ±0.75% ±1.00% ±1.30%
http/client-request-body.js method='end' len=1024 type='asc' dur=5 -0.06 % ±0.69% ±0.92% ±1.20%
http/client-request-body.js method='end' len=1024 type='buf' dur=5 0.01 % ±0.76% ±1.02% ±1.32%
http/client-request-body.js method='end' len=1024 type='utf' dur=5 -0.28 % ±0.59% ±0.79% ±1.03%
http/client-request-body.js method='end' len=256 type='asc' dur=5 -0.49 % ±0.67% ±0.90% ±1.17%
http/client-request-body.js method='end' len=256 type='buf' dur=5 * -0.75 % ±0.68% ±0.90% ±1.18%
http/client-request-body.js method='end' len=256 type='utf' dur=5 0.03 % ±0.62% ±0.83% ±1.08%
http/client-request-body.js method='end' len=32 type='asc' dur=5 -0.01 % ±0.56% ±0.75% ±0.98%
http/client-request-body.js method='end' len=32 type='buf' dur=5 -0.37 % ±0.60% ±0.79% ±1.03%
http/client-request-body.js method='end' len=32 type='utf' dur=5 -0.16 % ±0.62% ±0.83% ±1.08%
http/client-request-body.js method='write' len=1024 type='asc' dur=5 -0.16 % ±0.78% ±1.03% ±1.34%
http/client-request-body.js method='write' len=1024 type='buf' dur=5 -0.34 % ±0.68% ±0.90% ±1.17%
http/client-request-body.js method='write' len=1024 type='utf' dur=5 0.06 % ±0.78% ±1.04% ±1.35%
http/client-request-body.js method='write' len=256 type='asc' dur=5 0.27 % ±0.70% ±0.93% ±1.21%
http/client-request-body.js method='write' len=256 type='buf' dur=5 0.09 % ±0.76% ±1.02% ±1.32%
http/client-request-body.js method='write' len=256 type='utf' dur=5 0.49 % ±0.59% ±0.79% ±1.03%
http/client-request-body.js method='write' len=32 type='asc' dur=5 -0.40 % ±0.64% ±0.86% ±1.11%
http/client-request-body.js method='write' len=32 type='buf' dur=5 -0.21 % ±0.65% ±0.86% ±1.12%
http/client-request-body.js method='write' len=32 type='utf' dur=5 0.02 % ±0.60% ±0.79% ±1.03%
http/cluster.js duration=5 c=50 len=1024 type='buffer' benchmarker='wrk' 0.13 % ±0.46% ±0.62% ±0.81%
http/cluster.js duration=5 c=50 len=1024 type='bytes' benchmarker='wrk' -0.11 % ±0.38% ±0.50% ±0.66%
http/cluster.js duration=5 c=50 len=102400 type='buffer' benchmarker='wrk' -0.24 % ±0.49% ±0.65% ±0.85%
http/cluster.js duration=5 c=50 len=102400 type='bytes' benchmarker='wrk' 0.14 % ±0.80% ±1.06% ±1.38%
http/cluster.js duration=5 c=50 len=4 type='buffer' benchmarker='wrk' -0.23 % ±0.29% ±0.39% ±0.51%
http/cluster.js duration=5 c=50 len=4 type='bytes' benchmarker='wrk' 0.00 % ±0.51% ±0.67% ±0.88%
http/cluster.js duration=5 c=500 len=1024 type='buffer' benchmarker='wrk' ** -0.77 % ±0.50% ±0.67% ±0.87%
http/cluster.js duration=5 c=500 len=1024 type='bytes' benchmarker='wrk' -0.18 % ±0.65% ±0.86% ±1.12%
http/cluster.js duration=5 c=500 len=102400 type='buffer' benchmarker='wrk' -0.18 % ±0.59% ±0.78% ±1.02%
http/cluster.js duration=5 c=500 len=102400 type='bytes' benchmarker='wrk' 0.28 % ±0.72% ±0.95% ±1.24%
http/cluster.js duration=5 c=500 len=4 type='buffer' benchmarker='wrk' -0.25 % ±0.47% ±0.62% ±0.81%
http/cluster.js duration=5 c=500 len=4 type='bytes' benchmarker='wrk' -0.36 % ±0.52% ±0.70% ±0.91%
http/create-clientrequest.js e=1 arg='options' url='idn' 2.09 % ±7.80% ±10.38% ±13.50%
http/create-clientrequest.js e=1 arg='options' url='long' -9.98 % ±14.10% ±18.77% ±24.46%
http/create-clientrequest.js e=1 arg='options' url='wpt' -4.69 % ±6.75% ±8.98% ±11.70%
http/create-clientrequest.js e=1 arg='string' url='idn' -4.15 % ±10.23% ±13.61% ±17.71%
http/create-clientrequest.js e=1 arg='string' url='long' -0.93 % ±12.77% ±16.99% ±22.12%
http/create-clientrequest.js e=1 arg='string' url='wpt' 0.60 % ±11.36% ±15.12% ±19.68%
http/create-clientrequest.js e=1 arg='URL' url='idn' 0.87 % ±9.17% ±12.20% ±15.88%
http/create-clientrequest.js e=1 arg='URL' url='long' -5.01 % ±10.02% ±13.35% ±17.41%
http/create-clientrequest.js e=1 arg='URL' url='wpt' 1.99 % ±8.00% ±10.64% ±13.85%
http/end-string.js duration=5 c=50 len=1024 benchmarker='wrk' *** 10.48 % ±0.81% ±1.08% ±1.41%
http/end-string.js duration=5 c=50 len=102400 benchmarker='wrk' *** 2.47 % ±0.50% ±0.66% ±0.86%
http/end-string.js duration=5 c=50 len=16384 benchmarker='wrk' *** 5.59 % ±0.89% ±1.19% ±1.55%
http/end-string.js duration=5 c=50 len=4 benchmarker='wrk' *** 9.92 % ±0.82% ±1.10% ±1.43%
http/end-string.js duration=5 c=50 len=64 benchmarker='wrk' *** 8.43 % ±0.71% ±0.94% ±1.23%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='asc' benchmarker='wrk' *** 2.48 % ±0.47% ±0.62% ±0.81%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='buf' benchmarker='wrk' -0.12 % ±0.43% ±0.57% ±0.74%
http/end-vs-write-end.js duration=5 method='end' c=100 len=1048576 type='utf' benchmarker='wrk' *** 0.68 % ±0.38% ±0.51% ±0.66%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='asc' benchmarker='wrk' ** 1.19 % ±0.81% ±1.09% ±1.43%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='buf' benchmarker='wrk' *** 1.50 % ±0.59% ±0.78% ±1.01%
http/end-vs-write-end.js duration=5 method='end' c=100 len=131072 type='utf' benchmarker='wrk' *** 2.25 % ±0.45% ±0.59% ±0.77%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='asc' benchmarker='wrk' *** 1.18 % ±0.42% ±0.56% ±0.73%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='buf' benchmarker='wrk' *** 0.92 % ±0.48% ±0.63% ±0.83%
http/end-vs-write-end.js duration=5 method='end' c=100 len=262144 type='utf' benchmarker='wrk' *** 1.25 % ±0.32% ±0.43% ±0.56%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='asc' benchmarker='wrk' *** 1.60 % ±0.83% ±1.10% ±1.44%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='buf' benchmarker='wrk' *** 2.34 % ±0.88% ±1.18% ±1.53%
http/end-vs-write-end.js duration=5 method='end' c=100 len=65536 type='utf' benchmarker='wrk' *** 2.95 % ±0.48% ±0.64% ±0.83%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='asc' benchmarker='wrk' -0.33 % ±0.57% ±0.77% ±1.00%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='buf' benchmarker='wrk' -0.16 % ±0.52% ±0.69% ±0.90%
http/end-vs-write-end.js duration=5 method='write' c=100 len=1048576 type='utf' benchmarker='wrk' -0.12 % ±0.36% ±0.47% ±0.62%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='asc' benchmarker='wrk' 0.07 % ±0.76% ±1.01% ±1.32%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='buf' benchmarker='wrk' -0.25 % ±0.51% ±0.68% ±0.89%
http/end-vs-write-end.js duration=5 method='write' c=100 len=131072 type='utf' benchmarker='wrk' 0.53 % ±1.00% ±1.34% ±1.74%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='asc' benchmarker='wrk' -0.26 % ±0.61% ±0.81% ±1.06%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='buf' benchmarker='wrk' -0.05 % ±0.47% ±0.62% ±0.81%
http/end-vs-write-end.js duration=5 method='write' c=100 len=262144 type='utf' benchmarker='wrk' -0.08 % ±0.56% ±0.74% ±0.96%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='asc' benchmarker='wrk' -0.50 % ±0.96% ±1.28% ±1.66%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='buf' benchmarker='wrk' -0.22 % ±0.71% ±0.94% ±1.23%
http/end-vs-write-end.js duration=5 method='write' c=100 len=65536 type='utf' benchmarker='wrk' 0.10 % ±0.58% ±0.77% ±1.01%
http/headers.js group='fewHeaders' duration=5 len=1 n=10 benchmarker='wrk' -0.23 % ±0.65% ±0.86% ±1.13%
http/headers.js group='fewHeaders' duration=5 len=5 n=10 benchmarker='wrk' 0.25 % ±0.59% ±0.79% ±1.03%
http/headers.js group='manyHeaders' duration=5 len=1 n=600 benchmarker='wrk' -0.11 % ±0.86% ±1.15% ±1.49%
http/headers.js group='manyHeaders' duration=5 len=100 n=600 benchmarker='wrk' 0.22 % ±1.12% ±1.49% ±1.94%
http/headers.js group='mediumHeaders' duration=5 len=1 n=50 benchmarker='wrk' -0.28 % ±0.51% ±0.67% ±0.88%
http/headers.js group='mediumHeaders' duration=5 len=10 n=50 benchmarker='wrk' 0.04 % ±0.53% ±0.71% ±0.93%
http/http_server_for_chunky_client.js type='send' n=2000 len=1 0.19 % ±0.57% ±0.77% ±1.00%
http/http_server_for_chunky_client.js type='send' n=2000 len=128 -0.12 % ±0.59% ±0.78% ±1.02%
http/http_server_for_chunky_client.js type='send' n=2000 len=16 -0.01 % ±0.60% ±0.79% ±1.03%
http/http_server_for_chunky_client.js type='send' n=2000 len=32 0.15 % ±0.61% ±0.81% ±1.06%
http/http_server_for_chunky_client.js type='send' n=2000 len=4 0.67 % ±0.69% ±0.92% ±1.21%
http/http_server_for_chunky_client.js type='send' n=2000 len=64 -0.30 % ±0.48% ±0.64% ±0.83%
http/http_server_for_chunky_client.js type='send' n=2000 len=8 -0.50 % ±0.55% ±0.73% ±0.95%
http/http_server_for_chunky_client.js type='send' n=5 len=1 -1.39 % ±2.60% ±3.47% ±4.51%
http/http_server_for_chunky_client.js type='send' n=5 len=128 -4.15 % ±13.02% ±17.32% ±22.54%
http/http_server_for_chunky_client.js type='send' n=5 len=16 7.54 % ±10.05% ±13.50% ±17.81%
http/http_server_for_chunky_client.js type='send' n=5 len=32 0.87 % ±11.95% ±15.91% ±20.71%
http/http_server_for_chunky_client.js type='send' n=5 len=4 1.73 % ±10.57% ±14.06% ±18.30%
http/http_server_for_chunky_client.js type='send' n=5 len=64 -5.12 % ±14.17% ±18.86% ±24.56%
http/http_server_for_chunky_client.js type='send' n=5 len=8 -2.55 % ±5.92% ±7.90% ±10.32%
http/http_server_for_chunky_client.js type='send' n=50 len=1 1.27 % ±2.86% ±3.81% ±4.96%
http/http_server_for_chunky_client.js type='send' n=50 len=128 * 5.17 % ±4.13% ±5.49% ±7.15%
http/http_server_for_chunky_client.js type='send' n=50 len=16 -0.71 % ±2.69% ±3.58% ±4.67%
http/http_server_for_chunky_client.js type='send' n=50 len=32 -0.12 % ±2.72% ±3.63% ±4.74%
http/http_server_for_chunky_client.js type='send' n=50 len=4 -1.47 % ±3.06% ±4.07% ±5.29%
http/http_server_for_chunky_client.js type='send' n=50 len=64 2.04 % ±3.51% ±4.67% ±6.09%
http/http_server_for_chunky_client.js type='send' n=50 len=8 -0.08 % ±2.21% ±2.94% ±3.84%
http/http_server_for_chunky_client.js type='send' n=500 len=1 -0.08 % ±0.80% ±1.07% ±1.40%
http/http_server_for_chunky_client.js type='send' n=500 len=128 -0.38 % ±0.70% ±0.93% ±1.21%
http/http_server_for_chunky_client.js type='send' n=500 len=16 * -0.94 % ±0.83% ±1.11% ±1.45%
http/http_server_for_chunky_client.js type='send' n=500 len=32 -0.43 % ±0.83% ±1.11% ±1.45%
http/http_server_for_chunky_client.js type='send' n=500 len=4 -0.02 % ±0.71% ±0.95% ±1.24%
http/http_server_for_chunky_client.js type='send' n=500 len=64 -0.19 % ±0.93% ±1.24% ±1.62%
http/http_server_for_chunky_client.js type='send' n=500 len=8 -0.15 % ±0.71% ±0.95% ±1.23%
http/incoming_headers.js duration=5 w=0 headers=20 connections=50 benchmarker='wrk' 0.04 % ±0.81% ±1.08% ±1.42%
http/incoming_headers.js duration=5 w=6 headers=20 connections=50 benchmarker='wrk' 0.04 % ±0.64% ±0.85% ±1.11%
http/set_header.js n=1000000 value='Connection' ** -2.20 % ±1.65% ±2.19% ±2.85%
http/set_header.js n=1000000 value='Content-Length' 0.29 % ±1.71% ±2.28% ±2.97%
http/set_header.js n=1000000 value='Content-Type' 1.33 % ±1.88% ±2.51% ±3.27%
http/set_header.js n=1000000 value='Set-Cookie' 1.14 % ±1.33% ±1.77% ±2.30%
http/set_header.js n=1000000 value='Transfer-Encoding' 1.06 % ±1.33% ±1.76% ±2.30%
http/set_header.js n=1000000 value='Vary' -0.57 % ±1.72% ±2.29% ±2.99%
http/set_header.js n=1000000 value='X-Powered-By' * 1.49 % ±1.33% ±1.77% ±2.30%
http/set-header.js duration=5 res='normal' benchmarker='wrk' *** 9.74 % ±0.78% ±1.04% ±1.35%
http/set-header.js duration=5 res='setHeader' benchmarker='wrk' *** 9.87 % ±0.83% ±1.10% ±1.44%
http/set-header.js duration=5 res='setHeaderWH' benchmarker='wrk' *** 9.59 % ±0.92% ±1.22% ±1.59%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=1024 type='buffer' benchmarker='wrk' *** 2.60 % ±0.75% ±1.00% ±1.30%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=1024 type='bytes' benchmarker='wrk' *** 9.54 % ±0.74% ±0.99% ±1.28%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=102400 type='buffer' benchmarker='wrk' ** 1.23 % ±0.75% ±0.99% ±1.29%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=102400 type='bytes' benchmarker='wrk' *** 1.98 % ±0.49% ±0.65% ±0.84%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=4 type='buffer' benchmarker='wrk' *** 2.43 % ±0.76% ±1.01% ±1.31%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=1 len=4 type='bytes' benchmarker='wrk' *** 9.55 % ±0.71% ±0.95% ±1.24%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=1024 type='buffer' benchmarker='wrk' *** 3.14 % ±0.86% ±1.15% ±1.50%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=1024 type='bytes' benchmarker='wrk' *** 2.94 % ±0.78% ±1.04% ±1.35%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=102400 type='buffer' benchmarker='wrk' *** 1.55 % ±0.62% ±0.82% ±1.07%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=102400 type='bytes' benchmarker='wrk' ** 1.10 % ±0.82% ±1.09% ±1.42%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=4 type='buffer' benchmarker='wrk' *** 3.91 % ±0.83% ±1.10% ±1.44%
http/simple.js duration=5 chunkedEnc=0 c=50 chunks=4 len=4 type='bytes' benchmarker='wrk' *** 3.47 % ±0.93% ±1.23% ±1.60%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=1024 type='buffer' benchmarker='wrk' *** 3.60 % ±0.96% ±1.27% ±1.66%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=1024 type='bytes' benchmarker='wrk' *** 9.20 % ±0.99% ±1.32% ±1.72%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=102400 type='buffer' benchmarker='wrk' *** 1.28 % ±0.53% ±0.71% ±0.93%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=102400 type='bytes' benchmarker='wrk' *** 1.28 % ±0.65% ±0.87% ±1.13%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=4 type='buffer' benchmarker='wrk' *** 3.59 % ±0.96% ±1.28% ±1.67%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=1 len=4 type='bytes' benchmarker='wrk' *** 9.93 % ±1.01% ±1.35% ±1.76%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=1024 type='buffer' benchmarker='wrk' *** 2.04 % ±0.98% ±1.31% ±1.70%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=1024 type='bytes' benchmarker='wrk' *** 2.14 % ±0.82% ±1.08% ±1.41%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=102400 type='buffer' benchmarker='wrk' *** 1.74 % ±0.67% ±0.89% ±1.16%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=102400 type='bytes' benchmarker='wrk' ** 1.10 % ±0.79% ±1.05% ±1.36%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=4 type='buffer' benchmarker='wrk' *** 3.20 % ±0.94% ±1.24% ±1.62%
http/simple.js duration=5 chunkedEnc=0 c=500 chunks=4 len=4 type='bytes' benchmarker='wrk' *** 3.12 % ±0.76% ±1.01% ±1.32%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=1024 type='buffer' benchmarker='wrk' -0.19 % ±0.80% ±1.06% ±1.38%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=1024 type='bytes' benchmarker='wrk' -0.44 % ±0.95% ±1.26% ±1.65%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=102400 type='buffer' benchmarker='wrk' 0.11 % ±0.61% ±0.81% ±1.06%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=102400 type='bytes' benchmarker='wrk' * -1.19 % ±1.11% ±1.47% ±1.92%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=4 type='buffer' benchmarker='wrk' -0.23 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=1 len=4 type='bytes' benchmarker='wrk' 0.10 % ±0.75% ±1.00% ±1.30%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=1024 type='buffer' benchmarker='wrk' -0.55 % ±0.76% ±1.01% ±1.32%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=1024 type='bytes' benchmarker='wrk' 0.19 % ±0.95% ±1.27% ±1.65%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=102400 type='buffer' benchmarker='wrk' ** -1.32 % ±0.79% ±1.06% ±1.37%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=102400 type='bytes' benchmarker='wrk' 0.69 % ±1.07% ±1.42% ±1.85%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=4 type='buffer' benchmarker='wrk' 0.54 % ±0.81% ±1.07% ±1.40%
http/simple.js duration=5 chunkedEnc=1 c=50 chunks=4 len=4 type='bytes' benchmarker='wrk' 0.56 % ±0.71% ±0.95% ±1.23%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=1024 type='buffer' benchmarker='wrk' -0.48 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=1024 type='bytes' benchmarker='wrk' -0.62 % ±0.85% ±1.13% ±1.48%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=102400 type='buffer' benchmarker='wrk' -0.20 % ±0.69% ±0.92% ±1.20%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=102400 type='bytes' benchmarker='wrk' 0.43 % ±1.18% ±1.56% ±2.04%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=4 type='buffer' benchmarker='wrk' 0.29 % ±0.89% ±1.19% ±1.55%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=1 len=4 type='bytes' benchmarker='wrk' * -1.01 % ±0.80% ±1.07% ±1.39%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=1024 type='buffer' benchmarker='wrk' -0.18 % ±0.68% ±0.90% ±1.18%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=1024 type='bytes' benchmarker='wrk' 0.09 % ±0.65% ±0.86% ±1.12%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=102400 type='buffer' benchmarker='wrk' * -0.55 % ±0.49% ±0.66% ±0.86%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=102400 type='bytes' benchmarker='wrk' 0.10 % ±0.82% ±1.09% ±1.42%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=4 type='buffer' benchmarker='wrk' 0.35 % ±0.74% ±0.98% ±1.28%
http/simple.js duration=5 chunkedEnc=1 c=500 chunks=4 len=4 type='bytes' benchmarker='wrk' -0.26 % ±0.65% ±0.86% ±1.12%
http/upgrade.js n=1000 0.73 % ±2.37% ±3.16% ±4.11%
http/upgrade.js n=5 6.72 % ±8.30% ±11.05% ±14.38%

Be aware that when doing many comparisons the risk of a false-positive result increases.
In this case, there are 235 comparisons, you can thus expect the following amount of false-positive results:
11.75 false positives, when considering a 5% risk acceptance (*, **, *),
2.35 false positives, when considering a 1% risk acceptance (
, ),
0.24 false positives, when considering a 0.1% risk acceptance (
)

Looks good I think. Headlines:

  • No notable regressions - each of the small negative cases I can see are low-confidence and fit into an overall pattern of no change considering the tests around them
  • A very consistent 9.59% - 9.87% speed up in http/set-header.js test, which tests headers + res.end(body).
  • For http/simple:
    • Consistent boost around 9.5% with type=bytes, no chunking, and len up to 1024.
    • 3% boost with type=buffer, on the same small non-chunked responses.
    • Both buffer & byte body perf dropping to about 1-2% improvement for larger bodies (1MB).
    • No significant change with chunked encoding.
  • 10.48% boost to http/end-string test with 1KB, dropping to 5.59% with 16KB, down to 2.47% improvement with 1MB.
  • ~2% boost across various http/end-vs-write-end.js cases that call end(data) on different large sizes.

Looks pretty convincing to me! All approved and ready-to-go now and I think this is all just good news, so I'll commit-queue.

@pimterrypimterry added the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 24, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 214cf06 into nodejs:mainAug 24, 2026
85 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 214cf06

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 24, 2026
@pimterry
pimterry deleted the h1-clean-end-perf branch August 25, 2026 15:12
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
aduh95 pushed a commit that referenced this pull request Aug 27, 2026
This boosts RPS performance for the common API case where you call
`res.end(data)` with the entire response by up to 9%.
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: #65466
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

httpIssues and PRs related to the http subsystem.needs-benchmark-ciPRs that need a benchmark CI run.needs-ciPRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants

@pimterry@nodejs-github-bot@mcollina@lpinca@anonrig@efekrskl@mertcanaltin@gurgunday@bjohansebas