GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — quic: apply multiple quic performance and packet handling improvements by jasnell · Pull Request #63267 · nodejs/node

Conversation

@jasnell

@jasnell jasnell commented May 12, 2026

Copy link
Copy Markdown
Member

A number of planned backend changes and improvements in the packet handling. Yields a net performance improvement of around 10% higher rps. Sets us up to be able to better leverage libuv/libuv#5116 if/when that lands (@santigimeno @saghul fyi) which will provide an even larger perf boost. Fixes a bug while we're at it.

@nodejs/quic

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@nodejs-github-bot

nodejs-github-bot commented May 12, 2026

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/quic
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@jasnell
jasnell requested review from Qard and pimterry May 12, 2026 18:52
@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. lib / src Issues and PRs involving general changes in the lib/ or src/ directories. needs-ci PRs that need a full CI run. labels May 12, 2026
@jasnell jasnell changed the title meta: add additional gitignore entries quic: apply multiple quic performance and packet handling improvements May 12, 2026
@nodejs-github-bot

This comment was marked as outdated.

Sign in to view
@codecov

This comment was marked as outdated.

Sign in to view
@nodejs-github-bot

This comment was marked as outdated.

Sign in to view
@jasnell
jasnell force-pushed the jasnell/quic-backend-improvements branch from e921c66 to ef9e8da Compare May 13, 2026 03:54
@nodejs-github-bot

This comment was marked as outdated.

Sign in to view
@nodejs-github-bot

This comment was marked as outdated.

Sign in to view
@jasnell
jasnell requested a review from mcollina May 14, 2026 13:37
@jasnell jasnell added the experimental Issues and PRs related to experimental features. label May 14, 2026
@jasnell
jasnell force-pushed the jasnell/quic-backend-improvements branch 4 times, most recently from bbe613a to 6ef4e68 Compare May 15, 2026 13:41
@Ethan-Arrowood

Ethan-Arrowood commented May 15, 2026

Copy link
Copy Markdown
Contributor

This diff is quite large. Can you provide a short summary of the most relevant parts? Such as maybe notable performance improvement areas, the bug fix, and whatever else seems relevant. That'll help expedite reviews, thanks!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@jasnell
jasnell force-pushed the jasnell/quic-backend-improvements branch 2 times, most recently from bfc3adc to c9c714e Compare May 15, 2026 16:56
@jasnell jasnell mentioned this pull request May 15, 2026
quic: Current implementation results in tiny Uint8Arrays in streaming mode #63303
Closed
@jasnell

jasnell commented May 15, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

Just an idea of where we're at... running a local 'hello world' benchmark using h2load as the client driver on the same 88 core machine... 4 runs with 100,000 requests over 100 concurrent connections:

image

The rps is not as high as I'd like and http/1 still beats it by a long way but it's a solid result for current state.

The primary performance bottleneck right now is the JS side, GC, and the C++/JS boundary cross. We lose a fair amount of throughput in the context switching.

My current goal is to get the per-request down to 10 microseconds.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@jasnell

jasnell commented May 15, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

Ok, with a bit of perf tunning and mangling with both h2load options and v8 perf tuning options on the server, with a node binary built with pointer compression enabled... we can get ~101k-102k rps. Still slower than http/1, on par with http/2 when pointer compression is enabled. Overall a great result given that I've only just started the perf tuning of the implementation.

/tmp/opencode/local/bin/h2load --h3 -n 200000 -c 5 -w 26 -W 30 -m 10 -D 2 https://127.0.0.1:4433
starting benchmark...
spawning thread #0: 5 total client(s). Timing-based test with 0s of warm-up time and 2s of main duration for measurements.
Warm-up started for thread #0.
progress: 20% of clients started
progress: 40% of clients started
progress: 60% of clients started
progress: 80% of clients started
progress: 100% of clients started
Warm-up phase is over for thread #0.
Main benchmark duration is started for thread #0.
TLS Protocol: TLSv1.3
Cipher: TLS_AES_128_GCM_SHA256
Certificate: ECDSA P-256 256 bits
Negotiated Group: X25519
Resumption: no
Application protocol: h3
Main benchmark duration is over for thread #0. Stopping all clients.
Stopped all clients for thread #0

finished in 2.02s, 102130.00 req/s, 2.23MB/s
requests: 204260 total, 204310 started, 204260 done, 204260 succeeded, 0 failed, 0 errored, 0 timeout
status codes: 204260 2xx, 0 3xx, 0 4xx, 0 5xx
traffic: 4.46MB (4676960) total, 797.97KB (817120) headers (space savings 87.50%), 2.14MB (2247080) data
UDP datagram: 33273 sent, 20462 received
                 min         max         median      p95         p99         mean        sd         +/- sd
request     :      150us     53.98ms       435us       490us       813us       487us      1.28ms    99.59%
connect     :     4.89ms      5.64ms      5.30ms      5.64ms      5.64ms      5.28ms       295us    60.00%
TTFB        :     8.11ms      8.25ms      8.18ms      8.25ms      8.25ms      8.18ms        54us    60.00%
req/s       :   20402.15    20442.34    20417.92    20442.34    20442.34    20421.97       17.40    60.00%
min RTT     :       22us       115us        38us       115us       115us        57us        40us    80.00%
smoothed RTT:       86us       226us       164us       226us       226us       163us        60us    60.00%
packets sent:       6219        7436        6373        7436        7436     6656.60      545.25    80.00%
packets recv:       4092        4099        4092        4099        4099     4094.40        3.36    80.00%
packets lost:          0           0           0           0           0        0.00        0.00   100.00%
GRO packets :          1           1           1           1           1        1.00        0.00   100.00%
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

jasnell added 5 commits May 15, 2026 16:08
@jasnell
meta: add additional gitignore entries
22c2e34
Signed-off-by: James M Snell <[email protected]>
@jasnell
quic: improve backend quic packet processing
cabae1e
Use a uv_check_t on BindingData to process outbound
pending packet send, and use TrySend for actually sending
packets when possible. Results in an 8% improvement in
req/s and ~24% improvement in p95 latency.

Also sets us up better for future improvements in
libuv if the changes proposed in libuv/libuv#5116
are accepted.

Signed-off-by: James M Snell <[email protected]>
Assisted-by: Opencode:Opus 4.6
@jasnell
test: fixup quic tests
5360171
Signed-off-by: James M Snell <[email protected]>
@jasnell
quic: improve batching of packet sending
6011429
Improves overall performance and sets us up for eventual
support for GRO/GSO batching in libuv in the future.

Signed-off-by: James M Snell <[email protected]>
Assisted-by: Opencode:Opus 4.6
@jasnell
quic: add support for future ECN marking
3e09dd6
Set up for when libuv eventually supports ECN marking.
Pass the ECN marking stuff into ngtcp2.

Signed-off-by: James M Snell <[email protected]>
Assisted-by: Opencode:Opus 4.6
@jasnell jasnell closed this May 21, 2026
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
meta: add additional gitignore entries
bc4c457
Signed-off-by: James M Snell <[email protected]>
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: improve backend quic packet processing
fe3639a
Use a uv_check_t on BindingData to process outbound
pending packet send, and use TrySend for actually sending
packets when possible. Results in an 8% improvement in
req/s and ~24% improvement in p95 latency.

Also sets us up better for future improvements in
libuv if the changes proposed in libuv/libuv#5116
are accepted.

Signed-off-by: James M Snell <[email protected]>
Assisted-by: Opencode:Opus 4.6
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
test: fixup quic tests
935468a
Signed-off-by: James M Snell <[email protected]>
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: improve batching of packet sending
2b3ff8a
Improves overall performance and sets us up for eventual
support for GRO/GSO batching in libuv in the future.

Signed-off-by: James M Snell <[email protected]>
Assisted-by: Opencode:Opus 4.6
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: add support for future ECN marking
9560084
Set up for when libuv eventually supports ECN marking.
Pass the ECN marking stuff into ngtcp2.

Signed-off-by: James M Snell <[email protected]>
Assisted-by: Opencode:Opus 4.6
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: cache the timestamp on send and receive
aec1e17
Signed-off-by: James M Snell <[email protected]>
Assisted-by: Opencode:Opus 4.6
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: eliminate per-received datagram allocation
5025e85
Signed-off-by: James M Snell <[email protected]>
Assisted-by: Opencode:Opus 4.6
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: fix crash in early handshake failure
24e9f4f
Signed-off-by: James M Snell <[email protected]>
Assisted-by: Opencode:Opus 4.6
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: fixup linting issue after other changes
b171f39
Signed-off-by: James M Snell <[email protected]>
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: implement rate limiting for version nego and immediate close
5622701
Signed-off-by: James M Snell <[email protected]>
Assisted-by: Opencode:Opus 4.6
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: add handshake timeout and default connection limits
9543043
Signed-off-by: James M Snell <[email protected]>
Assisted-by: Opencode:Opus 4.6
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: add aliased struct arenas
5e38946
Every stream, session, and endpoint creates aliased
structs for stats and state. These were creating
v8::ArrayBuffer allocations and views for each instance,
which is expensive. This adds a new arena mechanism
for AliasedStructs that allocates in pages and allows
Streams and Sessions to share the same underlying
ArrayBuffer for their stats and state. Since these
are never exposed to users, this is safe and results
in a significant reduction in allocation counts.

Each arena maintains a freelist of pages, where each
page is a max of 16KB bytes. Pages are lazily allocated
and freed as needed. Each slot in the arena corresponds
to a single struct instance, and the slot index is
used to calculate the byte offset within the page for
that struct's view.

The perf improvement is modest but measurable. The
key benefit is in reduced memory fragmentation and GC
overhead.

Signed-off-by: James M Snell <[email protected]>
Assisted-by: Opencode:Opus 4.6
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: improve internal structure of QuicStream
0045dc3
Signed-off-by: James M Snell <[email protected]>
Assisted-by: Opencode:Opus 4.6
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: improve the quic js structure
378dbf0
* Adds invalid this protections in the stats classes
* Collects internal private fields into a single private symbol
  to reduce the number of private field accesses
* Adds and corrects isQuic* class checks
* Preserve stream id and direction after destroy
* Improve stats close snapshotting
* Fixes a handful of other bugs and doc issues

Signed-off-by: James M Snell <[email protected]>
Assisted-by: Opencode:Opus 4.6
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: fix UAF in Application::OnTimeout()
fd00e0a
Signed-off-by: James M Snell <[email protected]>
Assisted-by: Opencode:Opus 4.6
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: fixup UAFs in bindingdata, streams, and app
f940d6b
Signed-off-by: James M Snell <[email protected]>
Assisted-by: Opencode:Opus 4.6
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: fix premature unref of endpoint when listening
9bc875e
Signed-off-by: James M Snell <[email protected]>
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: fixup some v8:: qualifiers
6cffc93
Signed-off-by: James M Snell <[email protected]>
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: fix tests that are missing serverEndpoint close
ea5f372
Signed-off-by: James M Snell <[email protected]>
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: apply multiple additional minor improvements
f9a6a2f
Signed-off-by: James M Snell <[email protected]>
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: coalesce received data into fewer buffers
9a2afff
Signed-off-by: James M Snell <[email protected]>
Assisted-by: Opencode:Opus 4.6
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
aduh95 pushed a commit that referenced this pull request May 22, 2026
@jasnell @aduh95
quic: add reusePort option to QuicEndpoint
409460f
Signed-off-by: James M Snell <[email protected]>
Assisted-by: Opencode:Opus 4.6
PR-URL: #63267
Reviewed-By: Matteo Collina <[email protected]>
@github-actions github-actions Bot mentioned this pull request May 30, 2026
2026-06-01, Version 26.3.0 (Current) #63664
Merged
@github-actions github-actions Bot mentioned this pull request Jun 19, 2026
2026-06-19, Version 24.18.0 'Krypton' (LTS) #64001
Closed
@martenrichter

martenrichter commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

@jasnell: Can I ask something about this PR and the performance optimization?
As I understood it, it should coalesce incoming data.
I am currently running on my webtransport branch a test against a quiche wt server. There are of course some modifications, but it is basically the same code path that every serverside h3 data stream data enters (ReceiveData) in the client.
The test sends many 1024 bytes over the line and ReceiveData gets them from the parser in100 bytes packages, which are passed down to the js stream. The performance is so poor that my test fails on timeout. (It is actually this one https://github.com/fails-components/webtransport/blob/08f95586a949463c8b2f502cde59f166deeee996/test/bidirectional-streams.spec.js#L131, but I see the 100 bytes also at other tests).
So I guess the coalescing does not work for the http3 route.

I do not know if it is the parser of nghttp3 that changes the calling pattern, or it is something else.
(I do not have a generic test yet, I have just discovered it here, and I thought before opening an issue, I would ask here as it is related.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@martenrichter

martenrichter commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

I found the underlying cause. I have drafted an issue #64035

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@sxa sxa mentioned this pull request Jun 22, 2026
2026-06-23, Version 24.18.0 'Krypton' (LTS) #64062
Merged
@aduh95 aduh95 mentioned this pull request Jul 22, 2026
[v24.x backport] node:stream/iter and QUIC backports #64675
Closed
@github-actions github-actions Bot mentioned this pull request Aug 21, 2026
2026-08-26, Version 24.20.0 'Krypton' (LTS) #65461
Merged
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@mcollina mcollina mcollina approved these changes
@Qard Qard Awaiting requested review from Qard
@pimterry pimterry Awaiting requested review from pimterry
+1 more reviewer
@martenrichter martenrichter martenrichter left review comments
Reviewers whose approvals may not affect merge requirements

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

author ready PRs with CI started, the required approvals, and no outstanding review comments. c++ Issues and PRs that require attention from people who are familiar with C++. experimental Issues and PRs related to experimental features. lib / src Issues and PRs involving general changes in the lib/ or src/ directories. needs-ci PRs that need a full CI run.

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

5 participants

@jasnell @nodejs-github-bot @Ethan-Arrowood @martenrichter @mcollina
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.