Skip to content

Commit c208caf

Browse files
authored
fix: skip validation when encapsulating/decapsulating (#420)
Shifts expensive validation to `validate` function which gives the user more control over operations take place. Skips validation when we create a multiaddr from an existing multiaddr. Adds an internal `validate` method that can perform explicit validation. For example we currently run multiple regex passes over IP addresses when creating new multiaddrs which can cause CPU bottlenecks. Running the benchmark added in this PR it's an order of magnitude faster.
1 parent 21dce2a commit c208caf

22 files changed

+1532
-1175
lines changed

benchmarks/operations/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# multiaddr Benchmark
2+
3+
Benchmarks multiaddr performance during common operations - parsing strings,
4+
encapsulating/decapsulating addresses, turning to bytes, decoding bytes, etc.
5+
6+
## Running the benchmarks
7+
8+
```console
9+
% npm start
10+
11+
12+
> npm run build && node dist/src/index.js
13+
14+
15+
16+
> aegir build --bundle false
17+
18+
[06:10:56] tsc [started]
19+
[06:10:56] tsc [completed]
20+
┌─────────┬──────────────────────────────────┬─────────────┬────────┬───────┬────────┐
21+
│ (index) │ Implementation │ ops/s │ ms/op │ runs │ p99 │
22+
├─────────┼──────────────────────────────────┼─────────────┼────────┼───────┼────────┤
23+
│ 0 │ 'head' │ '105679.89' │ '0.01' │ 50000 │ '0.01' │
24+
│ 1 │ '@multiformats/[email protected]' │ '18244.31' │ '0.06' │ 50000 │ '0.13' │
25+
└─────────┴──────────────────────────────────┴─────────────┴────────┴───────┴────────┘
26+
```

benchmarks/operations/package.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "benchmarks-operations",
3+
"version": "1.0.0",
4+
"main": "index.js",
5+
"private": true,
6+
"type": "module",
7+
"scripts": {
8+
"clean": "aegir clean",
9+
"build": "aegir build --bundle false",
10+
"lint": "aegir lint",
11+
"dep-check": "aegir dep-check",
12+
"doc-check": "aegir doc-check",
13+
"start": "npm run build && node dist/test/index.js"
14+
},
15+
"devDependencies": {
16+
"@multiformats/multiaddr-12.4.0": "npm:@multiformats/[email protected]",
17+
"@multiformats/multiaddr": "../../",
18+
"aegir": "^47.0.7",
19+
"tinybench": "^4.0.1"
20+
}
21+
}

benchmarks/operations/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {}

benchmarks/operations/test/index.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/* eslint-disable no-console */
2+
3+
import { multiaddr } from '@multiformats/multiaddr'
4+
import { multiaddr as multiaddr12 } from '@multiformats/multiaddr-12.4.0'
5+
import { Bench } from 'tinybench'
6+
7+
const ITERATIONS = parseInt(process.env.ITERATIONS ?? '50000')
8+
const MIN_TIME = parseInt(process.env.MIN_TIME ?? '1')
9+
const RESULT_PRECISION = 2
10+
11+
function bench (m: typeof multiaddr | typeof multiaddr12): void {
12+
const ma = m('/ip4/127.0.0.1/udp/1234/quic-v1/webtransport/certhash/uEiAkH5a4DPGKUuOBjYw0CgwjvcJCJMD2K_1aluKR_tpevQ/certhash/uEiAfbgiymPP2_nX7Dgir8B4QkksjHp2lVuJZz0F79Be9JA')
13+
ma.encapsulate('/p2p-circuit/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC')
14+
ma.decapsulate('/quic-v1')
15+
16+
const ma2 = m(ma.bytes)
17+
ma2.encapsulate('/tls/sni/example.com/http/http-path/path%2Findex.html')
18+
ma2.equals(ma)
19+
20+
ma2.getPath()
21+
ma2.getPeerId()
22+
23+
const ma3 = m('/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/udp/1234/quic-v1/webtransport/certhash/uEiAkH5a4DPGKUuOBjYw0CgwjvcJCJMD2K_1aluKR_tpevQ/certhash/uEiAfbgiymPP2_nX7Dgir8B4QkksjHp2lVuJZz0F79Be9JA')
24+
ma3.encapsulate('/p2p-circuit/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC')
25+
ma3.decapsulate('/quic-v1')
26+
}
27+
28+
async function main (): Promise<void> {
29+
const suite = new Bench({
30+
iterations: ITERATIONS,
31+
time: MIN_TIME
32+
})
33+
suite.add('head', () => {
34+
bench(multiaddr)
35+
})
36+
suite.add('@multiformats/[email protected]', () => {
37+
bench(multiaddr12)
38+
})
39+
40+
await suite.run()
41+
42+
console.table(suite.tasks.map(({ name, result }) => {
43+
if (result?.error != null) {
44+
console.error(result.error)
45+
46+
return {
47+
Implementation: name,
48+
'ops/s': 'error',
49+
'ms/op': 'error',
50+
runs: 'error',
51+
p99: 'error'
52+
}
53+
}
54+
55+
return {
56+
Implementation: name,
57+
'ops/s': result?.hz.toFixed(RESULT_PRECISION),
58+
'ms/op': result?.period.toFixed(RESULT_PRECISION),
59+
runs: result?.samples.length,
60+
p99: result?.p99.toFixed(RESULT_PRECISION)
61+
}
62+
}))
63+
}
64+
65+
main().catch(err => {
66+
console.error(err)
67+
process.exit(1)
68+
})

benchmarks/operations/tsconfig.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"extends": "aegir/src/config/tsconfig.aegir.json",
3+
"compilerOptions": {
4+
"outDir": "dist"
5+
},
6+
"include": [
7+
"src",
8+
"test"
9+
],
10+
"references": [
11+
{
12+
"path": "../../"
13+
}
14+
]
15+
}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,13 +171,14 @@
171171
"@chainsafe/is-ip": "^2.0.1",
172172
"@chainsafe/netmask": "^2.0.0",
173173
"@multiformats/dns": "^1.0.3",
174+
"abort-error": "^1.0.1",
174175
"multiformats": "^13.0.0",
175176
"uint8-varint": "^2.0.1",
176177
"uint8arrays": "^5.0.0"
177178
},
178179
"devDependencies": {
179180
"@types/sinon": "^17.0.2",
180-
"aegir": "^47.0.12",
181+
"aegir": "^47.0.16",
181182
"sinon": "^19.0.2",
182183
"sinon-ts": "^2.0.0"
183184
},

src/codec.ts

Lines changed: 0 additions & 236 deletions
This file was deleted.

0 commit comments

Comments
 (0)