Skip to content

Commit 3ef744e

Browse files
committed
wip
1 parent f676c34 commit 3ef744e

File tree

5 files changed

+108
-18
lines changed

5 files changed

+108
-18
lines changed

yarn-project/end-to-end/src/bench/client_flows/amm.test.ts

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,27 @@ const AMOUNT_PER_NOTE = 1_000_000;
2020

2121
const MINIMUM_NOTES_FOR_RECURSION_LEVEL = [0, 2, 10];
2222

23+
/**
24+
* Expected number of node round trips per account contract and payment method.
25+
* These values are measured per single execution (stats are reset before each profile).
26+
* Update these values after verifying that any changes to round trip counts are intentional.
27+
*
28+
* Unfortunately these values depend on the test running in the expected sequence.
29+
*/
30+
const EXPECTED_ROUND_TRIPS: Record<string, number> = {
31+
// 'ecdsar1+bridged_fee_juice': 32,
32+
'ecdsar1+private_fpc': 266, // 215 when run on it's own? why?
33+
'ecdsar1+sponsored_fpc': 139,
34+
// 'ecdsar1+fee_juice': 32,
35+
// 'schnorr+bridged_fee_juice': 32,
36+
'schnorr+private_fpc': 506,
37+
'schnorr+sponsored_fpc': 289,
38+
// 'schnorr+fee_juice': 32,
39+
};
40+
2341
describe('AMM benchmark', () => {
42+
// Disable RPC batching by setting maxBatchSize to 0
43+
// This ensures accurate round trip measurements in the benchmark
2444
const t = new ClientFlowsBenchmark('amm');
2545
// The wallet used by the admin to interact
2646
let adminWallet: Wallet;
@@ -73,9 +93,11 @@ describe('AMM benchmark', () => {
7393
await t.teardown();
7494
});
7595

76-
for (const accountType of config.accounts) {
77-
ammBenchmark(accountType);
78-
}
96+
// for (const accountType of config.accounts) {
97+
// ammBenchmark(accountType);
98+
// }
99+
ammBenchmark('ecdsar1');
100+
// ammBenchmark('schnorr');
79101

80102
function ammBenchmark(accountType: AccountType) {
81103
return describe(`AMM benchmark for ${accountType}`, () => {
@@ -158,7 +180,7 @@ describe('AMM benchmark', () => {
158180
.methods.add_liquidity(amountToSend, amountToSend, amountToSend, amountToSend, nonceForAuthwits)
159181
.with({ authWitnesses: [token0Authwit, token1Authwit] });
160182

161-
await captureProfile(
183+
const profileResult = await captureProfile(
162184
`${accountType}+amm_add_liquidity_1_recursions+${benchmarkingPaymentMethod}`,
163185
addLiquidityInteraction,
164186
options,
@@ -176,6 +198,34 @@ describe('AMM benchmark', () => {
176198
1, // Kernel hiding
177199
);
178200

201+
// Log round trip details
202+
const roundTripStats = profileResult.stats.nodeRPCCalls?.roundTrips;
203+
if (roundTripStats) {
204+
console.log(`\n=== Round Trip Details for ${accountType}+${benchmarkingPaymentMethod} ===`);
205+
console.log(`Total round trips: ${roundTripStats.roundTrips}`);
206+
console.log(`Total blocking time: ${roundTripStats.totalBlockingTime.toFixed(2)}ms`);
207+
console.log('\nPer round trip:');
208+
for (let i = 0; i < roundTripStats.roundTripMethods.length; i++) {
209+
const methods = roundTripStats.roundTripMethods[i];
210+
const duration = roundTripStats.roundTripDurations[i];
211+
console.log(` RT ${i + 1}: ${duration.toFixed(2)}ms - [${methods.join(', ')}]`);
212+
}
213+
console.log('');
214+
}
215+
216+
// Check that the number of round trips matches the expected value.
217+
// This serves as a regression test - if round trips change, update EXPECTED_ROUND_TRIPS.
218+
const roundTripsKey = `${accountType}+${benchmarkingPaymentMethod}`;
219+
const actualRoundTrips = profileResult.stats.nodeRPCCalls?.roundTrips.roundTrips ?? 0;
220+
const expectedRoundTrips = EXPECTED_ROUND_TRIPS[roundTripsKey];
221+
if (expectedRoundTrips === undefined) {
222+
throw new Error(
223+
`Missing expected round trips for ${roundTripsKey}. ` +
224+
`Add '${roundTripsKey}': ${actualRoundTrips} to EXPECTED_ROUND_TRIPS.`,
225+
);
226+
}
227+
expect(actualRoundTrips).toBe(expectedRoundTrips);
228+
179229
if (process.env.SANITY_CHECKS) {
180230
const tx = await addLiquidityInteraction.send({ from: benchysAddress }).wait();
181231
expect(tx.transactionFee!).toBeGreaterThan(0n);
@@ -184,9 +234,11 @@ describe('AMM benchmark', () => {
184234
});
185235
}
186236

187-
for (const paymentMethod of config.feePaymentMethods) {
188-
addLiquidityTest(paymentMethod);
189-
}
237+
// for (const paymentMethod of config.feePaymentMethods) {
238+
// addLiquidityTest(paymentMethod);
239+
// }
240+
// addLiquidityTest('private_fpc');
241+
addLiquidityTest('sponsored_fpc');
190242
});
191243
}
192244
});

yarn-project/end-to-end/src/bench/client_flows/benchmark.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ export function generateBenchmark(
221221
const totalGateCount = steps[steps.length - 1].accGateCount;
222222
const nodeRPCCalls = stats.nodeRPCCalls ?? {
223223
perMethod: {},
224-
roundTrips: { roundTrips: 0, totalBlockingTime: 0, roundTripDurations: [] },
224+
roundTrips: { roundTrips: 0, totalBlockingTime: 0, roundTripDurations: [], roundTripMethods: [] },
225225
};
226226
return {
227227
name: flow,

yarn-project/pxe/src/contract_function_simulator/contract_function_simulator.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,10 @@ export class ContractFunctionSimulator {
333333
const nodeRPCCalls =
334334
typeof (this.aztecNode as ProxiedNode).getStats === 'function'
335335
? (this.aztecNode as ProxiedNode).getStats()
336-
: { perMethod: {}, roundTrips: { roundTrips: 0, totalBlockingTime: 0, roundTripDurations: [] } };
336+
: {
337+
perMethod: {},
338+
roundTrips: { roundTrips: 0, totalBlockingTime: 0, roundTripDurations: [], roundTripMethods: [] },
339+
};
337340

338341
return { nodeRPCCalls };
339342
}

yarn-project/pxe/src/contract_function_simulator/proxied_node.ts

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ export class ProxiedNodeFactory {
2020
// Round trip tracking
2121
let inFlightCount = 0;
2222
let currentRoundTripTimer: Timer | null = null;
23+
let currentRoundTripMethods: string[] = [];
2324
const roundTrips: RoundTripStats = {
2425
roundTrips: 0,
2526
totalBlockingTime: 0,
2627
roundTripDurations: [],
28+
roundTripMethods: [],
2729
};
2830

2931
return new Proxy(node, {
@@ -43,18 +45,18 @@ export class ProxiedNodeFactory {
4345
if (inFlightCount === 0) {
4446
roundTrips.roundTrips++;
4547
currentRoundTripTimer = new Timer();
48+
currentRoundTripMethods = [];
4649
}
4750
inFlightCount++;
51+
currentRoundTripMethods.push(prop);
4852

4953
const callTimer = new Timer();
50-
// Use try/finally to ensure cleanup even if the RPC call throws.
51-
// Without this, a failed call would leave inFlightCount incremented,
52-
// breaking round trip tracking for all subsequent calls.
53-
try {
54-
return (target[prop] as any).apply(target, args);
55-
} finally {
54+
const result = (target[prop] as any).apply(target, args);
55+
56+
// Handle completion - called when the call finishes (after Promise resolves)
57+
const handleCompletion = () => {
5658
const callTime = callTimer.ms();
57-
perMethod[prop].times.push(callTime);
59+
perMethod[prop]!.times.push(callTime);
5860

5961
inFlightCount--;
6062

@@ -63,8 +65,28 @@ export class ProxiedNodeFactory {
6365
const roundTripTime = currentRoundTripTimer.ms();
6466
roundTrips.totalBlockingTime += roundTripTime;
6567
roundTrips.roundTripDurations.push(roundTripTime);
68+
roundTrips.roundTripMethods.push(currentRoundTripMethods);
6669
currentRoundTripTimer = null;
70+
currentRoundTripMethods = [];
6771
}
72+
};
73+
74+
// If the result is a Promise, chain the completion handler
75+
if (result && typeof result.then === 'function') {
76+
return result.then(
77+
(value: any) => {
78+
handleCompletion();
79+
return value;
80+
},
81+
(error: any) => {
82+
handleCompletion();
83+
throw error;
84+
},
85+
);
86+
} else {
87+
// Synchronous method - handle completion immediately
88+
handleCompletion();
89+
return result;
6890
}
6991
};
7092
}

yarn-project/stdlib/src/tx/profiling.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@ export type RoundTripStats = {
1313
totalBlockingTime: number;
1414
/** Individual round trip durations */
1515
roundTripDurations: number[];
16+
/** Methods called in each round trip (parallel calls grouped together) */
17+
roundTripMethods: string[][];
1618
};
1719

1820
const RoundTripStatsSchema = z.object({
1921
roundTrips: z.number(),
2022
totalBlockingTime: z.number(),
2123
roundTripDurations: z.array(z.number()),
24+
roundTripMethods: z.array(z.array(z.string())),
2225
});
2326

2427
export type NodeStats = {
@@ -130,7 +133,12 @@ export class TxProfileResult {
130133
{
131134
nodeRPCCalls: {
132135
perMethod: { getBlockHeader: { times: [1] } },
133-
roundTrips: { roundTrips: 1, totalBlockingTime: 1, roundTripDurations: [1] },
136+
roundTrips: {
137+
roundTrips: 1,
138+
totalBlockingTime: 1,
139+
roundTripDurations: [1],
140+
roundTripMethods: [['getBlockHeader']],
141+
},
134142
},
135143
timings: {
136144
sync: 1,
@@ -168,7 +176,12 @@ export class UtilitySimulationResult {
168176
return new UtilitySimulationResult([Fr.random()], {
169177
nodeRPCCalls: {
170178
perMethod: { getBlockHeader: { times: [1] } },
171-
roundTrips: { roundTrips: 1, totalBlockingTime: 1, roundTripDurations: [1] },
179+
roundTrips: {
180+
roundTrips: 1,
181+
totalBlockingTime: 1,
182+
roundTripDurations: [1],
183+
roundTripMethods: [['getBlockHeader']],
184+
},
172185
},
173186
timings: {
174187
sync: 1,

0 commit comments

Comments
 (0)