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

chore(profiler): Docs on profiler command and more complete error reporting #7436

Merged
merged 10 commits into from
Feb 20, 2025
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion tooling/profiler/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "noir_profiler"
description = "Profiler for noir circuits"
description = "Profiler for Noir circuits"
version.workspace = true
authors.workspace = true
edition.workspace = true
Expand Down Expand Up @@ -34,6 +34,7 @@ nargo.workspace = true
noirc_errors.workspace = true
noirc_abi.workspace = true
noirc_evaluator.workspace = true
thiserror.workspace = true

# Logs
tracing-subscriber.workspace = true
Expand Down
53 changes: 50 additions & 3 deletions tooling/profiler/src/cli/execution_flamegraph_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
use std::path::{Path, PathBuf};

use acir::circuit::Opcode;
use acir::circuit::OpcodeLocation;
use clap::Args;
use color_eyre::eyre::{self, Context};
use nargo::errors::try_to_diagnose_runtime_error;
use nargo::foreign_calls::DefaultForeignCallBuilder;
use nargo::PrintOutput;
use noirc_artifacts::program::ProgramArtifact;

use crate::errors::{report_error, CliError};
use crate::flamegraph::{BrilligExecutionSample, FlamegraphGenerator, InfernoFlamegraphGenerator};
use crate::fs::{read_inputs_from_file, read_program_from_file};
use crate::opcode_formatter::format_brillig_opcode;
use bn254_blackbox_solver::Bn254BlackBoxSolver;
use noirc_abi::input_parser::Format;
use noirc_artifacts::debug::DebugArtifact;

/// Generates a flamegraph mapping unconstrained Noir execution to source code.
#[derive(Debug, Clone, Args)]
pub(crate) struct ExecutionFlamegraphCommand {
/// The path to the artifact JSON file
Expand Down Expand Up @@ -54,17 +59,40 @@ fn run_with_generator(
let program =
read_program_from_file(artifact_path).context("Error reading program from file")?;

ensure_brillig_entry_point(&program)?;

let (inputs_map, _) = read_inputs_from_file(prover_toml_path, Format::Toml, &program.abi)?;

let initial_witness = program.abi.encode(&inputs_map, None)?;

println!("Executing");
let (_, mut profiling_samples) = nargo::ops::execute_program_with_profiling(
println!("Executing...");

let solved_witness_stack_err = nargo::ops::execute_program_with_profiling(
&program.bytecode,
initial_witness,
&Bn254BlackBoxSolver(pedantic_solving),
&mut DefaultForeignCallBuilder::default().with_output(PrintOutput::Stdout).build(),
)?;
);
let mut profiling_samples = match solved_witness_stack_err {
Ok((_, profiling_samples)) => profiling_samples,
Err(err) => {
let debug_artifact = DebugArtifact {
debug_symbols: program.debug_symbols.debug_infos.clone(),
file_map: program.file_map.clone(),
};

if let Some(diagnostic) = try_to_diagnose_runtime_error(
&err,
&program.abi,
&program.debug_symbols.debug_infos,
) {
diagnostic.report(&debug_artifact, false);
}

return Err(CliError::Generic.into());
}
};

println!("Executed");

println!("Collecting {} samples", profiling_samples.len());
Expand Down Expand Up @@ -104,3 +132,22 @@ fn run_with_generator(

Ok(())
}

fn ensure_brillig_entry_point(artifact: &ProgramArtifact) -> Result<(), CliError> {
let err_msg = "Command only supports fully unconstrained Noir programs e.g. `unconstrained fn main() { .. }".to_owned();
let program = &artifact.bytecode;
if program.functions.len() != 1 || program.unconstrained_functions.len() != 1 {
return report_error(err_msg);
}

let main_function = &program.functions[0];
let Opcode::BrilligCall { id, .. } = main_function.opcodes[0] else {
return report_error(err_msg);
};

if id.as_usize() != 0 {
return report_error(err_msg);
}

Ok(())
}
4 changes: 3 additions & 1 deletion tooling/profiler/src/cli/gates_flamegraph_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,22 @@ use crate::fs::read_program_from_file;
use crate::gates_provider::{BackendGatesProvider, GatesProvider};
use crate::opcode_formatter::format_acir_opcode;

/// Generates a flamegraph mapping backend opcodes to their associated locations in the source code.
#[derive(Debug, Clone, Args)]
pub(crate) struct GatesFlamegraphCommand {
/// The path to the artifact JSON file
#[clap(long, short)]
artifact_path: String,

/// Path to the noir backend binary
/// Path to the Noir backend binary
#[clap(long, short)]
backend_path: String,

/// Command to get a gates report from the backend. Defaults to "gates"
#[clap(long, short = 'g', default_value = "gates")]
backend_gates_command: String,

/// Optional arguments for the backend gates command
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
backend_extra_args: Vec<String>,

Expand Down
4 changes: 3 additions & 1 deletion tooling/profiler/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,7 @@ pub(crate) fn start_cli() -> eyre::Result<()> {
ProfilerCommand::Gates(args) => gates_flamegraph_cmd::run(args),
ProfilerCommand::Opcodes(args) => opcodes_flamegraph_cmd::run(args),
ProfilerCommand::ExecutionOpcodes(args) => execution_flamegraph_cmd::run(args),
}
}?;

Ok(())
}
1 change: 1 addition & 0 deletions tooling/profiler/src/cli/opcodes_flamegraph_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::flamegraph::{CompilationSample, FlamegraphGenerator, InfernoFlamegrap
use crate::fs::read_program_from_file;
use crate::opcode_formatter::{format_acir_opcode, format_brillig_opcode};

/// Generates a flamegraph mapping ACIR opcodes to their associated locations in the source code.
#[derive(Debug, Clone, Args)]
pub(crate) struct OpcodesFlamegraphCommand {
/// The path to the artifact JSON file
Expand Down
16 changes: 16 additions & 0 deletions tooling/profiler/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use fm::FileMap;
use noirc_errors::{CustomDiagnostic, Span};
use thiserror::Error;

#[derive(Debug, Error)]
pub(crate) enum CliError {
#[error("Failed to run profiler command")]
Generic,
}

/// Report an error from the CLI that is not reliant on a stack trace.
pub(crate) fn report_error(message: String) -> Result<(), CliError> {
let error = CustomDiagnostic::simple_error(message.clone(), String::new(), Span::default());
noirc_errors::reporter::report(&FileMap::default(), &error, None, false);
Err(CliError::Generic)
}
3 changes: 2 additions & 1 deletion tooling/profiler/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#![cfg_attr(not(test), warn(unused_crate_dependencies, unused_extern_crates))]

mod cli;
mod errors;
mod flamegraph;
mod fs;
mod gates_provider;
Expand Down Expand Up @@ -33,7 +34,7 @@ fn main() {
}

if let Err(report) = cli::start_cli() {
eprintln!("{report:?}");
eprintln!("{report}");
std::process::exit(1);
}
}
Loading