feat(benchmark): allow running benchmarks individually

This commit is contained in:
2025-07-14 20:50:05 +02:00
parent d5ceaad797
commit fab389f4e4

View File

@@ -1,6 +1,5 @@
// import * as wasm from "@pow-captcha/solver-wasm";
import * as powCaptcha from "@pow-captcha/pow-captcha"; import * as powCaptcha from "@pow-captcha/pow-captcha";
import { useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useState } from "react";
async function benchmark(cb: () => void | Promise<void>): Promise<number> { async function benchmark(cb: () => void | Promise<void>): Promise<number> {
const start = performance.now(); const start = performance.now();
@@ -10,75 +9,90 @@ async function benchmark(cb: () => void | Promise<void>): Promise<number> {
} }
export default function App() { export default function App() {
const [durationJs, _setDurationJs] = useState<null | number>(null); const [challenge, setChallenge] =
const [durationWasm, setDurationWasm] = useState<null | number>(null); useState<null | powCaptcha.wire.Challenge>(null);
const [runBenchmark, setRunBenchmark] = useState(false); const [durationJs, setDurationJs] = useState<null | string>(null);
const [durationWasm, setDurationWasm] = useState<null | string>(null);
const initStartedRef = useRef(false);
useEffect(() => { useEffect(() => {
if (!runBenchmark || initStartedRef.current) {
return;
}
initStartedRef.current = true;
async function init() { async function init() {
const challengesRaw = await powCaptcha.server.createChallengesRaw({ const challengesRaw = await powCaptcha.server.createChallengesRaw({
difficultyBits: 18, difficultyBits: 19,
challengeCount: 32, challengeCount: 64,
}); });
setChallenge(challengesRaw);
const challenges = challengesRaw.challenges.map(
(challenge) =>
[
powCaptcha.wire.deserializeArray(challenge[0]),
powCaptcha.wire.deserializeArray(challenge[1]),
] as const,
);
const durationWasm = await benchmark(async () => {
const solutions = await powCaptcha.solver.solveChallenges({
difficultyBits: challengesRaw.difficultyBits,
challenges,
engine: "wasm",
});
console.log("wasm solutions", solutions);
});
setDurationWasm(durationWasm);
// const durationJs = await benchmark(async () => {
// const solutions = await powCaptcha.solver.solveChallenges({
// difficultyBits: challengesRaw.difficultyBits,
// challenges,
// engine: "js",
// });
// console.log("js solutions", solutions);
// });
// setDurationJs(durationJs);
} }
init(); init();
}, [runBenchmark]); }, []);
const run = useCallback(
async (
engine: "wasm" | "js",
setter: React.Dispatch<React.SetStateAction<string | null>>,
) => {
try {
if (!challenge) {
return;
}
setter(`Running`);
const challenges = challenge.challenges.map(
(challenge) =>
[
powCaptcha.wire.deserializeArray(challenge[0]),
powCaptcha.wire.deserializeArray(challenge[1]),
] as const,
);
const duration = await benchmark(async () => {
await powCaptcha.solver.solveChallenges({
difficultyBits: challenge.difficultyBits,
challenges,
engine,
});
});
setter(`${duration.toFixed(1)}ms`);
} catch (err) {
setter(`Error: ${err}`);
}
},
[challenge],
);
const runJs = useCallback(async () => {
await run("js", setDurationJs);
}, [run]);
const runWasm = useCallback(async () => {
await run("wasm", setDurationWasm);
}, [run]);
return ( return (
<div> <div>
<h1>pow-captcha Benchmark</h1> <h1>pow-captcha Benchmark</h1>
<button onClick={() => setRunBenchmark(true)}>run</button>
Results: Results:
<table> <table>
<tr> <tr>
<th>type</th> <th>type</th>
<th>duration</th> <th>duration</th>
<th></th>
</tr> </tr>
<tr> <tr>
<td>wasm</td> <td>wasm</td>
<td>{durationWasm}ms</td> <td>{durationWasm}</td>
<td>
<button onClick={runWasm}>run</button>
</td>
</tr> </tr>
<tr> <tr>
<td>js</td> <td>js</td>
<td>{durationJs}ms</td> <td>{durationJs}</td>
<td>
<button onClick={runJs}>run</button>
</td>
</tr> </tr>
</table> </table>
</div> </div>