Skip to content

perf(websocket): unroll client frame masking - #5809

Open
dexhunter wants to merge 1 commit into
nodejs:mainfrom
dexhunter:perf/websocket-mask-unroll
Open

perf(websocket): unroll client frame masking#5809
dexhunter wants to merge 1 commit into
nodejs:mainfrom
dexhunter:perf/websocket-mask-unroll

Conversation

@dexhunter

@dexhunter dexhunter commented Sep 12, 2026

Copy link
Copy Markdown

This relates to...

Existing issues #3201 and #2927.

Rationale

Client WebSocket frames are masked before they are written. The masking path currently performs one loop iteration per byte. This change keeps the existing mask generation and wire format, while processing eight bytes per iteration and handling the remaining bytes with the existing byte-wise semantics.

Changes

  • Unroll the masking loop with four preloaded mask bytes.
  • Keep the existing mask generation, frame headers, caller-buffer behavior, and byte tail unchanged.
  • Add coverage for short, boundary, aligned, unaligned, binary, and UTF-8 text payloads.

Features

N/A

Bug Fixes

Reduces the CPU work in the maintained WebSocket masking path without changing frame semantics.

Breaking Changes and Deprecations

N/A

Validation

  • node --test test/websocket/frame.js: 3 passed.
  • npm run lint: passed.
  • The WebSocket suite reported 132 passed, 5 failed, and 2 cancelled. The H2 failures and 180-second timeouts reproduce on the clean base and are retained as baseline/environment failures; the suite is not presented as fully green.
  • Independent correctness-checking echo measurements used the maintained 256 KiB WebSocket workload with Node v22.23.1, ws 8.20.1, loopback, no compression, one connection, and one in-flight message. The five paired runs used AB BA AB BA AB order, with two seconds of warmup and one second of measurement per cell. The primary binary median of per-run p50 values changed from 876.749 µs to 797.448 µs (-9.045%). All five paired rows improved; median p99 improved 3.915%, CPU time improved 9.426%, and the small-payload controls were flat.
  • These are short-window measurements on a shared host and cover the WebSocket masking path only; they do not claim an improvement for HTTP or Fetch.
  • Weco trajectory

Status

Refs nodejs#3201, nodejs#2927

Co-Authored-By: Aiden <aiden@weco.ai>
@mcollina

Copy link
Copy Markdown
Member

@tsctx PTAL

@codecov-commenter

codecov-commenter commented Sep 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.50%. Comparing base (1801a3d) to head (e8c2318).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5809      +/-   ##
==========================================
- Coverage   93.50%   93.50%   -0.01%     
==========================================
  Files         110      110              
  Lines       39521    39544      +23     
==========================================
+ Hits        36954    36974      +20     
- Misses       2567     2570       +3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 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.

@KhafraDev

Copy link
Copy Markdown
Member

The title of this PR is "perf" but there are no benchmarks nor benchmark results.

@tsctx
tsctx requested a lite review from Copilot September 13, 2026 22:37
@tsctx
tsctx removed the request for review from Copilot September 13, 2026 22:39
@tsctx tsctx closed this Sep 13, 2026
@tsctx tsctx reopened this Sep 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants