From 85ac13842ed35e12e4b50ee06465d717c716f70c Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Sun, 8 Dec 2024 03:19:59 -0800 Subject: [PATCH] Add function to calculate different types of average times. Expand existing performance testing and add block pow performance tests. Replace underperforming reduce function with for loop. --- GLOBALS.mjs | 15 ++++++++ perf/account.perf.js | 91 ++++++++++++++++++++++++++------------------ perf/block.perf.js | 60 +++++++++++++++++++++++++++++ perf/main.mjs | 3 +- perf/wallet.perf.js | 52 +++++++++++++++---------- src/lib/convert.ts | 7 ++-- 6 files changed, 167 insertions(+), 61 deletions(-) create mode 100644 perf/block.perf.js diff --git a/GLOBALS.mjs b/GLOBALS.mjs index 4d269f2..563ff8e 100644 --- a/GLOBALS.mjs +++ b/GLOBALS.mjs @@ -16,6 +16,21 @@ if (globalThis.sessionStorage == null) { }) } +export function average (times) { + let sum = 0, reciprocals = 0, product = 1, count = times.length + for (let i = 0; i < count; i++) { + sum += times[i] + reciprocals += 1 / times[i] + product *= times[i] + } + return { + total: sum, + arithmetic: sum / count, + harmonic: count / reciprocals, + geometric: Math.pow(product, 1 / count) + } +} + const failures = [] const passes = [] function fail (...args) { diff --git a/perf/account.perf.js b/perf/account.perf.js index 612414e..32a0d0e 100644 --- a/perf/account.perf.js +++ b/perf/account.perf.js @@ -3,47 +3,64 @@ 'use strict' -import { assert, skip, test } from '#GLOBALS.mjs' +import { assert, average, skip, suite, test } from '#GLOBALS.mjs' import { NANO_TEST_VECTORS } from '#test/TEST_VECTORS.js' import { Bip44Wallet, Blake2bWallet } from '#dist/main.js' -await test('total time to create 0x8000 BIP-44 accounts', async () => { - const wallet = await Bip44Wallet.create(NANO_TEST_VECTORS.PASSWORD) - await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) - let now = performance.now() - const accounts = await wallet.accounts(0, 0x7fff) - console.log(`${performance.now() - now} ms`) - assert.equals(accounts.length, 0x8000) -}) - -await test('average time to create 1 BIP-44 account 0x80 times', async () => { - const wallet = await Bip44Wallet.create(NANO_TEST_VECTORS.PASSWORD) - await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) - let now = performance.now() - for (let i = 0; i < 0x80; i++) { - await wallet.accounts(i) - } - const avg = (performance.now() - now) / 0x80 - console.log(`${avg} ms`) -}) +await suite('Account performance', async () => { + await test('Time to create 0x2000 BIP-44 accounts', async () => { + const wallet = await Bip44Wallet.create(NANO_TEST_VECTORS.PASSWORD) + await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) + const start = performance.now() + const accounts = await wallet.accounts(0, 0x1fff) + const end = performance.now() + console.log(`Total: ${end - start} ms`) + console.log(`Average: ${(end - start) / 0x2000} ms`) + assert.equals(accounts.length, 0x2000) + }) -await test('create 0x8000 BLAKE2b accounts', async () => { - const wallet = await Blake2bWallet.create(NANO_TEST_VECTORS.PASSWORD) - await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) - let now = performance.now() - const accounts = await wallet.accounts(0, 0x7fff) - console.log(`${performance.now() - now} ms`) - assert.equals(accounts.length, 0x8000) -}) + await test('Time to create 1 BIP-44 account 0x20 times', async () => { + const times = [] + const wallet = await Bip44Wallet.create(NANO_TEST_VECTORS.PASSWORD) + await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) + for (let i = 0; i < 0x20; i++) { + const start = performance.now() + await wallet.accounts(i) + const end = performance.now() + times.push(end - start) + } + const { total, arithmetic, harmonic, geometric } = average(times) + console.log(`Total: ${total} ms`) + console.log(`Average: ${arithmetic} ms`) + console.log(`Harmonic: ${harmonic} ms`) + console.log(`Geometric: ${geometric} ms`) + }) + await test('Time to create 0x2000 BLAKE2b accounts', async () => { + const wallet = await Blake2bWallet.create(NANO_TEST_VECTORS.PASSWORD) + await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) + const start = performance.now() + const accounts = await wallet.accounts(0, 0x1fff) + const end = performance.now() + console.log(`Total: ${end - start} ms`) + console.log(`Average: ${(end - start) / 0x2000} ms`) + assert.equals(accounts.length, 0x2000) + }) -await test('average time to create 1 BLAKE2b account 0x80 times', async () => { - const wallet = await Blake2bWallet.create(NANO_TEST_VECTORS.PASSWORD) - await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) - let now = performance.now() - for (let i = 0; i < 0x80; i++) { - await wallet.accounts(i) - } - const avg = (performance.now() - now) / 0x80 - console.log(`${avg} ms`) + await test('Average time to create 1 BLAKE2b account 0x20 times', async () => { + const times = [] + const wallet = await Blake2bWallet.create(NANO_TEST_VECTORS.PASSWORD) + await wallet.unlock(NANO_TEST_VECTORS.PASSWORD) + for (let i = 0; i < 0x20; i++) { + const start = performance.now() + await wallet.accounts(i) + const end = performance.now() + times.push(end - start) + } + const { total, arithmetic, harmonic, geometric } = average(times) + console.log(`Total: ${total} ms`) + console.log(`Average: ${arithmetic} ms`) + console.log(`Harmonic: ${harmonic} ms`) + console.log(`Geometric: ${geometric} ms`) + }) }) diff --git a/perf/block.perf.js b/perf/block.perf.js new file mode 100644 index 0000000..adbb37d --- /dev/null +++ b/perf/block.perf.js @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: 2024 Chris Duncan +// SPDX-License-Identifier: GPL-3.0-or-later + +'use strict' + +import { assert, average, skip, suite, test } from '#GLOBALS.mjs' +import { NANO_TEST_VECTORS } from '#test/TEST_VECTORS.js' +import { SendBlock, ReceiveBlock } from '#dist/main.js' + +await suite('Block performance', async () => { + const COUNT = 0x10 + + await test('Time to calculate proof-of-work for a send block 0x10 times', async () => { + const times = [] + const block = new SendBlock( + NANO_TEST_VECTORS.SEND_BLOCK.account, + NANO_TEST_VECTORS.SEND_BLOCK.balance, + NANO_TEST_VECTORS.SEND_BLOCK.link, + '0', + NANO_TEST_VECTORS.SEND_BLOCK.representative, + NANO_TEST_VECTORS.SEND_BLOCK.previous + ) + for (let i = 0; i < COUNT; i++) { + const start = performance.now() + await block.pow() + const end = performance.now() + times.push(end - start) + console.log(`${end - start} ms`) + } + const { total, arithmetic, harmonic, geometric } = average(times) + console.log(`Total: ${total} ms`) + console.log(`Average: ${arithmetic} ms`) + console.log(`Harmonic: ${harmonic} ms`) + console.log(`Geometric: ${geometric} ms`) + }) + + await test('Time to calculate proof-of-work for a send block 0x10 times', async () => { + const times = [] + const block = new ReceiveBlock( + NANO_TEST_VECTORS.RECEIVE_BLOCK.account, + NANO_TEST_VECTORS.RECEIVE_BLOCK.balance, + NANO_TEST_VECTORS.RECEIVE_BLOCK.link, + '0', + NANO_TEST_VECTORS.RECEIVE_BLOCK.representative, + NANO_TEST_VECTORS.RECEIVE_BLOCK.previous + ) + for (let i = 0; i < COUNT; i++) { + const start = performance.now() + await block.pow() + const end = performance.now() + times.push(end - start) + console.log(`${end - start} ms`) + } + const { total, arithmetic, harmonic, geometric } = average(times) + console.log(`Total: ${total} ms`) + console.log(`Average: ${arithmetic} ms`) + console.log(`Harmonic: ${harmonic} ms`) + console.log(`Geometric: ${geometric} ms`) + }) +}) diff --git a/perf/main.mjs b/perf/main.mjs index b80898f..23ff8a9 100644 --- a/perf/main.mjs +++ b/perf/main.mjs @@ -1,8 +1,9 @@ // SPDX-FileCopyrightText: 2024 Chris Duncan // SPDX-License-Identifier: GPL-3.0-or-later -import './account.perf.js' import './wallet.perf.js' +import './account.perf.js' +import './block.perf.js' document.addEventListener('load', () => { console.log('> TESTING COMPLETE <') diff --git a/perf/wallet.perf.js b/perf/wallet.perf.js index 0e92618..7ed3b14 100644 --- a/perf/wallet.perf.js +++ b/perf/wallet.perf.js @@ -3,28 +3,40 @@ 'use strict' -import { assert, skip, test } from '#GLOBALS.mjs' +import { assert, average, skip, suite, test } from '#GLOBALS.mjs' import { NANO_TEST_VECTORS } from '#test/TEST_VECTORS.js' import { Bip44Wallet, Blake2bWallet } from '#dist/main.js' -await test('creating BIP-44 wallets performance test', async () => { - const seeds = [] - let now = performance.now() - for (let i = 0x80; i > 0; i--) { - const wallet = await Bip44Wallet.create(NANO_TEST_VECTORS.PASSWORD) - seeds.push(wallet.seed) - } - console.log(`${performance.now() - now} ms`) - assert.equals(seeds.length, 0x80) -}) +await suite(`Wallet performance`, async () => { + const COUNT = 0x20 + + await test(`Time to create ${COUNT} BIP-44 wallets`, async () => { + const times = [] + for (let i = 0; i < COUNT; i++) { + const start = performance.now() + const wallet = await Bip44Wallet.create(NANO_TEST_VECTORS.PASSWORD) + const end = performance.now() + times.push(end - start) + } + const { total, arithmetic, harmonic, geometric } = average(times) + console.log(`Total: ${total} ms`) + console.log(`Average: ${arithmetic} ms`) + console.log(`Harmonic: ${harmonic} ms`) + console.log(`Geometric: ${geometric} ms`) + }) -await test('creating BLAKE2b wallets performance test', async () => { - const seeds = [] - let now = performance.now() - for (let i = 0x80; i > 0; i--) { - const wallet = await Blake2bWallet.create(NANO_TEST_VECTORS.PASSWORD) - seeds.push(wallet.seed) - } - console.log(`${performance.now() - now} ms`) - assert.equals(seeds.length, 0x80) + await test(`Time to create ${COUNT} BLAKE2b wallets`, async () => { + const times = [] + for (let i = 0; i < COUNT; i++) { + const start = performance.now() + const wallet = await Blake2bWallet.create(NANO_TEST_VECTORS.PASSWORD) + const end = performance.now() + times.push(end - start) + } + const { total, arithmetic, harmonic, geometric } = average(times) + console.log(`Total: ${total} ms`) + console.log(`Average: ${arithmetic} ms`) + console.log(`Harmonic: ${harmonic} ms`) + console.log(`Geometric: ${geometric} ms`) + }) }) diff --git a/src/lib/convert.ts b/src/lib/convert.ts index 80c8003..08fe685 100644 --- a/src/lib/convert.ts +++ b/src/lib/convert.ts @@ -169,9 +169,10 @@ export const bytes = { toDec (bytes: Uint8Array): bigint | number { const integers: bigint[] = [] bytes.reverse().forEach(b => integers.push(BigInt(b))) - const decimal = integers.reduce((sum, byte, index) => { - return sum + (byte << BigInt(index * 8)) - }) + let decimal = 0n + for (let i = 0; i < integers.length; i++) { + decimal += integers[i] << BigInt(i * 8) + } if (decimal > 9007199254740991n) { return decimal } else { -- 2.34.1