Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add new metrics #3855

Merged
merged 8 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { toBigIntBE, toBufferBE } from '@aztec/foundation/bigint-buffer';
import { createDebugLogger } from '@aztec/foundation/log';
import { Timer } from '@aztec/foundation/timer';
import { IndexedTreeLeaf, IndexedTreeLeafPreimage } from '@aztec/foundation/trees';
import { Hasher, SiblingPath } from '@aztec/types';
import { TreeInsertionStats } from '@aztec/types/stats';

import { LevelUp } from 'levelup';

Expand Down Expand Up @@ -507,6 +509,7 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree {
leaves: Buffer[],
subtreeHeight: SubtreeHeight,
): Promise<BatchInsertionResult<TreeHeight, SubtreeSiblingPathHeight>> {
const timer = new Timer();
const insertedKeys = new Map<bigint, boolean>();
const emptyLowLeafWitness = getEmptyLowLeafWitness(this.getDepth() as TreeHeight, this.leafPreimageFactory);
// Accumulators
Expand Down Expand Up @@ -603,6 +606,15 @@ export class StandardIndexedTree extends TreeBase implements IndexedTree {
// inclusion. See {@link encodeLeaf} for a more through param explanation.
await this.encodeAndAppendLeaves(pendingInsertionSubtree, false);

this.log(`Inserted ${leaves.length} leaves into ${this.getName()} tree`, {
eventName: 'tree-insertion',
duration: timer.ms(),
batchSize: leaves.length,
treeName: this.getName(),
treeDepth: this.getDepth(),
treeType: 'indexed',
} satisfies TreeInsertionStats);

return {
lowLeavesWitnessData: lowLeavesWitnesses,
sortedNewLeaves: sortedDescendingLeafTuples.map(leafTuple => leafTuple.leaf.toBuffer()),
Expand Down
12 changes: 12 additions & 0 deletions yarn-project/merkle-tree/src/standard_tree/standard_tree.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { Timer } from '@aztec/foundation/timer';
import { TreeInsertionStats } from '@aztec/types/stats';

import { AppendOnlySnapshotBuilder, TreeSnapshot } from '../index.js';
import { AppendOnlyTree } from '../interfaces/append_only_tree.js';
import { TreeBase } from '../tree_base.js';
Expand All @@ -14,7 +17,16 @@ export class StandardTree extends TreeBase implements AppendOnlyTree {
* @returns Empty promise.
*/
public async appendLeaves(leaves: Buffer[]): Promise<void> {
const timer = new Timer();
await super.appendLeaves(leaves);
this.log(`Inserted ${leaves.length} leaves into ${this.getName()} tree`, {
eventName: 'tree-insertion',
duration: timer.ms(),
batchSize: leaves.length,
treeName: this.getName(),
treeDepth: this.getDepth(),
treeType: 'append-only',
} satisfies TreeInsertionStats);
}

public snapshot(block: number): Promise<TreeSnapshot> {
Expand Down
4 changes: 4 additions & 0 deletions yarn-project/merkle-tree/src/tree_base.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { toBigIntLE, toBufferLE } from '@aztec/foundation/bigint-buffer';
import { DebugLogger, createDebugLogger } from '@aztec/foundation/log';
import { Hasher, SiblingPath } from '@aztec/types';

import { LevelUp, LevelUpChain } from 'levelup';
Expand Down Expand Up @@ -36,6 +37,7 @@ export abstract class TreeBase implements MerkleTree {
private root!: Buffer;
private zeroHashes: Buffer[] = [];
private cache: { [key: string]: Buffer } = {};
protected log: DebugLogger;

public constructor(
protected db: LevelUp,
Expand All @@ -58,6 +60,8 @@ export abstract class TreeBase implements MerkleTree {

this.root = root ? root : current;
this.maxIndex = 2n ** BigInt(depth) - 1n;

this.log = createDebugLogger(`aztec:merkle-tree:${name}`);
}

/**
Expand Down
8 changes: 8 additions & 0 deletions yarn-project/pxe/src/pxe_service/pxe_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { padArrayEnd } from '@aztec/foundation/collection';
import { Fr } from '@aztec/foundation/fields';
import { SerialQueue } from '@aztec/foundation/fifo';
import { DebugLogger, createDebugLogger } from '@aztec/foundation/log';
import { Timer } from '@aztec/foundation/timer';
import { NoirWasmVersion } from '@aztec/noir-compiler/versions';
import {
AuthWitness,
Expand Down Expand Up @@ -52,6 +53,7 @@ import {
getNewContractPublicFunctions,
isNoirCallStackUnresolved,
} from '@aztec/types';
import { TxPXEProcessingStats } from '@aztec/types/stats';

import { PXEServiceConfig, getPackageInfo } from '../config/index.js';
import { ContractDataOracle } from '../contract_data_oracle/index.js';
Expand Down Expand Up @@ -353,7 +355,13 @@ export class PXEService implements PXE {
const deployedContractAddress = txRequest.txContext.isContractDeploymentTx ? txRequest.origin : undefined;
const newContract = deployedContractAddress ? await this.db.getContract(deployedContractAddress) : undefined;

const timer = new Timer();
const tx = await this.#simulateAndProve(txRequest, newContract);
this.log(`Processed private part of ${tx.data.end.newNullifiers[0]}`, {
eventName: 'tx-pxe-processing',
duration: timer.ms(),
...tx.getStats(),
} satisfies TxPXEProcessingStats);
if (simulatePublic) {
await this.#simulatePublicCalls(tx);
}
Expand Down
29 changes: 29 additions & 0 deletions yarn-project/scripts/src/benchmarks/aggregate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ import {
NodeSyncedChainHistoryStats,
NoteProcessorCaughtUpStats,
Stats,
TreeInsertionStats,
TxAddedToPoolStats,
TxPXEProcessingStats,
TxSequencerProcessingStats,
} from '@aztec/types/stats';

import * as fs from 'fs';
Expand Down Expand Up @@ -151,6 +154,26 @@ function processTxAddedToPool(entry: TxAddedToPoolStats, results: BenchmarkColle
append(results, 'tx_size_in_bytes', entry.newContractCount, entry.size);
}

/** Process entries for events tx-private-part-processed, grouped by new commitments */
function processTxPXEProcessingStats(entry: TxPXEProcessingStats, results: BenchmarkCollectedResults) {
append(results, 'tx_pxe_processing_time_ms', entry.newCommitmentCount, entry.duration);
}

/** Process entries for events tx-public-part-processed, grouped by public data writes */
function processTxSequencerProcessingStats(entry: TxSequencerProcessingStats, results: BenchmarkCollectedResults) {
append(results, 'tx_sequencer_processing_time_ms', entry.publicDataUpdateRequests, entry.duration);
}

/** Process a tree insertion event and updates results */
function processTreeInsertion(entry: TreeInsertionStats, results: BenchmarkCollectedResults) {
const bucket = entry.batchSize;
if (entry.treeType === 'append-only') {
append(results, 'batch_insert_into_append_only_tree_ms', bucket, entry.duration);
} else if (entry.treeType === 'indexed') {
append(results, 'batch_insert_into_indexed_tree_ms', bucket, entry.duration);
}
}

/** Processes a parsed entry from a log-file and updates results */
function processEntry(entry: Stats, results: BenchmarkCollectedResults) {
switch (entry.eventName) {
Expand All @@ -168,6 +191,12 @@ function processEntry(entry: Stats, results: BenchmarkCollectedResults) {
return processNodeSyncedChain(entry, results);
case 'tx-added-to-pool':
return processTxAddedToPool(entry, results);
case 'tx-pxe-processing':
return processTxPXEProcessingStats(entry, results);
case 'tx-sequencer-processing':
return processTxSequencerProcessingStats(entry, results);
case 'tree-insertion':
return processTreeInsertion(entry, results);
default:
return;
}
Expand Down
30 changes: 25 additions & 5 deletions yarn-project/scripts/src/benchmarks/markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,13 @@ function getCell(
row: string,
col: string,
) {
const value = data[row][col];
const value: number | undefined = data[row][col];
const formattedValue = formatValue(value);
const baseValue = base ? (base[row] ?? {})[col] : undefined;
const percentDiff = baseValue ? Math.round(((value - baseValue) / baseValue) * 100) : undefined;
const baseValue: number | undefined = base?.[row]?.[col];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't know this syntax, cool!

const percentDiff =
typeof baseValue === 'number' && typeof value === 'number'
? Math.round(((value - baseValue) / baseValue) * 100)
: undefined;
alexghr marked this conversation as resolved.
Show resolved Hide resolved
if (!percentDiff || Math.abs(percentDiff) < 1) {
return formattedValue;
}
Expand All @@ -118,7 +121,11 @@ function withDesc(name: string) {
}

/** Formats a numeric value for display. */
function formatValue(value: number) {
function formatValue(value: number | undefined): string {
if (typeof value === 'undefined') {
return 'N/A';
}

if (value < 100) {
return value.toPrecision(3);
}
Expand Down Expand Up @@ -180,6 +187,10 @@ export function getMarkdown() {
const metricsByChainLength = Metrics.filter(m => m.groupBy === 'chain-length').map(m => m.name);
const metricsByCircuitName = Metrics.filter(m => m.groupBy === 'circuit-name').map(m => m.name);
const metricsByContractCount = Metrics.filter(m => m.groupBy === 'contract-count').map(m => m.name);
const metricsByLeafCount = Metrics.filter(m => m.groupBy === 'leaf-count').map(m => m.name);

const metricsTxPxeProcessing = Metrics.filter(m => m.name === 'tx_pxe_processing_time_ms').map(m => m.name);
const metricsTxSeqProcessing = Metrics.filter(m => m.name === 'tx_sequencer_processing_time_ms').map(m => m.name);

const baseHash = process.env.BASE_COMMIT_HASH;
const baseUrl = baseHash && `[\`${baseHash.slice(0, 8)}\`](${S3_URL}/benchmarks-v1/master/${baseHash}.json)`;
Expand All @@ -202,7 +213,7 @@ ${getWarningsSummary(benchmark, baseBenchmark)}

<summary>Detailed results</summary>

All benchmarks are run on txs on the \`Benchmarking\` contract on the repository. Each tx consists of a batch call to \`create_note\` and \`increment_balance\`, which guarantees that each tx has a private call, a nested private call, a public call, and a nested public call, as well as an emitted private note, an unencrypted log, and public storage read and write.
All benchmarks are run on txs on the \`Benchmarking\` contract on the repository. Each tx consists of a batch call to \`create_note\` and \`increment_balance\`, which guarantees that each tx has a private call, a nested private call, a public call, and a nested public call, as well as an emitted private note, an unencrypted log, and public storage read and write.
${prSourceDataText}
${baseCommitText}

Expand All @@ -221,11 +232,20 @@ ${getTableContent(pick(benchmark, metricsByChainLength), baseBenchmark, 'blocks'
Stats on running time and I/O sizes collected for every circuit run across all benchmarks.
${getTableContent(transpose(pick(benchmark, metricsByCircuitName)), transpose(baseBenchmark), '', 'Circuit')}

### Tree insertion stats

The duration to insert a fixed batch of leaves into each tree type.
${getTableContent(pick(benchmark, metricsByLeafCount), baseBenchmark, 'leaves')}

### Miscellaneous

Transaction sizes based on how many contracts are deployed in the tx.
${getTableContent(pick(benchmark, metricsByContractCount), baseBenchmark, 'deployed contracts')}

Transaction processing duration by data writes.
${getTableContent(pick(benchmark, metricsTxPxeProcessing), baseBenchmark, 'new commitments')}
${getTableContent(pick(benchmark, metricsTxSeqProcessing), baseBenchmark, 'public data writes')}

</details>
${COMMENT_MARK}
`;
Expand Down
15 changes: 14 additions & 1 deletion yarn-project/sequencer-client/src/sequencer/public_processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ import { computeVarArgsHash } from '@aztec/circuits.js/abis';
import { arrayNonEmptyLength, isArrayEmpty, padArrayEnd } from '@aztec/foundation/collection';
import { createDebugLogger } from '@aztec/foundation/log';
import { to2Fields } from '@aztec/foundation/serialize';
import { Timer } from '@aztec/foundation/timer';
import { ContractDataSource, FunctionL2Logs, L1ToL2MessageSource, MerkleTreeId, Tx } from '@aztec/types';
import { TxSequencerProcessingStats } from '@aztec/types/stats';
import { MerkleTreeOperations } from '@aztec/world-state';

import { getVerificationKeys } from '../index.js';
Expand Down Expand Up @@ -159,12 +161,23 @@ export class PublicProcessor {

protected async processTx(tx: Tx): Promise<ProcessedTx> {
if (!isArrayEmpty(tx.data.end.publicCallStack, item => item.isEmpty())) {
const timer = new Timer();

const [publicKernelOutput, publicKernelProof, newUnencryptedFunctionLogs] = await this.processEnqueuedPublicCalls(
tx,
);
tx.unencryptedLogs.addFunctionLogs(newUnencryptedFunctionLogs);

return makeProcessedTx(tx, publicKernelOutput, publicKernelProof);
const processedTransaction = await makeProcessedTx(tx, publicKernelOutput, publicKernelProof);
this.log(`Processed public part of ${tx.data.end.newNullifiers[0]}`, {
eventName: 'tx-sequencer-processing',
duration: timer.ms(),
publicDataUpdateRequests:
processedTransaction.data.end.publicDataUpdateRequests.filter(x => !x.leafSlot.isZero()).length ?? 0,
...tx.getStats(),
} satisfies TxSequencerProcessingStats);

return processedTransaction;
} else {
return makeProcessedTx(tx);
}
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/types/src/logs/log_filter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AztecAddress, FunctionSelector } from '@aztec/circuits.js';

import { TxHash } from '../tx/index.js';
import { TxHash } from '../tx/tx_hash.js';
import { LogId } from './log_id.js';

/**
Expand Down
32 changes: 31 additions & 1 deletion yarn-project/types/src/stats/metrics.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { StatsEventName } from './stats.js';

/** How a metric is grouped in benchmarks: by block size, by length of chain processed, or by circuit name. */
export type MetricGroupBy = 'block-size' | 'chain-length' | 'circuit-name' | 'contract-count';
export type MetricGroupBy =
| 'block-size'
| 'chain-length'
| 'circuit-name'
| 'contract-count'
| 'leaf-count'
| 'data-writes';

/** Definition of a metric to track in benchmarks. */
export interface Metric {
Expand Down Expand Up @@ -127,6 +133,30 @@ export const Metrics = [
description: 'Size of txs received in the mempool.',
events: ['tx-added-to-pool'],
},
{
name: 'tx_pxe_processing_time_ms',
groupBy: 'data-writes',
description: 'Time to process the private part of a tx.',
events: ['tx-pxe-processing'],
},
{
name: 'tx_sequencer_processing_time_ms',
groupBy: 'data-writes',
description: 'Time to process the public part of a tx.',
events: ['tx-sequencer-processing'],
},
{
name: 'batch_insert_into_append_only_tree_ms',
groupBy: 'leaf-count',
description: 'Time to insert a batch of leaves into an append-only tree',
events: ['tree-insertion'],
},
{
name: 'batch_insert_into_indexed_tree_ms',
groupBy: 'leaf-count',
description: 'Time to insert a batch of leaves into an indexed tree',
events: ['tree-insertion'],
},
] as const satisfies readonly Metric[];

/** Metric definitions to track from benchmarks. */
Expand Down
49 changes: 48 additions & 1 deletion yarn-project/types/src/stats/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,50 @@ export type TxStats = {
newContractDataSize: number;
/** Number of new contracts deployed in this tx. */
newContractCount: number;
/** comm */
newCommitmentCount: number;
/** a */
newNullifierCount: number;
};

/**
* Stats for a tx that has been processed by the public processor.
*/
export type TxPXEProcessingStats = {
/** Name of the event. */
eventName: 'tx-pxe-processing';
/** Duration in ms. */
duration: number;
} & TxStats;

/**
* Stats for a tx that has been processed by the public processor.
*/
export type TxSequencerProcessingStats = {
/** Name of the event. */
eventName: 'tx-sequencer-processing';
/** Duration in ms. */
duration: number;
/** Count of how many public writes this tx has made. Acts as a proxy for how 'heavy' this tx */
publicDataUpdateRequests: number;
} & TxStats;

/**
* Stats for tree insertions
*/
export type TreeInsertionStats = {
/** Name of the event. */
eventName: 'tree-insertion';
/** Duration in ms. */
duration: number;
/** The size of the insertion batch */
batchSize: number;
/** The tree name */
treeName: string;
/** The tree depth */
treeDepth: number;
/** Tree type */
treeType: 'append-only' | 'indexed';
};

/** A new tx was added to the tx pool. */
Expand All @@ -154,7 +198,10 @@ export type Stats =
| L2BlockBuiltStats
| L2BlockHandledStats
| NoteProcessorCaughtUpStats
| TxAddedToPoolStats;
| TxAddedToPoolStats
| TxPXEProcessingStats
| TxSequencerProcessingStats
| TreeInsertionStats;

/** Set of event names across emitted stats. */
export type StatsEventName = Stats['eventName'];
Loading
Loading