Skip to content

Commit 4d53643

Browse files
committed
Add benchmarks and make sure Node is faster
1 parent bfe4c9e commit 4d53643

File tree

7 files changed

+131
-20
lines changed

7 files changed

+131
-20
lines changed

.github/workflows/ci.yml

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,28 @@ jobs:
1313
- uses: actions/checkout@v2
1414
- uses: actions/setup-node@v1
1515
with:
16-
node-version: 14
16+
node-version: 20
1717
registry-url: https://registry.npmjs.org/
1818
- run: npm i
1919
- run: npm run unit
20+
benchmarks:
21+
runs-on: ubuntu-latest
22+
continue-on-error: true
23+
steps:
24+
- uses: actions/checkout@v2
25+
- uses: actions/setup-node@v1
26+
with:
27+
node-version: 20
28+
registry-url: https://registry.npmjs.org/
29+
- run: npm i
30+
- run: npm run benchmarks
2031
coverage:
2132
runs-on: ubuntu-latest
2233
steps:
2334
- uses: actions/checkout@v2
2435
- uses: actions/setup-node@v1
2536
with:
26-
node-version: 14
37+
node-version: 20
2738
registry-url: https://registry.npmjs.org/
2839
- run: npm i
2940
- run: npm run coverage
@@ -33,7 +44,7 @@ jobs:
3344
- uses: actions/checkout@v2
3445
- uses: actions/setup-node@v1
3546
with:
36-
node-version: 14
47+
node-version: 20
3748
registry-url: https://registry.npmjs.org/
3849
- run: npm i
3950
- run: npm run gitdiff:ci
@@ -43,7 +54,7 @@ jobs:
4354
- uses: actions/checkout@v2
4455
- uses: actions/setup-node@v1
4556
with:
46-
node-version: 14
57+
node-version: 20
4758
registry-url: https://registry.npmjs.org/
4859
- run: npm i
4960
- run: npm run lint

benchmarks/main.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { Suite } from "bench-node";
2+
import * as nodeTools from "../src/mjs/index.js";
3+
import * as browserTools from "../src/mjs/browser.js";
4+
5+
const DUMMY_BUFFER = Uint8Array.from([
6+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde,
7+
0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad,
8+
0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe,
9+
0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
10+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde,
11+
0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad,
12+
0xbe, 0xef,
13+
]);
14+
const DUMMY_HEX =
15+
"deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
16+
17+
// Note: only include benchmarks for functions with differing implementations for Node and Browser
18+
const BENCHMARKS = [
19+
[
20+
`fromHex`,
21+
(library) => () => {
22+
library.fromHex(DUMMY_HEX);
23+
},
24+
],
25+
[
26+
`toHex`,
27+
(library) => () => {
28+
library.toHex(DUMMY_BUFFER);
29+
},
30+
],
31+
];
32+
33+
const LIBRARIES = [
34+
["Node ", nodeTools],
35+
["Browser", browserTools],
36+
];
37+
38+
function setUpSuite(suite, platform, library, funcName, func) {
39+
suite.add(`${platform} ${funcName}`, func(library));
40+
}
41+
42+
async function main() {
43+
const suite = new Suite();
44+
for (const [funcName, func] of BENCHMARKS) {
45+
for (const [name, library] of LIBRARIES) {
46+
setUpSuite(suite, name, library, funcName, func);
47+
}
48+
}
49+
const results = await suite.run();
50+
51+
const nodeSlower = [];
52+
53+
for (let i = 0; i < results.length; i += 2) {
54+
const nodeResult = results[i];
55+
const browserResult = results[i + 1];
56+
if (nodeResult.opsSec < browserResult.opsSec) {
57+
nodeSlower.push(BENCHMARKS[i / 2][0]);
58+
}
59+
}
60+
if (nodeSlower.length > 0) {
61+
throw new Error(
62+
`\n*** Node was slower in the following:\n *** ${nodeSlower.join(
63+
"\n *** "
64+
)}`
65+
);
66+
}
67+
}
68+
69+
main().catch((err) => {
70+
console.error(err);
71+
process.exit(1);
72+
});

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"types": "src/cjs/index.d.ts",
2424
"type": "module",
2525
"scripts": {
26+
"benchmarks": "node benchmarks/main.js",
2627
"build": "npm run clean && npm run build-ts && npm run convert-cjs && rm -f ./src/cjs/browser.d.ts",
2728
"build-ts": "tsc -p tsconfig.json && tsc -p tsconfig-cjs.json",
2829
"clean": "rm -rf ./src/* && rm -rf ./coverage && rm -f ./package-lock.json",
@@ -50,6 +51,7 @@
5051
"@types/node": "16.11.1",
5152
"@typescript-eslint/eslint-plugin": "5.0.0",
5253
"@typescript-eslint/parser": "5.0.0",
54+
"bench-node": "0.0.1-beta.0",
5355
"eslint": "8.0.1",
5456
"eslint-config-prettier": "8.3.0",
5557
"eslint-plugin-prettier": "4.0.0",

src/cjs/index.cjs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
"use strict";
22
Object.defineProperty(exports, "__esModule", { value: true });
3-
exports.compare = exports.fromHex = exports.toHex = exports.toUtf8 = void 0;
4-
function toUtf8(bytes) {
5-
return Buffer.from(bytes || []).toString();
6-
}
7-
exports.toUtf8 = toUtf8;
3+
exports.toUtf8 = exports.compare = exports.fromHex = exports.toHex = void 0;
84
function toHex(bytes) {
95
return Buffer.from(bytes || []).toString("hex");
106
}
@@ -13,7 +9,19 @@ function fromHex(hexString) {
139
return Uint8Array.from(Buffer.from(hexString || "", "hex"));
1410
}
1511
exports.fromHex = fromHex;
12+
// Same behavior as Buffer.compare()
1613
function compare(v1, v2) {
17-
return Buffer.from(v1).compare(Buffer.from(v2));
14+
const minLength = Math.min(v1.length, v2.length);
15+
for (let i = 0; i < minLength; ++i) {
16+
if (v1[i] !== v2[i]) {
17+
return v1[i] < v2[i] ? -1 : 1;
18+
}
19+
}
20+
return v1.length === v2.length ? 0 : v1.length > v2.length ? 1 : -1;
1821
}
1922
exports.compare = compare;
23+
const DECODER = new TextDecoder();
24+
function toUtf8(bytes) {
25+
return DECODER.decode(bytes);
26+
}
27+
exports.toUtf8 = toUtf8;

src/cjs/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
export declare function toUtf8(bytes: Uint8Array): string;
21
export declare function toHex(bytes: Uint8Array): string;
32
export declare function fromHex(hexString: string): Uint8Array;
43
export declare type CompareResult = -1 | 0 | 1;
54
export declare function compare(v1: Uint8Array, v2: Uint8Array): CompareResult;
5+
export declare function toUtf8(bytes: Uint8Array): string;

src/mjs/index.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
1-
export function toUtf8(bytes) {
2-
return Buffer.from(bytes || []).toString();
3-
}
41
export function toHex(bytes) {
52
return Buffer.from(bytes || []).toString("hex");
63
}
74
export function fromHex(hexString) {
85
return Uint8Array.from(Buffer.from(hexString || "", "hex"));
96
}
7+
// Same behavior as Buffer.compare()
108
export function compare(v1, v2) {
11-
return Buffer.from(v1).compare(Buffer.from(v2));
9+
const minLength = Math.min(v1.length, v2.length);
10+
for (let i = 0; i < minLength; ++i) {
11+
if (v1[i] !== v2[i]) {
12+
return v1[i] < v2[i] ? -1 : 1;
13+
}
14+
}
15+
return v1.length === v2.length ? 0 : v1.length > v2.length ? 1 : -1;
16+
}
17+
const DECODER = new TextDecoder();
18+
export function toUtf8(bytes) {
19+
return DECODER.decode(bytes);
1220
}

ts_src/index.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
export function toUtf8(bytes: Uint8Array): string {
2-
return Buffer.from(bytes || []).toString();
3-
}
4-
51
export function toHex(bytes: Uint8Array): string {
62
return Buffer.from(bytes || []).toString("hex");
73
}
@@ -10,7 +6,21 @@ export function fromHex(hexString: string): Uint8Array {
106
return Uint8Array.from(Buffer.from(hexString || "", "hex"));
117
}
128

9+
// API that is copy-paste from browser
10+
1311
export type CompareResult = -1 | 0 | 1;
12+
// Same behavior as Buffer.compare()
1413
export function compare(v1: Uint8Array, v2: Uint8Array): CompareResult {
15-
return Buffer.from(v1).compare(Buffer.from(v2)) as CompareResult;
14+
const minLength = Math.min(v1.length, v2.length);
15+
for (let i = 0; i < minLength; ++i) {
16+
if (v1[i] !== v2[i]) {
17+
return v1[i] < v2[i] ? -1 : 1;
18+
}
19+
}
20+
return v1.length === v2.length ? 0 : v1.length > v2.length ? 1 : -1;
21+
}
22+
23+
const DECODER = new TextDecoder();
24+
export function toUtf8(bytes: Uint8Array): string {
25+
return DECODER.decode(bytes);
1626
}

0 commit comments

Comments
 (0)