Skip to content

Commit 9f045eb

Browse files
JounQinellipsis-dev[bot]autofix-ci[bot]
authored
chore: migrate benchmark framework and deprecated hash-obj (#5)
Signed-off-by: JounQin <[email protected]> Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent cb7340b commit 9f045eb

File tree

7 files changed

+132
-106
lines changed

7 files changed

+132
-106
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ jobs:
4242
env:
4343
PARSER_NO_WATCH: true
4444

45+
- name: Benchmark
46+
run: node benchmark
47+
4548
- name: Codecov
4649
# bad Windows -- https://github.com/codecov/codecov-action/issues/1787
4750
if: ${{ !github.event.pull_request.head.repo.fork && matrix.os != 'windows-latest' }}

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ jobs:
4040
- name: Create Release Pull Request or Publish to npm
4141
uses: changesets/action@v1
4242
with:
43-
commit: 'chore: release lib-boilerplate'
44-
title: 'chore: release lib-boilerplate'
43+
commit: 'chore: release stable-hash-x'
44+
title: 'chore: release stable-hash-x'
4545
version: yarn run version
4646
publish: yarn release
4747
env:

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ It's similar to `JSON.stringify(value)`, but:
3131
- [Array](#array)
3232
- [Object](#object)
3333
- [`Function`, `Class`, `Set`, `Map`, `Buffer`...](#function-class-set-map-buffer)
34+
- [Benchmark](#benchmark)
3435
- [Notes](#notes)
3536
- [Sponsors and Backers](#sponsors-and-backers)
3637
- [Sponsors](#sponsors)
@@ -152,6 +153,39 @@ hash(foo) === hash(foo)
152153
hash(foo) !== hash(new Set([1]))
153154
```
154155

156+
## Benchmark
157+
158+
```log
159+
clk: ~2.91 GHz
160+
cpu: Apple M1 Max
161+
runtime: node 22.16.0 (arm64-darwin)
162+
163+
benchmark avg (min … max) p75 / p99 (min … top 1%)
164+
------------------------------------------- -------------------------------
165+
stable-hash-x 7.87 µs/iter 7.38 µs █
166+
(6.67 µs … 749.13 µs) 11.42 µs ▇█▃
167+
(104.00 b … 859.30 kb) 10.89 kb ▁███▅▂▂▂▂▁▁▁▁▁▁▁▁▁▁▁▁
168+
4.41 ipc ( 1.81% stalls) 98.08% L1 data cache
169+
28.04k cycles 123.52k instructions 29.75% retired LD/ST ( 36.75k)
170+
171+
hash-object 15.07 µs/iter 14.95 µs █ █
172+
(14.77 µs … 16.93 µs) 15.00 µs ▅ ▅ ▅▅█ ▅█▅ ▅
173+
(659.78 b … 3.26 kb) 1.95 kb █▁▁█▁▁▁▁▁▁███▁▁███▁▁█
174+
4.97 ipc ( 1.22% stalls) 99.33% L1 data cache
175+
46.36k cycles 230.44k instructions 35.12% retired LD/ST ( 80.94k)
176+
177+
json-stringify-deterministic 8.37 µs/iter 8.41 µs █
178+
(8.29 µs … 8.50 µs) 8.44 µs █ █
179+
( 1.65 kb … 1.65 kb) 1.65 kb █▁████▁██▁█▁▁▁█▁█▁███
180+
5.17 ipc ( 1.28% stalls) 99.40% L1 data cache
181+
25.99k cycles 134.30k instructions 35.51% retired LD/ST ( 47.69k)
182+
183+
summary
184+
stable-hash-x
185+
1.06x faster than json-stringify-deterministic
186+
1.91x faster than hash-object
187+
```
188+
155189
## Notes
156190

157191
This function does something similar to `JSON.stringify`, but more than it. It doesn't generate a secure checksum, which usually has a fixed length and is hard to be reversed. With `stable-hash-x` it's still possible to get the original data. Also, the output might include any charaters, not just alphabets and numbers like other hash algorithms. So:

benchmark.js

Lines changed: 29 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import crypto from 'node:crypto'
44

55
import { encodeUrl } from 'ab64'
66
import { flattie } from 'flattie'
7-
import hashObject from 'hash-obj'
7+
import hashObject from 'hash-object'
88
import stringify from 'json-stringify-deterministic'
9-
import bench from 'nanobench'
9+
import { bench, run, summary } from 'mitata'
1010

1111
import { hash } from 'stable-hash-x'
1212

@@ -41,33 +41,44 @@ const payload = {
4141
}
4242

4343
/**
44-
* Benchmarking `hash-obj` vs. `stable-hash`
44+
* Benchmarking `stable-hash-x` vs. `hash-object` vs.
45+
* `json-stringify-deterministic`
4546
*
4647
* The goal is to represent a real use-case. Because that:
4748
*
4849
* - Ensure the input is flatten
4950
* - Output is base64 URL safe
5051
* - Sha512 is used as algorithm
51-
*
52-
* @param {object} obj - The object to hash
52+
*/
53+
54+
/**
55+
* @param {unknown} obj
5356
* @returns {string} The hash
5457
*/
5558
const getHashOne = obj =>
56-
encodeUrl(
57-
hashObject(flattie(obj), {
58-
encoding: 'base64',
59-
algorithm: 'sha512',
60-
}),
61-
)
62-
63-
const getHashTwo = obj =>
6459
encodeUrl(
6560
crypto
6661
.createHash('sha512')
6762
.update(hash(flattie(obj)))
6863
.digest('base64'),
6964
)
7065

66+
/**
67+
* @param {unknown} obj - The object to hash
68+
* @returns {string} The hash
69+
*/
70+
const getHashTwo = obj =>
71+
encodeUrl(
72+
hashObject(flattie(obj), {
73+
encoding: 'base64',
74+
algorithm: 'sha512',
75+
}),
76+
)
77+
78+
/**
79+
* @param {unknown} obj
80+
* @returns {string} The hash
81+
*/
7182
const getHashThree = obj =>
7283
encodeUrl(
7384
crypto
@@ -76,34 +87,12 @@ const getHashThree = obj =>
7687
.digest('base64'),
7788
)
7889

79-
const count = 200_000
90+
summary(() => {
91+
bench('stable-hash-x', () => getHashOne(payload)).baseline()
8092

81-
bench('`hash-obj` 200.000 times', function (b) {
82-
b.start()
93+
bench('hash-object', () => getHashTwo(payload))
8394

84-
for (let i = 0; i < count; i++) {
85-
getHashOne(payload)
86-
}
87-
88-
b.end()
89-
})
90-
91-
bench('`stable-hash` 200.000 times', function (b) {
92-
b.start()
93-
94-
for (let i = 0; i < count; i++) {
95-
getHashTwo(payload)
96-
}
97-
98-
b.end()
95+
bench('json-stringify-deterministic', () => getHashThree(payload))
9996
})
10097

101-
bench('`json-stringify-deterministic` 200.000 times', function (b) {
102-
b.start()
103-
104-
for (let i = 0; i < count; i++) {
105-
getHashThree(payload)
106-
}
107-
108-
b.end()
109-
})
98+
await run()

benchmark.txt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
clk: ~2.91 GHz
2+
cpu: Apple M1 Max
3+
runtime: node 22.16.0 (arm64-darwin)
4+
5+
benchmark avg (min … max) p75 / p99 (min … top 1%)
6+
------------------------------------------- -------------------------------
7+
stable-hash-x 7.87 µs/iter 7.38 µs █
8+
(6.67 µs … 749.13 µs) 11.42 µs ▇█▃
9+
(104.00 b … 859.30 kb) 10.89 kb ▁███▅▂▂▂▂▁▁▁▁▁▁▁▁▁▁▁▁
10+
4.41 ipc ( 1.81% stalls) 98.08% L1 data cache
11+
28.04k cycles 123.52k instructions 29.75% retired LD/ST ( 36.75k)
12+
13+
hash-object 15.07 µs/iter 14.95 µs █ █
14+
(14.77 µs … 16.93 µs) 15.00 µs ▅ ▅ ▅▅█ ▅█▅ ▅
15+
(659.78 b … 3.26 kb) 1.95 kb █▁▁█▁▁▁▁▁▁███▁▁███▁▁█
16+
4.97 ipc ( 1.22% stalls) 99.33% L1 data cache
17+
46.36k cycles 230.44k instructions 35.12% retired LD/ST ( 80.94k)
18+
19+
json-stringify-deterministic 8.37 µs/iter 8.41 µs █
20+
(8.29 µs … 8.50 µs) 8.44 µs █ █
21+
( 1.65 kb … 1.65 kb) 1.65 kb █▁████▁██▁█▁▁▁█▁█▁███
22+
5.17 ipc ( 1.28% stalls) 99.40% L1 data cache
23+
25.99k cycles 134.30k instructions 35.51% retired LD/ST ( 47.69k)
24+
25+
summary
26+
stable-hash-x
27+
1.06x faster than json-stringify-deterministic
28+
1.91x faster than hash-object

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"lib"
3232
],
3333
"scripts": {
34+
"benchmark": "sudo env NO_COLOR=1 node benchmark > benchmark.txt",
3435
"build": "tsdown -d lib -f cjs,esm",
3536
"dev": "vitest",
3637
"docs": "vite",
@@ -52,8 +53,8 @@
5253
"@changesets/cli": "^2.29.4",
5354
"@commitlint/cli": "^19.8.1",
5455
"@mdx-js/rollup": "^3.1.0",
56+
"@mitata/counters": "^0.0.8",
5557
"@shikijs/rehype": "^3.5.0",
56-
"@types/nanobench": "^3.0.0",
5758
"@types/node": "^22.15.29",
5859
"@types/react": "^19",
5960
"@types/react-dom": "^19",
@@ -67,10 +68,10 @@
6768
"eslint": "^9.28.0",
6869
"flattie": "^1.1.1",
6970
"github-markdown-css": "^5.8.1",
70-
"hash-obj": "^5.0.0",
71+
"hash-object": "^5.0.1",
7172
"json-stringify-deterministic": "^1.0.12",
73+
"mitata": "^1.0.34",
7274
"nano-staged": "^0.8.0",
73-
"nanobench": "^3.0.0",
7475
"npm-run-all2": "^8.0.4",
7576
"prettier": "^3.5.3",
7677
"react": "^19.1.0",

0 commit comments

Comments
 (0)