Skip to content

Commit cf55e87

Browse files
committed
feat: setup node bench
1 parent 904b338 commit cf55e87

4 files changed

Lines changed: 317 additions & 16 deletions

File tree

bench/bench-node/package.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "bench-node",
3+
"private": true,
4+
"version": "0.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"start": "tsx src/index.ts",
8+
"build": "tsc"
9+
},
10+
"dependencies": {
11+
"@wbe/debug": "workspace:*",
12+
"debug": "4.4.0",
13+
"chalk": "^5.3.0"
14+
},
15+
"devDependencies": {
16+
"typescript": "~5.7.2",
17+
"tsx": "^4.7.0"
18+
}
19+
}

bench/bench-node/src/index.ts

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
import debugOriginal from "debug"
2+
import debugWbe from "@wbe/debug"
3+
import chalk from "chalk"
4+
5+
// Enable logs for both libraries
6+
process.env.DEBUG = "*"
7+
8+
// Function to format numbers with commas for better readability
9+
const formatNumber = (num: number): string => {
10+
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")
11+
}
12+
13+
/**
14+
* Benchmark class to compare @wbe/debug vs debug performances
15+
*/
16+
class Benchmark {
17+
private readonly iterations: number
18+
private readonly warmupIterations: number
19+
private results: {
20+
debugOriginal: number
21+
debugWbe: number
22+
}
23+
private testMessages: any[]
24+
25+
constructor(iterations: number = 100000, warmupIterations: number = 1000) {
26+
this.iterations = iterations
27+
this.warmupIterations = warmupIterations
28+
this.results = {
29+
debugOriginal: 0,
30+
debugWbe: 0,
31+
}
32+
33+
// Create a variety of test messages to use in benchmarks
34+
this.testMessages = [
35+
"Simple string message",
36+
["Array", "of", "strings"],
37+
{ complex: "object", with: { nested: "properties" } },
38+
["Mixed", 123, { type: "content" }],
39+
]
40+
}
41+
42+
/**
43+
* Run warmup phase to initialize both libraries
44+
*/
45+
private warmup(): void {
46+
console.log(chalk.dim("Warming up..."))
47+
48+
const logOriginal = debugOriginal("bench:original:warmup")
49+
const logWbe = debugWbe("bench:wbe:warmup")
50+
51+
for (let i = 0; i < this.warmupIterations; i++) {
52+
logOriginal("warmup")
53+
logWbe("warmup")
54+
}
55+
}
56+
57+
/**
58+
* Benchmark the original debug library
59+
*/
60+
private benchmarkOriginal(): void {
61+
console.log(
62+
chalk.blue.bold(
63+
`\nBenchmarking ${chalk.underline("original debug")} library...`
64+
)
65+
)
66+
67+
const logOriginal = debugOriginal("bench:original")
68+
const start = process.hrtime.bigint()
69+
70+
for (let i = 0; i < this.iterations; i++) {
71+
const msgIndex = i % this.testMessages.length
72+
logOriginal(this.testMessages[msgIndex])
73+
}
74+
75+
const end = process.hrtime.bigint()
76+
this.results.debugOriginal = Number(end - start) / 1_000_000 // Convert to ms
77+
}
78+
79+
/**
80+
* Benchmark the @wbe/debug library
81+
*/
82+
private benchmarkWbe(): void {
83+
console.log(
84+
chalk.green.bold(
85+
`\nBenchmarking ${chalk.underline("@wbe/debug")} library...`
86+
)
87+
)
88+
89+
const logWbe = debugWbe("bench:wbe")
90+
const start = process.hrtime.bigint()
91+
92+
for (let i = 0; i < this.iterations; i++) {
93+
const msgIndex = i % this.testMessages.length
94+
logWbe(this.testMessages[msgIndex])
95+
}
96+
97+
const end = process.hrtime.bigint()
98+
this.results.debugWbe = Number(end - start) / 1_000_000 // Convert to ms
99+
}
100+
101+
/**
102+
* Display the benchmark results
103+
*/
104+
private displayResults(): void {
105+
console.log("\n" + chalk.yellow.bold("=".repeat(50)))
106+
console.log(chalk.yellow.bold(" BENCHMARK RESULTS"))
107+
console.log(chalk.yellow.bold("=".repeat(50)) + "\n")
108+
109+
const { debugOriginal, debugWbe } = this.results
110+
111+
console.log(
112+
`Total iterations per library: ${chalk.bold(
113+
formatNumber(this.iterations)
114+
)}`
115+
)
116+
console.log(
117+
`Test messages: ${chalk.dim(JSON.stringify(this.testMessages))}\n`
118+
)
119+
120+
// Calculate per-operation times
121+
const originalPerOp = debugOriginal / this.iterations
122+
const wbePerOp = debugWbe / this.iterations
123+
124+
// Display the results for the original debug library
125+
console.log(chalk.blue.bold("Original debug:"))
126+
console.log(` Total time: ${chalk.bold(debugOriginal.toFixed(2) + " ms")}`)
127+
console.log(
128+
` Per operation: ${chalk.bold(originalPerOp.toFixed(6) + " ms")}\n`
129+
)
130+
131+
// Display the results for @wbe/debug
132+
console.log(chalk.green.bold("@wbe/debug:"))
133+
console.log(` Total time: ${chalk.bold(debugWbe.toFixed(2) + " ms")}`)
134+
console.log(` Per operation: ${chalk.bold(wbePerOp.toFixed(6) + " ms")}\n`)
135+
136+
// Display the difference
137+
const diff = debugWbe - debugOriginal
138+
console.log(
139+
`Absolute difference: ${chalk.bold(Math.abs(diff).toFixed(2) + " ms")}`
140+
)
141+
142+
// Calculate which one is faster
143+
if (debugWbe < debugOriginal) {
144+
const percentFaster = ((debugOriginal / debugWbe - 1) * 100).toFixed(2)
145+
console.log(
146+
chalk.green.bold(
147+
`@wbe/debug is ${percentFaster}% faster than original debug`
148+
)
149+
)
150+
} else {
151+
const percentFaster = ((debugWbe / debugOriginal - 1) * 100).toFixed(2)
152+
console.log(
153+
chalk.blue.bold(
154+
`Original debug is ${percentFaster}% faster than @wbe/debug`
155+
)
156+
)
157+
}
158+
159+
// Display a simple visualization of the results
160+
this.displayVisualization()
161+
}
162+
163+
/**
164+
* Display a simple ASCII visualization of the benchmark results
165+
*/
166+
private displayVisualization(): void {
167+
const { debugOriginal, debugWbe } = this.results
168+
const maxTime = Math.max(debugOriginal, debugWbe)
169+
170+
// Calculate bar lengths (max 40 chars)
171+
const maxBarLength = 40
172+
const originalBarLength = Math.round(
173+
(debugOriginal / maxTime) * maxBarLength
174+
)
175+
const wbeBarLength = Math.round((debugWbe / maxTime) * maxBarLength)
176+
177+
console.log("\n" + chalk.yellow.bold("Performance Comparison:"))
178+
179+
// Original debug bar
180+
process.stdout.write(chalk.blue.bold("Original debug: "))
181+
process.stdout.write(chalk.blue("█".repeat(originalBarLength)))
182+
console.log(` ${debugOriginal.toFixed(2)} ms`)
183+
184+
// @wbe/debug bar
185+
process.stdout.write(chalk.green.bold("@wbe/debug: "))
186+
process.stdout.write(chalk.green("█".repeat(wbeBarLength)))
187+
console.log(` ${debugWbe.toFixed(2)} ms`)
188+
189+
console.log("\n" + chalk.yellow.bold("=".repeat(50)))
190+
}
191+
192+
/**
193+
* Run the complete benchmark
194+
*/
195+
public async run(): Promise<void> {
196+
console.log(
197+
chalk.bold("\n🚀 Starting Node.js benchmark: @wbe/debug vs debug")
198+
)
199+
console.log(
200+
chalk.dim(`Running with ${formatNumber(this.iterations)} iterations`)
201+
)
202+
203+
// First warm up
204+
this.warmup()
205+
206+
// Benchmark original debug
207+
this.benchmarkOriginal()
208+
209+
// Benchmark @wbe/debug
210+
this.benchmarkWbe()
211+
212+
// Display results
213+
this.displayResults()
214+
}
215+
}
216+
217+
// Run the benchmark with 100,000 iterations
218+
const benchmark = new Benchmark(100000)
219+
benchmark.run().catch(console.error)

bench/bench-node/tsconfig.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2020",
4+
"module": "ESNext",
5+
"moduleResolution": "bundler",
6+
"esModuleInterop": true,
7+
"strict": true,
8+
"outDir": "dist",
9+
"skipLibCheck": true
10+
},
11+
"include": ["src"]
12+
}

0 commit comments

Comments
 (0)