Skip to content

Commit

Permalink
chore: track avm proving time
Browse files Browse the repository at this point in the history
  • Loading branch information
fcarreiro committed Jun 18, 2024
1 parent bf6b8b8 commit f812ad7
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 41 deletions.
1 change: 1 addition & 0 deletions yarn-project/bb-prover/src/avm_proving.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ const proveAndVerifyAvmTestContract = async (
const publicInputs = getPublicInputs(pxResult);

const avmCircuitInputs = new AvmCircuitInputs(
functionName,
uncompressedBytecode,
context.environment.calldata,
publicInputs,
Expand Down
14 changes: 7 additions & 7 deletions yarn-project/bb-prover/src/prover/bb_native_proof_creator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { type NoirCompiledCircuit } from '@aztec/types/noir';
import { serializeWitness } from '@noir-lang/noirc_abi';
import { type WitnessMap } from '@noir-lang/types';
import * as fs from 'fs/promises';
import { join } from 'path';

import {
BB_RESULT,
Expand Down Expand Up @@ -175,7 +176,7 @@ export class BBNativeProofCreator implements ProofCreator {
throw new Error(errorMessage);
}

this.log.info(`Successfully verified ${circuitType} proof in ${result.duration} ms`);
this.log.info(`Successfully verified ${circuitType} proof in ${Math.ceil(result.duration)} ms`);
}

private async verifyProofFromKey(
Expand Down Expand Up @@ -304,13 +305,14 @@ export class BBNativeProofCreator implements ProofCreator {
}> {
const compressedBincodedWitness = serializeWitness(partialWitness);

const inputsWitnessFile = `${directory}/witness.gz`;
const inputsWitnessFile = join(directory, 'witness.gz');

await fs.writeFile(inputsWitnessFile, compressedBincodedWitness);

this.log.debug(`Written ${inputsWitnessFile}`);

this.log.info(`Proving ${circuitType} circuit...`);
const dbgCircuitName = appCircuitName ? `(${appCircuitName})` : '';
this.log.info(`Proving ${circuitType}${dbgCircuitName} circuit...`);

const timer = new Timer();

Expand All @@ -324,13 +326,11 @@ export class BBNativeProofCreator implements ProofCreator {
);

if (provingResult.status === BB_RESULT.FAILURE) {
this.log.error(`Failed to generate proof for ${circuitType}: ${provingResult.reason}`);
this.log.error(`Failed to generate proof for ${circuitType}${dbgCircuitName}: ${provingResult.reason}`);
throw new Error(provingResult.reason);
}

this.log.info(
`Generated ${circuitType === 'App' ? appCircuitName : circuitType} circuit proof in ${timer.ms()} ms`,
);
this.log.info(`Generated ${circuitType}${dbgCircuitName} circuit proof in ${Math.ceil(timer.ms())} ms`);

if (circuitType === 'App') {
const vkData = await extractVkData(directory);
Expand Down
36 changes: 15 additions & 21 deletions yarn-project/bb-prover/src/prover/bb_prover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -439,35 +439,30 @@ export class BBNativeRollupProver implements ServerCircuitProver {
const rawProof = await fs.readFile(`${provingResult.proofPath!}/${PROOF_FILENAME}`);

const proof = new Proof(rawProof, vkData.numPublicInputs);
logger.info(
`Generated proof for ${circuitType} in ${Math.ceil(provingResult.duration)} ms, size: ${
proof.buffer.length
} bytes`,
{
circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
// does not include reading the proof from disk
duration: provingResult.duration,
proofSize: proof.buffer.length,
eventName: 'circuit-proving',
// circuitOutput is the partial witness that became the input to the proof
inputSize: output.toBuffer().length,
circuitSize: vkData.circuitSize,
numPublicInputs: vkData.numPublicInputs,
} satisfies CircuitProvingStats,
);
logger.info(`Generated proof for ${circuitType} in ${Math.ceil(provingResult.duration)} ms`, {
circuitName: mapProtocolArtifactNameToCircuitName(circuitType),
// does not include reading the proof from disk
duration: provingResult.duration,
proofSize: proof.buffer.length,
eventName: 'circuit-proving',
// circuitOutput is the partial witness that became the input to the proof
inputSize: output.toBuffer().length,
circuitSize: vkData.circuitSize,
numPublicInputs: vkData.numPublicInputs,
} satisfies CircuitProvingStats);

return { circuitOutput: output, proof };
};
return await runInDirectory(this.config.bbWorkingDirectory, operation);
}

private async generateAvmProofWithBB(input: AvmCircuitInputs, workingDirectory: string): Promise<BBSuccess> {
logger.debug(`Proving avm-circuit...`);
logger.info(`Proving avm-circuit for ${input.functionName}...`);

const provingResult = await generateAvmProof(this.config.bbBinaryPath, workingDirectory, input, logger.verbose);

if (provingResult.status === BB_RESULT.FAILURE) {
logger.error(`Failed to generate proof for avm-circuit: ${provingResult.reason}`);
logger.error(`Failed to generate AVM proof for ${input.functionName}: ${provingResult.reason}`);
throw new Error(provingResult.reason);
}

Expand All @@ -490,11 +485,10 @@ export class BBNativeRollupProver implements ServerCircuitProver {

const circuitType = 'avm-circuit' as const;
logger.info(
`Generated proof for ${circuitType} in ${Math.ceil(provingResult.duration)} ms, size: ${
proof.buffer.length
} bytes`,
`Generated proof for ${circuitType}(${input.functionName}) in ${Math.ceil(provingResult.duration)} ms`,
{
circuitName: circuitType,
appCircuitName: input.functionName,
// does not include reading the proof from disk
duration: provingResult.duration,
proofSize: proof.buffer.length,
Expand Down
1 change: 1 addition & 0 deletions yarn-project/circuit-types/src/tx/processed_tx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export const AVM_REQUEST = 'AVM' as const;

export type AvmProvingRequest = {
type: typeof AVM_REQUEST;
functionName: string; // informational only
bytecode: Buffer;
calldata: Fr[];
avmHints: AvmExecutionHints;
Expand Down
17 changes: 13 additions & 4 deletions yarn-project/circuits.js/src/structs/avm/avm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ export class AvmExecutionHints {

export class AvmCircuitInputs {
constructor(
public readonly functionName: string, // only informational
public readonly bytecode: Buffer,
public readonly calldata: Fr[],
public readonly publicInputs: PublicCircuitPublicInputs,
Expand All @@ -378,7 +379,10 @@ export class AvmCircuitInputs {
* @returns - The inputs serialized to a buffer.
*/
toBuffer() {
const functionNameBuffer = Buffer.from(this.functionName);
return serializeToBuffer(
functionNameBuffer.length,
functionNameBuffer,
this.bytecode.length,
this.bytecode,
this.calldata.length,
Expand All @@ -402,7 +406,11 @@ export class AvmCircuitInputs {
*/
isEmpty(): boolean {
return (
this.bytecode.length == 0 && this.calldata.length == 0 && this.publicInputs.isEmpty() && this.avmHints.isEmpty()
this.functionName.length == 0 &&
this.bytecode.length == 0 &&
this.calldata.length == 0 &&
this.publicInputs.isEmpty() &&
this.avmHints.isEmpty()
);
}

Expand All @@ -421,7 +429,7 @@ export class AvmCircuitInputs {
* @returns An array of fields.
*/
static getFields(fields: FieldsOf<AvmCircuitInputs>) {
return [fields.bytecode, fields.calldata, fields.publicInputs, fields.avmHints] as const;
return [fields.functionName, fields.bytecode, fields.calldata, fields.publicInputs, fields.avmHints] as const;
}

/**
Expand All @@ -432,8 +440,9 @@ export class AvmCircuitInputs {
static fromBuffer(buff: Buffer | BufferReader): AvmCircuitInputs {
const reader = BufferReader.asReader(buff);
return new AvmCircuitInputs(
reader.readBuffer(),
reader.readVector(Fr),
/*functionName=*/ reader.readBuffer().toString(),
/*bytecode=*/ reader.readBuffer(),
/*calldata=*/ reader.readVector(Fr),
PublicCircuitPublicInputs.fromBuffer(reader),
AvmExecutionHints.fromBuffer(reader),
);
Expand Down
1 change: 1 addition & 0 deletions yarn-project/circuits.js/src/tests/factories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1336,6 +1336,7 @@ export function makeAvmExecutionHints(
*/
export function makeAvmCircuitInputs(seed = 0, overrides: Partial<FieldsOf<AvmCircuitInputs>> = {}): AvmCircuitInputs {
return AvmCircuitInputs.from({
functionName: `function${seed}`,
bytecode: makeBytes((seed % 100) + 100, seed),
calldata: makeArray((seed % 100) + 10, i => new Fr(i), seed + 0x1000),
publicInputs: makePublicCircuitPublicInputs(seed + 0x2000),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,7 @@ export class ProvingOrchestrator {
// Nothing downstream depends on the AVM proof yet. So having this mode lets us incrementally build the AVM circuit.
const doAvmProving = async (signal: AbortSignal) => {
const inputs: AvmCircuitInputs = new AvmCircuitInputs(
publicFunction.vmRequest!.functionName,
publicFunction.vmRequest!.bytecode,
publicFunction.vmRequest!.calldata,
publicFunction.vmRequest!.kernelRequest.inputs.publicCall.callStackItem.publicInputs,
Expand Down
6 changes: 3 additions & 3 deletions yarn-project/scripts/src/benchmarks/aggregate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,11 @@ function processCircuitSimulation(entry: CircuitSimulationStats, results: Benchm
* Buckets are circuit names
*/
function processCircuitProving(entry: CircuitProvingStats, results: BenchmarkCollectedResults) {
if (entry.circuitName === 'app-circuit') {
const bucket = entry.appCircuitName;
if (!bucket) {
if (entry.circuitName === 'app-circuit' || entry.circuitName === 'avm-circuit') {
if (!entry.appCircuitName) {
return;
}
const bucket = entry.appCircuitName + (entry.circuitName === 'avm-circuit' ? ' (avm)' : '');
append(results, 'app_circuit_proving_time_in_ms', bucket, entry.duration);
append(results, 'app_circuit_proof_size_in_bytes', bucket, entry.proofSize);
append(results, 'app_circuit_size_in_gates', bucket, entry.circuitSize);
Expand Down
20 changes: 15 additions & 5 deletions yarn-project/simulator/src/public/abstract_phase_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export const PhaseIsRevertible: Record<PublicKernelType, boolean> = {
};

export type PublicProvingInformation = {
functionName: string; // informational only
calldata: Fr[];
bytecode: Buffer;
inputs: PublicKernelCircuitPrivateInputs;
Expand All @@ -89,6 +90,7 @@ export function makeAvmProvingRequest(
): AvmProvingRequest {
return {
type: AVM_REQUEST,
functionName: info.functionName,
bytecode: info.bytecode,
calldata: info.calldata,
avmHints: info.avmHints,
Expand Down Expand Up @@ -274,6 +276,13 @@ export abstract class AbstractPhaseManager {
)
: current;

// For debug and stats.
const functionName =
(await this.publicExecutor.contractsDb.getDebugFunctionName(
result.execution.contractAddress,
result.execution.functionSelector,
)) ?? 'unknown';

// Accumulate gas used in this execution
gasUsed = gasUsed.add(Gas.from(result.startGasLeft).sub(Gas.from(result.endGasLeft)));

Expand All @@ -282,13 +291,13 @@ export abstract class AbstractPhaseManager {
const functionSelector = result.execution.functionSelector.toString();
if (result.reverted && !result.revertReason) {
throw new Error(
`Simulation of ${result.execution.contractAddress.toString()}:${functionSelector} reverted with no reason.`,
`Simulation of ${result.execution.contractAddress.toString()}:${functionSelector}(${functionName}) reverted with no reason.`,
);
}

if (result.reverted && !PhaseIsRevertible[this.phase]) {
this.log.debug(
`Simulation error on ${result.execution.contractAddress.toString()}:${functionSelector} with reason: ${
`Simulation error on ${result.execution.contractAddress.toString()}:${functionSelector}(${functionName}) with reason: ${
result.revertReason
}`,
);
Expand All @@ -302,14 +311,15 @@ export abstract class AbstractPhaseManager {

// Simulate the public kernel circuit.
this.log.debug(
`Running public kernel circuit for ${result.execution.contractAddress.toString()}:${functionSelector}`,
`Running public kernel circuit for ${result.execution.contractAddress.toString()}:${functionSelector}(${functionName})`,
);
const callData = await this.getPublicCallData(result, isExecutionRequest);
const [privateInputs, publicInputs] = await this.runKernelCircuit(kernelPublicOutput, callData);
kernelPublicOutput = publicInputs;

// Capture the inputs for later proving in the AVM and kernel.
const publicProvingInformation: PublicProvingInformation = {
functionName: functionName,
calldata: result.calldata,
bytecode: result.bytecode!,
inputs: privateInputs,
Expand All @@ -322,15 +332,15 @@ export abstract class AbstractPhaseManager {
// but the kernel carries the reverted flag forward. But if the simulator reverts, so should the kernel.
if (result.reverted && kernelPublicOutput.revertCode.isOK()) {
throw new Error(
`Public kernel circuit did not revert on ${result.execution.contractAddress.toString()}:${functionSelector}, but simulator did.`,
`Public kernel circuit did not revert on ${result.execution.contractAddress.toString()}:${functionSelector}(${functionName}), but simulator did.`,
);
}

// We know the phase is revertible due to the above check.
// So safely return the revert reason and the kernel output (which has had its revertible side effects dropped)
if (result.reverted) {
this.log.debug(
`Reverting on ${result.execution.contractAddress.toString()}:${functionSelector} with reason: ${
`Reverting on ${result.execution.contractAddress.toString()}:${functionSelector}(${functionName}) with reason: ${
result.revertReason
}`,
);
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/simulator/src/public/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { convertAvmResultsToPxResult, createAvmExecutionEnvironment } from './tr
export class PublicExecutor {
constructor(
private readonly stateDb: PublicStateDB,
private readonly contractsDb: PublicContractsDB,
public readonly contractsDb: PublicContractsDB,
private readonly commitmentsDb: CommitmentsDB,
private readonly header: Header,
) {}
Expand Down

0 comments on commit f812ad7

Please sign in to comment.