Skip to content

Commit e83726d

Browse files
authored
chore: add traces and histograms to avm simulator (#10233)
Add a histogram for tracking the gas/second of avm enqueued call simulations. Assert that we are above 2.5 Mgas/second in the public transfer test. Also some traces at the enqueued call level. See graph attached. Interestingly, `transfer_in_public` sits constantly around 5.5 Mgas/s, but `total_supply` was the worst at around 3 Mgas/s. <img width="957" alt="Screenshot 2024-11-26 at 21 17 50" src="https://github.com/user-attachments/assets/2f99546c-77e3-47a4-8faf-622e9ac6b9b0"> fix #10145 fix #10146
1 parent 321a175 commit e83726d

File tree

10 files changed

+87
-10
lines changed

10 files changed

+87
-10
lines changed

yarn-project/end-to-end/scripts/e2e_test_config.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ tests:
8484
e2e_state_vars: {}
8585
e2e_static_calls: {}
8686
e2e_synching: {}
87-
e2e_token_contract: {}
87+
e2e_token_contract:
88+
with_alerts: true
8889
e2e_p2p_gossip:
8990
test_path: 'e2e_p2p/gossip_network.test.ts'
9091
with_alerts: true

yarn-project/end-to-end/src/e2e_token_contract/token_contract_test.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
import { mintTokensToPrivate } from '../fixtures/token_utils.js';
1515
import { TokenSimulator } from '../simulators/token_simulator.js';
1616

17-
const { E2E_DATA_PATH: dataPath } = process.env;
17+
const { E2E_DATA_PATH: dataPath, METRICS_PORT: metricsPort } = process.env;
1818

1919
export class TokenContractTest {
2020
static TOKEN_NAME = 'USDC';
@@ -30,7 +30,9 @@ export class TokenContractTest {
3030

3131
constructor(testName: string) {
3232
this.logger = createDebugLogger(`aztec:e2e_token_contract:${testName}`);
33-
this.snapshotManager = createSnapshotManager(`e2e_token_contract/${testName}`, dataPath);
33+
this.snapshotManager = createSnapshotManager(`e2e_token_contract/${testName}`, dataPath, {
34+
metricsPort: metricsPort ? parseInt(metricsPort) : undefined,
35+
});
3436
}
3537

3638
/**

yarn-project/end-to-end/src/e2e_token_contract/transfer_in_public.test.ts

+19
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,23 @@
11
import { Fr } from '@aztec/aztec.js';
22

33
import { U128_UNDERFLOW_ERROR } from '../fixtures/fixtures.js';
4+
import { AlertChecker, type AlertConfig } from '../quality_of_service/alert_checker.js';
45
import { TokenContractTest } from './token_contract_test.js';
56

7+
const CHECK_ALERTS = process.env.CHECK_ALERTS === 'true';
8+
9+
const qosAlerts: AlertConfig[] = [
10+
{
11+
// Dummy alert to check that the metric is being emitted.
12+
// Separate benchmark tests will use dedicated machines with the published system requirements.
13+
alert: 'publishing_mana_per_second',
14+
expr: 'rate(aztec_public_executor_simulation_mana_per_second_per_second_sum[5m]) / rate(aztec_public_executor_simulation_mana_per_second_per_second_count[5m]) < 10',
15+
for: '5m',
16+
annotations: {},
17+
labels: {},
18+
},
19+
];
20+
621
describe('e2e_token_contract transfer public', () => {
722
const t = new TokenContractTest('transfer_in_public');
823
let { asset, accounts, tokenSim, wallets, badAccount } = t;
@@ -17,6 +32,10 @@ describe('e2e_token_contract transfer public', () => {
1732

1833
afterAll(async () => {
1934
await t.teardown();
35+
if (CHECK_ALERTS) {
36+
const alertChecker = new AlertChecker(t.logger);
37+
await alertChecker.runAlertCheck(qosAlerts);
38+
}
2039
});
2140

2241
afterEach(async () => {

yarn-project/end-to-end/src/fixtures/snapshot_manager.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ async function setupFromFresh(
345345
aztecNodeConfig.bbWorkingDirectory = bbConfig.bbWorkingDirectory;
346346
}
347347

348-
const telemetry = await getEndToEndTestTelemetryClient(opts.metricsPort, /*serviceName*/ 'basenode');
348+
const telemetry = await getEndToEndTestTelemetryClient(opts.metricsPort, /*serviceName*/ statePath);
349349

350350
logger.verbose('Creating and synching an aztec node...');
351351
const aztecNode = await AztecNodeService.createAndSync(aztecNodeConfig, { telemetry });

yarn-project/simulator/src/public/executor_metrics.ts

+23-1
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,20 @@ import {
33
type Histogram,
44
Metrics,
55
type TelemetryClient,
6+
type Tracer,
67
type UpDownCounter,
78
ValueType,
9+
linearBuckets,
810
} from '@aztec/telemetry-client';
911

1012
export class ExecutorMetrics {
13+
public readonly tracer: Tracer;
1114
private fnCount: UpDownCounter;
1215
private fnDuration: Histogram;
16+
private manaPerSecond: Histogram;
1317

1418
constructor(client: TelemetryClient, name = 'PublicExecutor') {
19+
this.tracer = client.getTracer(name);
1520
const meter = client.getMeter(name);
1621

1722
this.fnCount = meter.createUpDownCounter(Metrics.PUBLIC_EXECUTOR_SIMULATION_COUNT, {
@@ -23,13 +28,30 @@ export class ExecutorMetrics {
2328
unit: 'ms',
2429
valueType: ValueType.INT,
2530
});
31+
32+
this.manaPerSecond = meter.createHistogram(Metrics.PUBLIC_EXECUTOR_SIMULATION_MANA_PER_SECOND, {
33+
description: 'Mana used per second',
34+
unit: 'mana/s',
35+
valueType: ValueType.INT,
36+
advice: {
37+
explicitBucketBoundaries: linearBuckets(0, 10_000_000, 10),
38+
},
39+
});
2640
}
2741

28-
recordFunctionSimulation(durationMs: number) {
42+
recordFunctionSimulation(durationMs: number, manaUsed: number, fnName: string) {
2943
this.fnCount.add(1, {
3044
[Attributes.OK]: true,
45+
[Attributes.APP_CIRCUIT_NAME]: fnName,
46+
[Attributes.MANA_USED]: manaUsed,
3147
});
3248
this.fnDuration.record(Math.ceil(durationMs));
49+
if (durationMs > 0 && manaUsed > 0) {
50+
const manaPerSecond = Math.round((manaUsed * 1000) / durationMs);
51+
this.manaPerSecond.record(manaPerSecond, {
52+
[Attributes.APP_CIRCUIT_NAME]: fnName,
53+
});
54+
}
3355
}
3456

3557
recordFunctionSimulationFailure() {

yarn-project/simulator/src/public/public_processor.ts

+3
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,9 @@ export class PublicProcessor {
229229
return new PublicDataWrite(leafSlot, updatedBalance);
230230
}
231231

232+
@trackSpan('PublicProcessor.processPrivateOnlyTx', (tx: Tx) => ({
233+
[Attributes.TX_HASH]: tx.getTxHash().toString(),
234+
}))
232235
private async processPrivateOnlyTx(tx: Tx): Promise<[ProcessedTx]> {
233236
const gasFees = this.globalVariables.gasFees;
234237
const transactionFee = tx.data.gasUsed.computeFee(gasFees);

yarn-project/simulator/src/public/public_tx_simulator.ts

+19-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
} from '@aztec/circuits.js';
2121
import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';
2222
import { Timer } from '@aztec/foundation/timer';
23-
import { type TelemetryClient } from '@aztec/telemetry-client';
23+
import { Attributes, type TelemetryClient, type Tracer, trackSpan } from '@aztec/telemetry-client';
2424

2525
import { type AvmFinalizedCallResult } from '../avm/avm_contract_call_result.js';
2626
import { type AvmPersistableStateManager, AvmSimulator } from '../avm/index.js';
@@ -55,15 +55,18 @@ export class PublicTxSimulator {
5555
constructor(
5656
private db: MerkleTreeReadOperations,
5757
private worldStateDB: WorldStateDB,
58-
client: TelemetryClient,
58+
telemetryClient: TelemetryClient,
5959
private globalVariables: GlobalVariables,
6060
private realAvmProvingRequests: boolean = true,
6161
private doMerkleOperations: boolean = false,
6262
) {
6363
this.log = createDebugLogger(`aztec:public_tx_simulator`);
64-
this.metrics = new ExecutorMetrics(client, 'PublicTxSimulator');
64+
this.metrics = new ExecutorMetrics(telemetryClient, 'PublicTxSimulator');
6565
}
6666

67+
get tracer(): Tracer {
68+
return this.metrics.tracer;
69+
}
6770
/**
6871
* Simulate a transaction's public portion including all of its phases.
6972
* @param tx - The transaction to simulate.
@@ -244,6 +247,12 @@ export class PublicTxSimulator {
244247
* @param executionRequest - The execution request (includes args)
245248
* @returns The result of execution.
246249
*/
250+
@trackSpan('PublicTxSimulator.simulateEnqueuedCall', (phase, context, _callRequest, executionRequest) => ({
251+
[Attributes.TX_HASH]: context.getTxHash().toString(),
252+
[Attributes.TARGET_ADDRESS]: executionRequest.callContext.contractAddress.toString(),
253+
[Attributes.SENDER_ADDRESS]: executionRequest.callContext.msgSender.toString(),
254+
[Attributes.SIMULATOR_PHASE]: TxExecutionPhase[phase].toString(),
255+
}))
247256
private async simulateEnqueuedCall(
248257
phase: TxExecutionPhase,
249258
context: PublicTxContext,
@@ -312,6 +321,12 @@ export class PublicTxSimulator {
312321
* @param fnName - The name of the function
313322
* @returns The result of execution.
314323
*/
324+
@trackSpan(
325+
'PublicTxSimulator.simulateEnqueuedCallInternal',
326+
(_stateManager, _executionRequest, _allocatedGas, _transactionFee, fnName) => ({
327+
[Attributes.APP_CIRCUIT_NAME]: fnName,
328+
}),
329+
)
315330
private async simulateEnqueuedCallInternal(
316331
stateManager: AvmPersistableStateManager,
317332
executionRequest: PublicExecutionRequest,
@@ -356,7 +371,7 @@ export class PublicTxSimulator {
356371
if (result.reverted) {
357372
this.metrics.recordFunctionSimulationFailure();
358373
} else {
359-
this.metrics.recordFunctionSimulation(timer.ms());
374+
this.metrics.recordFunctionSimulation(timer.ms(), allocatedGas.sub(result.gasLeft).l2Gas, fnName);
360375
}
361376

362377
return result;

yarn-project/telemetry-client/src/attributes.ts

+5
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,8 @@ export const P2P_ID = 'aztec.p2p.id';
8383
export const POOL_NAME = 'aztec.pool.name';
8484

8585
export const SEQUENCER_STATE = 'aztec.sequencer.state';
86+
87+
export const SIMULATOR_PHASE = 'aztec.simulator.phase';
88+
export const TARGET_ADDRESS = 'aztec.address.target';
89+
export const SENDER_ADDRESS = 'aztec.address.sender';
90+
export const MANA_USED = 'aztec.mana.used';

yarn-project/telemetry-client/src/metrics.ts

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export const PUBLIC_PROCESSOR_DEPLOY_BYTECODE_SIZE = 'aztec.public_processor.dep
7171

7272
export const PUBLIC_EXECUTOR_SIMULATION_COUNT = 'aztec.public_executor.simulation_count';
7373
export const PUBLIC_EXECUTOR_SIMULATION_DURATION = 'aztec.public_executor.simulation_duration';
74+
export const PUBLIC_EXECUTOR_SIMULATION_MANA_PER_SECOND = 'aztec.public_executor.simulation_mana_per_second';
7475
export const PUBLIC_EXECUTION_SIMULATION_BYTECODE_SIZE = 'aztec.public_executor.simulation_bytecode_size';
7576

7677
export const PROVING_ORCHESTRATOR_BASE_ROLLUP_INPUTS_DURATION =

yarn-project/telemetry-client/src/otel.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,16 @@ export class OpenTelemetryClient implements TelemetryClient {
7575
}
7676

7777
public async stop() {
78-
await Promise.all([this.meterProvider.shutdown(), this.loggerProvider.shutdown()]);
78+
const flushAndShutdown = async (provider: { forceFlush: () => Promise<void>; shutdown: () => Promise<void> }) => {
79+
await provider.forceFlush();
80+
await provider.shutdown();
81+
};
82+
83+
await Promise.all([
84+
flushAndShutdown(this.meterProvider),
85+
flushAndShutdown(this.loggerProvider),
86+
this.traceProvider instanceof NodeTracerProvider ? flushAndShutdown(this.traceProvider) : Promise.resolve(),
87+
]);
7988
}
8089

8190
public static async createAndStart(config: TelemetryClientConfig, log: DebugLogger): Promise<OpenTelemetryClient> {

0 commit comments

Comments
 (0)