From: Chris Duncan Date: Mon, 16 Jun 2025 20:56:52 +0000 (-0700) Subject: Add --score option to CLI to calculate work-per-second. X-Git-Tag: v5.0.0~8 X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=84b92d3d2b6a257301b8a0be9ed150a226592a4a;p=nano-pow.git Add --score option to CLI to calculate work-per-second. --- diff --git a/package.json b/package.json index 7a9ac78..21e92c2 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "glgenerate": "cd src/lib/generate/webgl/shaders && rm -rf build && tsc && node build/generate.js > build/draw.frag && cp tsconfig.json* build", "gpugenerate": "cd src/lib/generate/webgpu/shaders && rm -rf build && tsc && node build/generate.js > build/compute.wgsl && cp tsconfig.json* build", "prepare": "npm run build", + "score": "npm run build && ./dist/bin/nano-pow.sh --effort 4 --benchmark 100 --score 100", "start": "./dist/bin/nano-pow.sh --server", "test": "npm run build && ./test/script.sh" }, diff --git a/src/bin/cli.ts b/src/bin/cli.ts index 1f0db16..8242b57 100755 --- a/src/bin/cli.ts +++ b/src/bin/cli.ts @@ -50,6 +50,7 @@ If using --validate, results will also include validity properties. -h, --help show this dialog --debug enable additional logging output --benchmark generate work for specified number of random hashes + --score used with --benchmark to run specified number of times and calculate work-per-second If validating a nonce, it must be a 16-character hexadecimal value. Effort must be a decimal number between 1-32. @@ -75,6 +76,7 @@ hashes.push(...inArgs) let isBatch = false let isBenchmark = false +let runs = 1 const body: { [key: string]: any } = { action: 'work_generate' } @@ -120,6 +122,14 @@ for (let i = 0; i < args.length; i++) { process.env.NANO_POW_EFFORT = e break } + case ('--score'): { + const s = args[i + 1] + if (s == null) throw new Error('Missing argument for score') + const count = +s + if (count < 1) throw new Error('Invalid score runs count') + runs = count + break + } case ('--validate'): case ('-v'): { const v = args[i + 1] @@ -169,7 +179,15 @@ server.on('message', async (msg: Serializable): Promise => { if (msg.data === 'ipc') { logger.log(`CLI connected to server over IPC`) try { - await execute() + if (isBenchmark) { + if (runs > 1) { + await score() + } else { + await benchmark() + } + } else { + await execute() + } } catch { logger.log(`Error executing ${body.action}`) } finally { @@ -189,45 +207,78 @@ server.on('close', code => { process.exit(code) }) -async function execute (): Promise { - const results: (WorkErrorResponse | WorkGenerateResponse | WorkValidateResponse)[] = [] - if (isBenchmark) { - console.log('Running benchmark...') - } - let start = 0 +async function benchmark () { + console.log('Running benchmark...') + let start = 0, end = 0 const times: number[] = [] for (const hash of hashes) { + const kill = setTimeout(() => { + throw new Error('cli execution timed out') + }, 60_000) + body.hash = hash try { - const aborter = new AbortController() - const kill = setTimeout(() => aborter.abort(), 60_000) - body.hash = hash start = performance.now() - const result: WorkGenerateResponse | WorkValidateResponse | WorkErrorResponse = await new Promise((resolve, reject): void => { - const listener = async (msg: Serializable): Promise => { - if (typeof msg === 'object' && msg != null - && 'type' in msg && typeof msg.type === 'string' - && 'data' in msg && typeof msg.data === 'string' - ) { - if (msg.type === 'ipc') { - resolve(JSON.parse(msg.data)) - server.off('message', listener) - } - } - } - server.on('message', listener) - server.send({ type: 'ipc', data: JSON.stringify(body) }, cb => cb ? reject(cb) : logger.log('cli ipc request to server')) - }) + await request(body) + end = performance.now() + times.push(end - start) + } catch (err) { + logger.log(err) + } finally { clearTimeout(kill) - if (isBatch || isBenchmark) { - results.push(result) - times.push(performance.now() - start) - } else { - console.log(result) + } + } + console.log(stats(times)) + return stats(times) +} + +async function execute (): Promise { + const results: (WorkErrorResponse | WorkGenerateResponse | WorkValidateResponse)[] = [] + for (const hash of hashes) { + const kill = setTimeout(() => { + throw new Error('cli execution timed out') + }, 60_000) + body.hash = hash + try { + const result = await request(body) + isBatch ? results.push(result) : console.log(result) + } catch (err) { + logger.log(err) + } finally { + clearTimeout(kill) + } + } + if (isBatch) console.log(results) +} + +async function request (body: { [key: string]: any }): Promise { + return new Promise((resolve, reject): void => { + const listener = async (msg: Serializable): Promise => { + if (typeof msg === 'object' && msg != null + && 'type' in msg && typeof msg.type === 'string' + && 'data' in msg && typeof msg.data === 'string' + ) { + if (msg.type === 'ipc') { + resolve(JSON.parse(msg.data)) + server.off('message', listener) + } } + } + server.on('message', listener) + server.send({ type: 'ipc', data: JSON.stringify(body) }, cb => cb ? reject(cb) : logger.log('cli ipc request to server')) + }) +} + +async function score (): Promise { + console.log('Calculating work per second...') + const rates: number[] = [] + for (let i = 0; i < runs; i++) { + try { + const result = await benchmark() + logger.log(result) + if (result != null) rates.push(result.truncatedArithmetic) } catch (err) { logger.log(err) } } - if (isBatch && !isBenchmark) console.log(results) - if (process.env.NANO_POW_DEBUG || isBenchmark) console.log(stats(times)) + console.log(stats(rates)?.truncatedHarmonic, 'wps') }