]> git.codecow.com Git - nano-pow.git/commitdiff
Reduce RNG calls by generating up front into larger typed array.
authorChris Duncan <chris@codecow.com>
Mon, 25 May 2026 09:10:44 +0000 (02:10 -0700)
committerChris Duncan <chris@codecow.com>
Mon, 25 May 2026 09:10:44 +0000 (02:10 -0700)
src/lib/generate/wasm/index.ts
src/lib/generate/webgl/index.ts
src/lib/generate/webgpu/index.ts
src/utils/bigint.ts

index 87eae923d94770fd6aed712abaa1432af4ad8a29..d8e0bf2e4d81d5ca8d693a9e015ea2945e35ee0e 100644 (file)
@@ -2,7 +2,7 @@
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
 import { NanoPowValidate } from '#lib/validate'
-import { BytesToHex, Logger, bigintRandom, isBytes } from '#utils'
+import { BytesToHex, Logger, isBytes } from '#utils'
 import { WorkGenerateResponse } from 'nano-pow'
 import { NanoPowWasmWorker } from './worker.js'
 
@@ -73,8 +73,10 @@ async function workersStarted () {
 async function dispatch (): Promise<Bytes> {
        return new Promise(next => {
                const attempts = []
-               for (const w of workers) {
-                       data.seed = bigintRandom() & ~((1n << 24n) - 1n)
+               const seed = crypto.getRandomValues(new BigUint64Array(workers.length))
+               for (let i = 0; i < workers.length; i++) {
+                       data.seed = seed[i] & ~((1n << 24n) - 1n)
+                       const w = workers[i]
                        const attempt = new Promise((resolve, reject) => {
                                w.onerror = reject
                                w.onmessage = (msg) => resolve(msg.data)
index 1169c638dca394b552efde04dbba959a4f777453..a86f2d7c477467b0500ca81dcd6cf95ebf4a4059 100644 (file)
@@ -2,7 +2,7 @@
 //! SPDX-FileContributor: Ben Green <ben@latenightsketches.com>
 //! SPDX-License-Identifier: GPL-3.0-or-later AND MIT
 
-import { BytesToHex, Logger, bigintRandom, bigintToHex } from '#utils'
+import { BytesToHex, Logger, bigintToHex } from '#utils'
 import { WorkGenerateResponse } from 'nano-pow'
 import { downsampleSource, drawSource, quadSource } from './shaders'
 
@@ -417,6 +417,7 @@ export async function generate (hash: Bytes, difficulty: bigint, effort: number,
        LOG: logger.log(`generate('${BytesToHex(hash.buffer)}', '${difficulty.toString(16)}', ${effort}, ${debug})`)
 
        // Start drawing to calculate one nonce per pixel
+       const seed = new BigUint64Array(4)
        let found = false
        let result: Record<string, bigint> = {}
        let isFirstRetry = false
@@ -427,13 +428,15 @@ export async function generate (hash: Bytes, difficulty: bigint, effort: number,
                                        setup(effort)
                                }
                                init(new Uint32Array(hash.buffer), difficulty)
+                               crypto.getRandomValues(seed)
                                LOG: logger.log('drawing frame 0')
-                               draw(bigintRandom(), drawFbos[0], queries[0])
-                               draw(bigintRandom(), drawFbos[1], queries[1])
-                               draw(bigintRandom(), drawFbos[2], queries[2])
+                               draw(seed[0], drawFbos[0], queries[0])
+                               draw(seed[1], drawFbos[1], queries[1])
+                               draw(seed[2], drawFbos[2], queries[2])
                                let drawIndex = 3
                                do {
-                                       draw(bigintRandom(), drawFbos[drawIndex], queries[drawIndex])
+                                       if (drawIndex === 0) crypto.getRandomValues(seed)
+                                       draw(seed[drawIndex], drawFbos[drawIndex], queries[drawIndex])
                                        drawIndex = (drawIndex + 1) % 4
                                        found = await check(queries[drawIndex])
                                } while (!found && !timeout)
index 081b0ebc9cacf476ecd2cf034762358cf0f694b6..50a5efe7421628b62d8a04b86f42bac5b0a67087 100644 (file)
@@ -1,7 +1,7 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-import { BytesToHex, Logger, Queue, bigintRandom, bigintToHex } from '#utils'
+import { BytesToHex, Logger, Queue, bigintToHex } from '#utils'
 import { WorkGenerateResponse } from 'nano-pow'
 import { default as NanoPowGpuComputeShader } from './shaders/compute.wgsl'
 
@@ -205,7 +205,7 @@ async function init (hash: Bytes, difficulty: bigint): Promise<void> {
 async function dispatch (dispatchIndex: number, seed: bigint, effort: number): Promise<void> {
        LOG: logger.log('dispatching compute pass')
        try {
-               LOG: logger.log('seed', bigintToHex(seed, 16))
+               LOG: logger.log('seed', seed.toString(16).padStart(16, '0'))
 
                // Copy seed into INPUT buffer
                inputDataView.setBigUint64(40, seed, true)
@@ -280,6 +280,7 @@ export async function generate (hash: Bytes, difficulty: bigint, effort: number,
        }, 60_000)
        LOG: logger.groupStart('NanoPow WebGPU work_generate')
        LOG: logger.log('generating')
+       const seed = new BigUint64Array(2)
        let found = false
        let result: Record<string, bigint> = {}
        let isFirstRetry = false
@@ -295,11 +296,12 @@ export async function generate (hash: Bytes, difficulty: bigint, effort: number,
                                }
                                await q.add(init, hash, difficulty)
                                // Dispatch initial workgroups and set index
-                               await dispatch(0, bigintRandom(), effort)
+                               await dispatch(0, crypto.getRandomValues(seed)[0], effort)
                                let dispatchIndex = 1
                                // Loop attempts until valid work found
                                do {
-                                       await dispatch(dispatchIndex, bigintRandom(), effort)
+                                       if (dispatchIndex === 0) crypto.getRandomValues(seed)
+                                       await dispatch(dispatchIndex, seed[dispatchIndex], effort)
                                        dispatchIndex ^= 1
                                        found = await check(dispatchIndex)
                                } while (!found && !timeout)
index 85b26ac95cb1cafa432fd17f9d458d5b24ee5d48..4bc3a30f168b55db1942b0746d4d75c851f789aa 100644 (file)
@@ -1,41 +1,6 @@
 //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
-export function bigintBitLength (int: bigint): bigint {
-       let bitLength = 1n
-       while (int > 1n || int < -1n) {
-               bitLength++
-               int >>= 1n
-       }
-       return bitLength
-}
-
-export function bigintByteLength (int: bigint): number {
-       let byteLength = 0
-       while (int > 0n || int < -1n) {
-               byteLength++
-               int >>= 8n
-       }
-       return byteLength
-}
-
-export function bigintRandom (): bigint {
-       const mask = 0xFFFFFFFFFFFFFFFFn
-       const randomUint8Array = new Uint8Array(8)
-       let output = 0n
-       do {
-               output = 0n
-               crypto.getRandomValues(randomUint8Array)
-               output = BigInt(randomUint8Array[0])
-               for (let i = 1; i < randomUint8Array.length; i++) {
-                       output <<= 8n
-                       output += BigInt(randomUint8Array[i])
-               }
-               output &= mask
-       } while (output > mask)
-       return output
-}
-
 export function bigintToHex (int: bigint, length: unknown = 0): string {
        if (typeof length !== 'number') {
                throw new TypeError('invalid length')