Skip to content

Commit 48b0510

Browse files
authored
Merge pull request #19 from willybrauner/benchmark
feat: Create benchmark
2 parents 3831f3a + 2a90d89 commit 48b0510

23 files changed

Lines changed: 1294 additions & 152 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# @wbe/debug
22

3-
Tiny debug tool (~500 bytes) for terminal and browser inspired by [debug-js/debug](https://github.com/debug-js/debug) API.
3+
Tiny debug tool (~600 bytes) for terminal and browser inspired by [debug-js/debug](https://github.com/debug-js/debug) API.
44

55
![](https://img.shields.io/npm/v/@wbe/debug/latest.svg)
66
![](https://github.com/willybrauner/debug/workflows/CI/badge.svg)

bench/bench-browser/.gitignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?

bench/bench-browser/index.html

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>@wbe/debug vs debug - Benchmark</title>
8+
</head>
9+
<body>
10+
<div id="app">
11+
</div>
12+
<script type="module" src="/src/main.tsx"></script>
13+
</body>
14+
</html>

bench/bench-browser/package.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "browser-bench",
3+
"private": true,
4+
"version": "0.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "tsc && vite build",
9+
"preview": "vite preview"
10+
},
11+
"dependencies": {
12+
"@wbe/debug": "workspace:*",
13+
"debug": "4.4.0",
14+
"preact": "^10.26.5"
15+
},
16+
"devDependencies": {
17+
"sass": "^1.86.3",
18+
"typescript": "~5.7.2",
19+
"vite": "^6.2.0"
20+
}
21+
}
Lines changed: 1 addition & 0 deletions
Loading

bench/bench-browser/src/App.tsx

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
import { useState, useEffect } from "preact/hooks"
2+
import debugOriginal from "debug"
3+
import debugWbe from "@wbe/debug"
4+
5+
interface BenchmarkResults {
6+
debugOriginal: number
7+
debugWbe: number
8+
iterations: number
9+
testMessages: any[]
10+
completed: boolean
11+
}
12+
13+
export const BenchmarkApp = () => {
14+
const [results, setResults] = useState<BenchmarkResults>({
15+
debugOriginal: 0,
16+
debugWbe: 0,
17+
iterations: 10000,
18+
testMessages: [],
19+
completed: false,
20+
})
21+
const [isRunning, setIsRunning] = useState(false)
22+
23+
useEffect(() => {
24+
runBenchmark()
25+
}, [])
26+
27+
const runBenchmark = async () => {
28+
setIsRunning(true)
29+
30+
const logBench = debugWbe("bench:main")
31+
logBench("Starting browser benchmark...")
32+
33+
// Setup for benchmarking
34+
const iterations = results.iterations
35+
const benchResults = {
36+
debugOriginal: 0,
37+
debugWbe: 0,
38+
}
39+
40+
// Create loggers for each library
41+
const logOriginal = debugOriginal("bench:original")
42+
const logWbe = debugWbe("bench:wbe")
43+
44+
// Warmup phase - warm up both libraries more thoroughly
45+
logBench("Warming up...")
46+
for (let i = 0; i < 1000; i++) {
47+
logOriginal("warmup")
48+
logWbe("warmup")
49+
}
50+
51+
// Setup test messages with different complexity
52+
const testMessages = [
53+
"Simple string message",
54+
["Array", "of", "strings"],
55+
{ complex: "object", with: { nested: "properties" } },
56+
["Mixed", 123, { type: "content" }],
57+
]
58+
59+
// Update state with test messages
60+
setResults((prev) => ({ ...prev, testMessages }))
61+
62+
// Run multiple rounds of benchmarking in alternating order
63+
const numberOfRounds = 4
64+
const roundResults = {
65+
debugOriginal: [] as number[],
66+
debugWbe: [] as number[],
67+
}
68+
69+
logBench(
70+
`Running ${numberOfRounds} rounds of benchmarks in alternating order...`
71+
)
72+
73+
for (let round = 0; round < numberOfRounds; round++) {
74+
logBench(`Round ${round + 1}/${numberOfRounds}`)
75+
76+
// Determine order based on round number (alternate)
77+
const runFirstSecond =
78+
round % 2 === 0
79+
? [runOriginalBenchmark, runWbeBenchmark]
80+
: [runWbeBenchmark, runOriginalBenchmark]
81+
82+
// Run benchmarks in determined order
83+
await new Promise((resolve) => setTimeout(resolve, 100)) // Small pause between rounds
84+
const result1 = await runFirstSecond[0]()
85+
await new Promise((resolve) => setTimeout(resolve, 100)) // Small pause between tests
86+
const result2 = await runFirstSecond[1]()
87+
88+
// Store results in correct slots regardless of execution order
89+
if (round % 2 === 0) {
90+
roundResults.debugOriginal.push(result1)
91+
roundResults.debugWbe.push(result2)
92+
} else {
93+
roundResults.debugWbe.push(result1)
94+
roundResults.debugOriginal.push(result2)
95+
}
96+
}
97+
98+
// Calculate average results
99+
benchResults.debugOriginal =
100+
roundResults.debugOriginal.reduce((a, b) => a + b, 0) / numberOfRounds
101+
benchResults.debugWbe =
102+
roundResults.debugWbe.reduce((a, b) => a + b, 0) / numberOfRounds
103+
104+
logBench("All benchmark rounds completed.")
105+
106+
// Function to benchmark original debug
107+
async function runOriginalBenchmark() {
108+
logBench("Benchmarking original debug library...")
109+
const start = performance.now()
110+
111+
for (let i = 0; i < iterations; i++) {
112+
const msgIndex = i % testMessages.length
113+
logOriginal(testMessages[msgIndex])
114+
}
115+
116+
const duration = performance.now() - start
117+
logBench(`Original debug completed in ${duration.toFixed(2)}ms`)
118+
return duration
119+
}
120+
121+
// Function to benchmark @wbe/debug
122+
async function runWbeBenchmark() {
123+
logBench("Benchmarking @wbe/debug library...")
124+
const start = performance.now()
125+
126+
for (let i = 0; i < iterations; i++) {
127+
const msgIndex = i % testMessages.length
128+
logWbe(testMessages[msgIndex])
129+
}
130+
131+
const duration = performance.now() - start
132+
logBench(`@wbe/debug completed in ${duration.toFixed(2)}ms`)
133+
return duration
134+
}
135+
136+
// Display results
137+
logBench("Browser benchmark completed.")
138+
139+
console.log(
140+
"%c---- BENCHMARK RESULTS ----",
141+
"font-weight: bold; font-size: 16px;"
142+
)
143+
console.log(`Total iterations per library: ${iterations}`)
144+
console.log(
145+
`Original debug: ${benchResults.debugOriginal.toFixed(2)}ms (${(
146+
benchResults.debugOriginal / iterations
147+
).toFixed(3)}ms per call)`
148+
)
149+
console.log(
150+
`@wbe/debug: ${benchResults.debugWbe.toFixed(2)}ms (${(
151+
benchResults.debugWbe / iterations
152+
).toFixed(3)}ms per call)`
153+
)
154+
console.log(
155+
`Difference: ${(
156+
benchResults.debugWbe - benchResults.debugOriginal
157+
).toFixed(2)}ms`
158+
)
159+
160+
if (benchResults.debugWbe < benchResults.debugOriginal) {
161+
console.log(
162+
`%c@wbe/debug is ${(
163+
(benchResults.debugOriginal / benchResults.debugWbe - 1) *
164+
100
165+
).toFixed(2)}% faster`,
166+
"color: green; font-weight: bold"
167+
)
168+
} else {
169+
console.log(
170+
`%cOriginal debug is ${(
171+
(benchResults.debugWbe / benchResults.debugOriginal - 1) *
172+
100
173+
).toFixed(2)}% faster`,
174+
"color: red; font-weight: bold"
175+
)
176+
}
177+
178+
// Update state with results
179+
setResults({
180+
debugOriginal: benchResults.debugOriginal,
181+
debugWbe: benchResults.debugWbe,
182+
iterations,
183+
testMessages,
184+
completed: true,
185+
})
186+
187+
setIsRunning(false)
188+
}
189+
190+
return (
191+
<div>
192+
<div className="actions">
193+
<button onClick={runBenchmark} disabled={isRunning} className="run-btn">
194+
{isRunning ? "Running..." : "Run Benchmark Again"}
195+
</button>
196+
</div>
197+
198+
{results.completed && <BenchmarkResults results={results} />}
199+
</div>
200+
)
201+
}
202+
203+
const BenchmarkResults = ({ results }: { results: BenchmarkResults }) => {
204+
const { debugOriginal, debugWbe, iterations, testMessages } = results
205+
206+
const originalPerCall = debugOriginal / iterations
207+
const wbePerCall = debugWbe / iterations
208+
const difference = debugWbe - debugOriginal
209+
210+
// Calculate percentage difference
211+
const isWbeFaster = debugWbe < debugOriginal
212+
const percentDiff = isWbeFaster
213+
? ((debugOriginal / debugWbe - 1) * 100).toFixed(2)
214+
: ((debugWbe / debugOriginal - 1) * 100).toFixed(2)
215+
216+
// Calculate bar widths
217+
const maxTime = Math.max(debugOriginal, debugWbe)
218+
const originalBarWidth = `${Math.min(100, (debugOriginal / maxTime) * 100)}%`
219+
const wbeBarWidth = `${Math.min(100, (debugWbe / maxTime) * 100)}%`
220+
221+
return (
222+
<div className="results">
223+
<h2>Benchmark Results</h2>
224+
225+
<div className="summary">
226+
<p>
227+
Total iterations per library: <strong>{iterations}</strong>
228+
</p>
229+
<p className="winner" style={{ color: isWbeFaster ? "green" : "red" }}>
230+
<strong>
231+
{isWbeFaster
232+
? `@wbe/debug is ${percentDiff}% faster`
233+
: `Original debug is ${percentDiff}% faster`}
234+
</strong>
235+
</p>
236+
</div>
237+
238+
<div className="result-bars">
239+
<div className="bar-container">
240+
<div className="bar-label">
241+
Original debug: {debugOriginal.toFixed(2)}ms (
242+
{originalPerCall.toFixed(3)}ms per call)
243+
</div>
244+
<div className="bar original-bar" style={{ width: originalBarWidth }}>
245+
{originalPerCall.toFixed(3)}ms
246+
</div>
247+
</div>
248+
249+
<div className="bar-container">
250+
<div className="bar-label">
251+
@wbe/debug: {debugWbe.toFixed(2)}ms ({wbePerCall.toFixed(3)}ms per
252+
call)
253+
</div>
254+
<div className="bar wbe-bar" style={{ width: wbeBarWidth }}>
255+
{wbePerCall.toFixed(3)}ms
256+
</div>
257+
</div>
258+
</div>
259+
260+
<div className="difference">
261+
<p>Difference: {difference.toFixed(2)}ms</p>
262+
</div>
263+
264+
<div className="test-details">
265+
<h3>Test Details</h3>
266+
<ul>
267+
<li>Iterations: {iterations}</li>
268+
<li>Test performed on: {new Date().toLocaleString()}</li>
269+
<li>Browser: {navigator.userAgent}</li>
270+
</ul>
271+
272+
<h3>Test Messages</h3>
273+
<pre>{JSON.stringify(testMessages, null, 2)}</pre>
274+
</div>
275+
</div>
276+
)
277+
}

bench/bench-browser/src/main.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { render } from "preact"
2+
import { BenchmarkApp } from "./App"
3+
import "./styles/main.scss"
4+
5+
localStorage.setItem("debug", "*")
6+
;(() => {
7+
render(<BenchmarkApp />, document.getElementById("app")!)
8+
})()

0 commit comments

Comments
 (0)