You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: update README to reflect current architecture
- Replace SSE2-only description with tiered AVX-512/AVX2/SSE2 dispatch
- Add performance table with benchmarks vs bufferutil
- Document all operations: mask, unmask, SHA-1, base64, CRC-32C,
UTF-8 validation, findHeader, batch API
- Update architecture diagram: V8 C++ API bridge (not N-API),
assembly layer with all .asm files and their dispatch tiers
- Document CPU feature detection (cpu_tier, cpu_features, nt_threshold)
- Update file structure to include all current source files
- Update comparison table vs bufferutil
- Add usage examples for new operations
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
**WebSocket frame masking in hand-written x86-64 assembly with SSE2 SIMD.**
7
+
**WebSocket acceleration in hand-written x86-64 assembly with tiered SIMD dispatch (AVX-512 / AVX2 / SSE2).**
8
8
9
-
A drop-in replacement for [`bufferutil`](https://github.com/websockets/bufferutil) — the native addon that makes the [`ws`](https://github.com/websockets/ws) WebSocket library fast. Instead of C, the hot path is written in NASM assembly with SSE2 vectorized XOR operations.
9
+
A drop-in replacement for [`bufferutil`](https://github.com/websockets/bufferutil) — the native addon that makes the [`ws`](https://github.com/websockets/ws) WebSocket library fast. Instead of C, the hot paths are written in NASM assembly with multi-tier SIMD vectorization, non-temporal memory paths for large payloads, and opmask branchless tails on AVX-512.
10
10
11
11
## Why?
12
12
13
-
The WebSocket protocol (RFC 6455 §5.3) requires that every client-to-server frame be masked with a 4-byte key via XOR. This is a tight loop that runs on every single message. The `ws` library delegates this to `bufferutil`, which implements it in C. This project replaces that C with hand-tuned assembly.
13
+
The WebSocket protocol (RFC 6455 §5.3) requires that every client-to-server frame be masked with a 4-byte key via XOR. This is a tight loop that runs on every single message. The `ws` library delegates this to `bufferutil`, which implements it in C. This project replaces that C with hand-tuned assembly that adapts to your CPU's capabilities at runtime.
14
+
15
+
## Performance
16
+
17
+
Benchmarked on AMD Ryzen 9 7950X3D (Zen 4, AVX-512) vs `bufferutil` (C):
18
+
19
+
| Operation | Speedup vs bufferutil | Peak throughput |
On Windows and macOS, `npm install` will compile the C layer only. The assembly SIMD paths are Linux x86-64 exclusive. The pure JavaScript fallback is used automatically on other platforms.
121
+
Prerequisites: **Linux x86-64** with `nasm` for assembly SIMD paths. On Windows and macOS, the C fallback (`ws_fallback.c`) provides AVX2/SSE2/scalar dispatch automatically.
| Portability | Any platform with C compiler | Linux x86-64 (C fallback elsewhere) |
142
211
143
-
## Relevant to Meteor/DDP
212
+
## CPU feature detection
144
213
145
-
If you're running Meteor.js, every DDP message (method calls, subscriptions, collection updates) goes through WebSocket framing. On a busy system with hundreds of concurrent connections, the masking loop runs thousands of times per second. Shaving microseconds here compounds into meaningful CPU savings.
214
+
At module load, `_init_cpu_features()`runs CPUID to detect:
146
215
147
-
To integrate with Meteor's internal WebSocket handling:
-**nt_threshold**: 50% of L3 cache size (auto-detected via cache topology CPUID leaves)
148
219
149
-
```javascript
150
-
// server/startup.js
151
-
// Meteor uses sockjs by default, but if using raw ws:
152
-
import { WebApp } from"meteor/webapp";
220
+
All dispatch is runtime — a single binary adapts to the host CPU.
153
221
154
-
// The ws package inside Meteor will pick up bufferutil
155
-
// if it's in node_modules. Use the package aliasing approach.
156
-
```
222
+
## Relevant to Meteor/DDP
223
+
224
+
If you're running Meteor.js, every DDP message (method calls, subscriptions, collection updates) goes through WebSocket framing. On a busy system with hundreds of concurrent connections, the masking loop runs thousands of times per second. Shaving microseconds here compounds into meaningful CPU savings.
157
225
158
226
## File structure
159
227
160
228
```
161
229
asm-bufferutil/
162
230
├── src/
163
-
│ ├── ws_napi.c # N-API C glue layer
231
+
│ ├── ws_fast_api.cc # Direct V8 C++ API bridge
232
+
│ ├── ws_napi.c # Legacy N-API bridge
164
233
│ ├── ws_sha1_ni.c # SHA-1 with Intel SHA-NI intrinsics
0 commit comments