Skip to content

Commit

Permalink
perf: enable wasm simd (nodejs#735)
Browse files Browse the repository at this point in the history
* perf: enable wasm simd

* bench: enable simd

* build: add wasm simd

* ci: use node 16 in benchmarks

* test: add simd test script

* ci: add simd bench

* enable simd by default in tests and benchmarks

* fix machine specs in README.md

Co-authored-by: Robert Nagy <ronagy@icloud.com>

* client: fallback to non-simd on all errors

* fixup: re-enable jest

* fixup

Co-authored-by: Daniele Belardi <dwon.dnl@gmail.com>
  • Loading branch information
2 people authored and crysmags committed Feb 27, 2024
1 parent 3963847 commit d2de340
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 24 deletions.
1 change: 1 addition & 0 deletions .taprc
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ coverage: true
expose-gc: true
timeout: 60
check-coverage: false
node-arg: --experimental-wasm-simd
38 changes: 21 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,36 @@ npm i undici

## Benchmarks

AMD EPYC 7502P 32 Core, Node 15
Node 16

The benchmark is a simple `hello world` [example](benchmarks/index.js) using a
number of unix sockets (connections) with a pipelining depth of 10.

### Connections 1

| Test | Samples | Result | Tolerance | Difference with slowest |
|---------------------|---------|----------------|-----------|-------------------------|
| http - no keepalive | 99 | 812 reqs/sec | ± 0.22 % | |
| http - keepalive | 99 | 819 reqs/sec | ± 0.20 % | + 0.82 % |
| undici - pipeline | 99 | 6632 reqs/sec | ± 0.63 % | + 716.73 % |
| undici - request | 99 | 6645 reqs/sec | ± 1.34 % | + 718.34 % |
| undici - stream | 99 | 7366 reqs/sec | ± 0.59 % | + 807.11 % |
| undici - dispatch | 99 | 7404 reqs/sec | ± 0.37 % | + 811.76 % |
| Tests | Samples | Result | Tolerance | Difference with slowest |
|---------------------|---------|---------------|-----------|-------------------------|
| http - no keepalive | 15 | 4.63 req/sec | ± 2.77 % | - |
| http - keepalive | 10 | 4.81 req/sec | ± 2.16 % | + 3.94 % |
| undici - stream | 25 | 62.22 req/sec | ± 2.67 % | + 1244.58 % |
| undici - dispatch | 15 | 64.33 req/sec | ± 2.47 % | + 1290.24 % |
| undici - request | 15 | 66.08 req/sec | ± 2.48 % | + 1327.88 % |
| undici - pipeline | 10 | 66.13 req/sec | ± 1.39 % | + 1329.08 % |

### Connections 50

| Test | Samples | Result | Tolerance | Difference with slowest |
|---------------------|---------|----------------|-----------|-------------------------|
| http - no keepalive | 99 | 12968 reqs/sec | ± 1.86 % | |
| http - keepalive | 99 | 14745 reqs/sec | ± 1.59 % | + 13.70 % |
| undici - pipeline | 99 | 20051 reqs/sec | ± 2.34 % | + 54.62 % |
| undici - stream | 100 | 26456 reqs/sec | ± 3.50 % | + 104.00 % |
| undici - request | 99 | 29342 reqs/sec | ± 1.26 % | + 126.26 % |
| undici - dispatch | 99 | 35323 reqs/sec | ± 0.77 % | + 172.38 % |
| Tests | Samples | Result | Tolerance | Difference with slowest |
|---------------------|---------|------------------|-----------|-------------------------|
| http - no keepalive | 50 | 3546.49 req/sec | ± 2.90 % | - |
| http - keepalive | 15 | 5692.67 req/sec | ± 2.48 % | + 60.52 % |
| undici - pipeline | 25 | 8478.71 req/sec | ± 2.62 % | + 139.07 % |
| undici - request | 20 | 9766.66 req/sec | ± 2.79 % | + 175.39 % |
| undici - stream | 15 | 10109.74 req/sec | ± 2.94 % | + 185.06 % |
| undici - dispatch | 25 | 10949.73 req/sec | ± 2.54 % | + 208.75 % |

#### Note

The benchmarks have the [simd](https://github.com/WebAssembly/simd) feature enabled.

## Quick Start

Expand Down
22 changes: 22 additions & 0 deletions build/wasm.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,25 @@ execSync(`${WASI_ROOT}/bin/clang \
${join(WASM_SRC, 'src')}/*.c \
-I${join(WASM_SRC, 'include')} \
-o ${join(WASM_OUT, 'llhttp.wasm')}`, { stdio: 'inherit' })

// Build wasm simd binary
execSync(`${WASI_ROOT}/bin/clang \
--sysroot=${WASI_ROOT}/share/wasi-sysroot \
-target wasm32-unknown-wasi \
-msimd128 \
-Ofast \
-fno-exceptions \
-fvisibility=hidden \
-mexec-model=reactor \
-Wl,-error-limit=0 \
-Wl,-O3 \
-Wl,--lto-O3 \
-Wl,--strip-all \
-Wl,--allow-undefined \
-Wl,--export-dynamic \
-Wl,--export-table \
-Wl,--export=malloc \
-Wl,--export=free \
${join(WASM_SRC, 'src')}/*.c \
-I${join(WASM_SRC, 'include')} \
-o ${join(WASM_OUT, 'llhttp_simd.wasm')}`, { stdio: 'inherit' })
26 changes: 20 additions & 6 deletions lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,6 @@ const {
BodyTimeoutError
} = require('./core/errors')

const { resolve } = require('path')
const { readFileSync } = require('fs')
const constants = require('./llhttp/constants')
const EMPTY_BUF = Buffer.alloc(0)
const mod = new WebAssembly.Module(readFileSync(resolve(__dirname, './llhttp/llhttp.wasm')))

const {
kUrl,
kReset,
Expand Down Expand Up @@ -387,6 +381,26 @@ class HTTPParserError extends Error {
}
}

let mod, build
const { resolve } = require('path')
const { readFileSync } = require('fs')
const constants = require('./llhttp/constants')
const EMPTY_BUF = Buffer.alloc(0)

try {
build = resolve(__dirname, './llhttp/llhttp_simd.wasm')
const bin = readFileSync(build)
mod = new WebAssembly.Module(bin)
} catch (e) {
// We could check if the error was caused by the simd option not
// being enabled, but the occurring of this other error
// * https://github.com/emscripten-core/emscripten/issues/11495
// got me to remove that check to avoid breaking Node 12.
build = resolve(__dirname, './llhttp/llhttp.wasm')
const bin = readFileSync(build)
mod = new WebAssembly.Module(bin)
}

const llhttp = new WebAssembly.Instance(mod, {
env: {
/* eslint-disable camelcase */
Expand Down
Binary file added lib/llhttp/llhttp_simd.wasm
Binary file not shown.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@
"coverage": "standard | snazzy && tap test/*.js",
"coverage:ci": "npm run coverage -- --coverage-report=lcovonly",
"bench": "concurrently -k -s first npm:bench:server npm:bench:run",
"bench:simd": "concurrently -k -s first npm:bench:server npm:bench:run:simd",
"bench:server": "node benchmarks/server.js",
"prebench:run": "node benchmarks/wait.js",
"bench:run": "CONNECTIONS=1 node benchmarks/benchmark.js && CONNECTIONS=50 node benchmarks/benchmark.js",
"bench:run": "CONNECTIONS=1 node --experimental-wasm-simd benchmarks/benchmark.js && CONNECTIONS=50 node --experimental-wasm-simd benchmarks/benchmark.js",
"serve:website": "docsify serve .",
"prepare": "husky install"
},
Expand Down

0 comments on commit d2de340

Please sign in to comment.