]> git.codecow.com Git - nano-pow.git/commitdiff
Add --score option to CLI to calculate work-per-second.
authorChris Duncan <chris@zoso.dev>
Mon, 16 Jun 2025 20:56:52 +0000 (13:56 -0700)
committerChris Duncan <chris@zoso.dev>
Mon, 16 Jun 2025 20:56:52 +0000 (13:56 -0700)
package.json
src/bin/cli.ts

index 7a9ac78068316d436c94d6286a02ad3281767c65..21e92c21fdb2315c1282a55b801e53e0d68626af 100644 (file)
@@ -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"
        },
index 1f0db16997045d5ba0e9ef3b13a11db3a24dda0a..8242b57e653a86f691f4a07f214edc11b63f8ec3 100755 (executable)
@@ -50,6 +50,7 @@ If using --validate, results will also include validity properties.
   -h, --help                  show this dialog
       --debug                 enable additional logging output
       --benchmark <value>     generate work for specified number of random hashes
+      --score <value>         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<void> => {
                        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<void> {
-       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<void> => {
-                                       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<void> {
+       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<WorkGenerateResponse | WorkValidateResponse | WorkErrorResponse> {
+       return new Promise((resolve, reject): void => {
+               const listener = async (msg: Serializable): Promise<void> => {
+                       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<void> {
+       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')
 }