perf: do bulk read

This commit is contained in:
Florian Dold 2021-08-06 17:15:46 +02:00
parent 05e52d4e11
commit 06db37640e
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
5 changed files with 40 additions and 34 deletions

View File

@ -82,7 +82,7 @@ interface WorkItem {
/** /**
* Time when the work was submitted to a (non-busy) worker thread. * Time when the work was submitted to a (non-busy) worker thread.
*/ */
startTime: number; startTime: BigInt;
} }
/** /**
@ -291,7 +291,7 @@ export class CryptoApi {
resolve, resolve,
reject, reject,
rpcId, rpcId,
startTime: 0, startTime: BigInt(0),
}; };
if (this.numBusy === this.workers.length) { if (this.numBusy === this.workers.length) {

View File

@ -106,8 +106,8 @@ function amountToBuffer(amount: AmountJson): Uint8Array {
if (typeof dvbuf.setBigUint64 !== "undefined") { if (typeof dvbuf.setBigUint64 !== "undefined") {
dvbuf.setBigUint64(0, BigInt(amount.value)); dvbuf.setBigUint64(0, BigInt(amount.value));
} else { } else {
const arr = bigint(amount.value).toArray(2 ** 8).value const arr = bigint(amount.value).toArray(2 ** 8).value;
let offset = 8 - arr.length let offset = 8 - arr.length;
for (let i = 0; i < arr.length; i++) { for (let i = 0; i < arr.length; i++) {
dvbuf.setUint8(offset++, arr[i]); dvbuf.setUint8(offset++, arr[i]);
} }
@ -126,9 +126,12 @@ function timestampRoundedToBuffer(ts: Timestamp): Uint8Array {
const s = BigInt(tsRounded.t_ms) * BigInt(1000); const s = BigInt(tsRounded.t_ms) * BigInt(1000);
v.setBigUint64(0, s); v.setBigUint64(0, s);
} else { } else {
const s = (tsRounded.t_ms === "never" ? bigint.zero : bigint(tsRounded.t_ms).times(1000)); const s =
const arr = s.toArray(2 ** 8).value tsRounded.t_ms === "never"
let offset = 8 - arr.length ? bigint.zero
: bigint(tsRounded.t_ms).times(1000);
const arr = s.toArray(2 ** 8).value;
let offset = 8 - arr.length;
for (let i = 0; i < arr.length; i++) { for (let i = 0; i < arr.length; i++) {
v.setUint8(offset++, arr[i]); v.setUint8(offset++, arr[i]);
} }
@ -139,7 +142,7 @@ function timestampRoundedToBuffer(ts: Timestamp): Uint8Array {
class SignaturePurposeBuilder { class SignaturePurposeBuilder {
private chunks: Uint8Array[] = []; private chunks: Uint8Array[] = [];
constructor(private purposeNum: number) { } constructor(private purposeNum: number) {}
put(bytes: Uint8Array): SignaturePurposeBuilder { put(bytes: Uint8Array): SignaturePurposeBuilder {
this.chunks.push(Uint8Array.from(bytes)); this.chunks.push(Uint8Array.from(bytes));
@ -317,7 +320,8 @@ export class CryptoImplementation {
.build(); .build();
const sig = decodeCrock(denom.masterSig); const sig = decodeCrock(denom.masterSig);
const pub = decodeCrock(masterPub); const pub = decodeCrock(masterPub);
return eddsaVerify(p, sig, pub); const res = eddsaVerify(p, sig, pub);
return res;
} }
isValidWireAccount( isValidWireAccount(
@ -550,14 +554,14 @@ export class CryptoImplementation {
} }
benchmark(repetitions: number): BenchmarkResult { benchmark(repetitions: number): BenchmarkResult {
let time_hash = 0; let time_hash = BigInt(0);
for (let i = 0; i < repetitions; i++) { for (let i = 0; i < repetitions; i++) {
const start = timer.performanceNow(); const start = timer.performanceNow();
this.hashString("hello world"); this.hashString("hello world");
time_hash += timer.performanceNow() - start; time_hash += timer.performanceNow() - start;
} }
let time_hash_big = 0; let time_hash_big = BigInt(0);
for (let i = 0; i < repetitions; i++) { for (let i = 0; i < repetitions; i++) {
const ba = randomBytes(4096); const ba = randomBytes(4096);
const start = timer.performanceNow(); const start = timer.performanceNow();
@ -565,14 +569,14 @@ export class CryptoImplementation {
time_hash_big += timer.performanceNow() - start; time_hash_big += timer.performanceNow() - start;
} }
let time_eddsa_create = 0; let time_eddsa_create = BigInt(0);
for (let i = 0; i < repetitions; i++) { for (let i = 0; i < repetitions; i++) {
const start = timer.performanceNow(); const start = timer.performanceNow();
createEddsaKeyPair(); createEddsaKeyPair();
time_eddsa_create += timer.performanceNow() - start; time_eddsa_create += timer.performanceNow() - start;
} }
let time_eddsa_sign = 0; let time_eddsa_sign = BigInt(0);
const p = randomBytes(4096); const p = randomBytes(4096);
const pair = createEddsaKeyPair(); const pair = createEddsaKeyPair();
@ -585,7 +589,7 @@ export class CryptoImplementation {
const sig = eddsaSign(p, pair.eddsaPriv); const sig = eddsaSign(p, pair.eddsaPriv);
let time_eddsa_verify = 0; let time_eddsa_verify = BigInt(0);
for (let i = 0; i < repetitions; i++) { for (let i = 0; i < repetitions; i++) {
const start = timer.performanceNow(); const start = timer.performanceNow();
eddsaVerify(p, sig, pair.eddsaPub); eddsaVerify(p, sig, pair.eddsaPub);
@ -595,11 +599,11 @@ export class CryptoImplementation {
return { return {
repetitions, repetitions,
time: { time: {
hash_small: time_hash, hash_small: Number(time_hash),
hash_big: time_hash_big, hash_big: Number(time_hash_big),
eddsa_create: time_eddsa_create, eddsa_create: Number(time_eddsa_create),
eddsa_sign: time_eddsa_sign, eddsa_sign: Number(time_eddsa_sign),
eddsa_verify: time_eddsa_verify, eddsa_verify: Number(time_eddsa_verify),
}, },
}; };
} }

View File

@ -306,15 +306,7 @@ export async function getCandidateWithdrawalDenoms(
return await ws.db return await ws.db
.mktx((x) => ({ denominations: x.denominations })) .mktx((x) => ({ denominations: x.denominations }))
.runReadOnly(async (tx) => { .runReadOnly(async (tx) => {
return tx.denominations.indexes.byExchangeBaseUrl return tx.denominations.indexes.byExchangeBaseUrl.getAll(exchangeBaseUrl);
.iter(exchangeBaseUrl)
.filter((d) => {
return (
(d.status === DenominationStatus.Unverified ||
d.status === DenominationStatus.VerifiedGood) &&
!d.isRevoked
);
});
}); });
} }

View File

@ -35,6 +35,7 @@ import {
IDBKeyPath, IDBKeyPath,
} from "@gnu-taler/idb-bridge"; } from "@gnu-taler/idb-bridge";
import { Logger } from "@gnu-taler/taler-util"; import { Logger } from "@gnu-taler/taler-util";
import { performanceNow } from "./timer.js";
const logger = new Logger("query.ts"); const logger = new Logger("query.ts");
@ -298,6 +299,7 @@ export function describeIndex(
interface IndexReadOnlyAccessor<RecordType> { interface IndexReadOnlyAccessor<RecordType> {
iter(query?: IDBValidKey): ResultStream<RecordType>; iter(query?: IDBValidKey): ResultStream<RecordType>;
get(query: IDBValidKey): Promise<RecordType | undefined>; get(query: IDBValidKey): Promise<RecordType | undefined>;
getAll(query: IDBValidKey, count?: number): Promise<RecordType[]>;
} }
type GetIndexReadOnlyAccess<RecordType, IndexMap> = { type GetIndexReadOnlyAccess<RecordType, IndexMap> = {
@ -307,6 +309,7 @@ type GetIndexReadOnlyAccess<RecordType, IndexMap> = {
interface IndexReadWriteAccessor<RecordType> { interface IndexReadWriteAccessor<RecordType> {
iter(query: IDBValidKey): ResultStream<RecordType>; iter(query: IDBValidKey): ResultStream<RecordType>;
get(query: IDBValidKey): Promise<RecordType | undefined>; get(query: IDBValidKey): Promise<RecordType | undefined>;
getAll(query: IDBValidKey, count?: number): Promise<RecordType[]>;
} }
type GetIndexReadWriteAccess<RecordType, IndexMap> = { type GetIndexReadWriteAccess<RecordType, IndexMap> = {
@ -484,6 +487,10 @@ function makeReadContext(
.openCursor(query); .openCursor(query);
return new ResultStream<any>(req); return new ResultStream<any>(req);
}, },
getAll(query, count) {
const req = tx.objectStore(storeName).index(indexName).getAll(query, count);
return requestToPromise(req);
}
}; };
} }
ctx[storeAlias] = { ctx[storeAlias] = {
@ -526,6 +533,10 @@ function makeWriteContext(
.openCursor(query); .openCursor(query);
return new ResultStream<any>(req); return new ResultStream<any>(req);
}, },
getAll(query, count) {
const req = tx.objectStore(storeName).index(indexName).getAll(query, count);
return requestToPromise(req);
}
}; };
} }
ctx[storeAlias] = { ctx[storeAlias] = {

View File

@ -78,24 +78,23 @@ class TimeoutHandle {
} }
/** /**
* Get a performance counter in milliseconds. * Get a performance counter in nanoseconds.
*/ */
export const performanceNow: () => number = (() => { export const performanceNow: () => bigint = (() => {
// @ts-ignore // @ts-ignore
if (typeof process !== "undefined" && process.hrtime) { if (typeof process !== "undefined" && process.hrtime) {
return () => { return () => {
const t = process.hrtime(); return process.hrtime.bigint();
return t[0] * 1e9 + t[1];
}; };
} }
// @ts-ignore // @ts-ignore
if (typeof performance !== "undefined") { if (typeof performance !== "undefined") {
// @ts-ignore // @ts-ignore
return () => performance.now(); return () => BigInt(performance.now()) * BigInt(1000 * 1000);
} }
return () => 0; return () => BigInt(0);
})(); })();
/** /**