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 noir-inspector #7136

Merged
merged 5 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
123 changes: 11 additions & 112 deletions tooling/nargo_cli/src/cli/info_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@ use nargo_toml::{get_package_manifest, resolve_workspace_from_toml};
use noirc_abi::input_parser::Format;
use noirc_artifacts::program::ProgramArtifact;
use noirc_driver::{CompileOptions, NOIR_ARTIFACT_VERSION_STRING};
use prettytable::{row, table, Row};
use prettytable::{row, Row};
use rayon::prelude::*;
use serde::Serialize;

use crate::{cli::fs::inputs::read_inputs_from_file, errors::CliError};
use crate::{
cli::fs::inputs::read_inputs_from_file,
errors::CliError,
program_info::{
count_opcodes_and_gates_in_program, show_info_report, FunctionInfo, InfoReport, ProgramInfo,
},
};

use super::{
compile_cmd::{compile_workspace_full, get_target_width},
Expand Down Expand Up @@ -94,74 +100,18 @@ pub(crate) fn run(mut args: InfoCommand, config: NargoConfig) -> Result<(), CliE
package.expression_width,
args.compile_options.expression_width,
);
count_opcodes_and_gates_in_program(program, &package, target_width)
let package_name = package.name.to_string();
count_opcodes_and_gates_in_program(program, package_name, target_width)
})
.collect()
};

let info_report = InfoReport { programs: program_info };

if args.json {
// Expose machine-readable JSON data.
println!("{}", serde_json::to_string(&info_report).unwrap());
} else {
// Otherwise print human-readable table.
if !info_report.programs.is_empty() {
let mut program_table = table!([Fm->"Package", Fm->"Function", Fm->"Expression Width", Fm->"ACIR Opcodes", Fm->"Brillig Opcodes"]);

for program_info in info_report.programs {
let program_rows: Vec<Row> = program_info.into();
for row in program_rows {
program_table.add_row(row);
}
}
program_table.printstd();
}
}
show_info_report(info_report, args.json);

Ok(())
}

#[derive(Debug, Default, Serialize)]
struct InfoReport {
programs: Vec<ProgramInfo>,
}

#[derive(Debug, Serialize)]
struct ProgramInfo {
package_name: String,
#[serde(skip)]
expression_width: ExpressionWidth,
functions: Vec<FunctionInfo>,
#[serde(skip)]
unconstrained_functions_opcodes: usize,
unconstrained_functions: Vec<FunctionInfo>,
}

impl From<ProgramInfo> for Vec<Row> {
fn from(program_info: ProgramInfo) -> Self {
let mut main = vecmap(program_info.functions, |function| {
row![
Fm->format!("{}", program_info.package_name),
Fc->format!("{}", function.name),
format!("{:?}", program_info.expression_width),
Fc->format!("{}", function.opcodes),
Fc->format!("{}", program_info.unconstrained_functions_opcodes),
]
});
main.extend(vecmap(program_info.unconstrained_functions, |function| {
row![
Fm->format!("{}", program_info.package_name),
Fc->format!("{}", function.name),
format!("N/A", ),
Fc->format!("N/A"),
Fc->format!("{}", function.opcodes),
]
}));
main
}
}

#[derive(Debug, Serialize)]
struct ContractInfo {
name: String,
Expand All @@ -171,12 +121,6 @@ struct ContractInfo {
functions: Vec<FunctionInfo>,
}

#[derive(Debug, Serialize)]
struct FunctionInfo {
name: String,
opcodes: usize,
}

impl From<ContractInfo> for Vec<Row> {
fn from(contract_info: ContractInfo) -> Self {
vecmap(contract_info.functions, |function| {
Expand All @@ -190,51 +134,6 @@ impl From<ContractInfo> for Vec<Row> {
}
}

fn count_opcodes_and_gates_in_program(
compiled_program: ProgramArtifact,
package: &Package,
expression_width: ExpressionWidth,
) -> ProgramInfo {
let functions = compiled_program
.bytecode
.functions
.into_par_iter()
.enumerate()
.map(|(i, function)| FunctionInfo {
name: compiled_program.names[i].clone(),
opcodes: function.opcodes.len(),
})
.collect();

let opcodes_len: Vec<usize> = compiled_program
.bytecode
.unconstrained_functions
.iter()
.map(|func| func.bytecode.len())
.collect();
let unconstrained_functions_opcodes = compiled_program
.bytecode
.unconstrained_functions
.into_par_iter()
.map(|function| function.bytecode.len())
.sum();
let unconstrained_info: Vec<FunctionInfo> = compiled_program
.brillig_names
.clone()
.iter()
.zip(opcodes_len)
.map(|(name, len)| FunctionInfo { name: name.clone(), opcodes: len })
.collect();

ProgramInfo {
package_name: package.name.to_string(),
expression_width,
functions,
unconstrained_functions_opcodes,
unconstrained_functions: unconstrained_info,
}
}

fn profile_brillig_execution(
binary_packages: Vec<(Package, ProgramArtifact)>,
prover_name: &str,
Expand Down
74 changes: 74 additions & 0 deletions tooling/nargo_cli/src/cli/inspect_cmd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use std::path::PathBuf;

use acvm::acir::circuit::ExpressionWidth;
use clap::Args;
use noirc_artifacts::program::ProgramArtifact;
use noirc_driver::{parse_expression_width, DEFAULT_EXPRESSION_WIDTH};

use crate::{
errors::CliError,
program_info::{count_opcodes_and_gates_in_program, show_info_report, InfoReport},
};

/// Provides detailed information on a build artifact.
///
/// Current information provided per circuit:
/// 1. The number of ACIR opcodes
/// 2. Counts the final number gates in the circuit used by a backend
#[derive(Debug, Clone, Args)]
pub(crate) struct InspectCommand {
/// The artifact to inspect
artifact: PathBuf,

/// Output a JSON formatted report. Changes to this format are not currently considered breaking.
#[clap(long, hide = true)]
json: bool,

/// Specify the backend expression width that should be assumed
#[arg(long, value_parser = parse_expression_width)]
expression_width: Option<ExpressionWidth>,

/// Display the ACIR for compiled circuit
#[arg(long)]
print_acir: bool,
}

pub(crate) fn run(args: InspectCommand) -> Result<(), CliError> {
let file = match std::fs::File::open(args.artifact.clone()) {
Ok(file) => file,
Err(err) => {
return Err(CliError::Generic(format!(
"Cannot open file `{}`: {}",
args.artifact.to_string_lossy(),
err,
)));
}
};
let artifact: ProgramArtifact = match serde_json::from_reader(file) {
Ok(artifact) => artifact,
Err(error) => {
return Err(CliError::Generic(format!("Cannot deserialize artifact: {}", error)));
}
};

if args.print_acir {
println!("Compiled ACIR for main:");
println!("{}", artifact.bytecode);
}

let package_name = args
.artifact
.with_extension("")
.file_name()
.map(|s| s.to_string_lossy().to_string())
.unwrap_or_else(|| "artifact".to_string());

let expression_width = args.expression_width.unwrap_or(DEFAULT_EXPRESSION_WIDTH);
let program_info =
count_opcodes_and_gates_in_program(artifact, package_name.to_string(), expression_width);

let info_report = InfoReport { programs: vec![program_info] };
show_info_report(info_report, args.json);

Ok(())
}
5 changes: 5 additions & 0 deletions tooling/nargo_cli/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod fmt_cmd;
mod generate_completion_script_cmd;
mod info_cmd;
mod init_cmd;
mod inspect_cmd;
mod lsp_cmd;
mod new_cmd;
mod test_cmd;
Expand Down Expand Up @@ -109,6 +110,7 @@ enum NargoCommand {
Debug(debug_cmd::DebugCommand),
Test(test_cmd::TestCommand),
Info(info_cmd::InfoCommand),
Inspect(inspect_cmd::InspectCommand),
Lsp(lsp_cmd::LspCommand),
#[command(hide = true)]
Dap(dap_cmd::DapCommand),
Expand Down Expand Up @@ -167,6 +169,7 @@ pub(crate) fn start_cli() -> eyre::Result<()> {
NargoCommand::Export(args) => export_cmd::run(args, config),
NargoCommand::Test(args) => test_cmd::run(args, config),
NargoCommand::Info(args) => info_cmd::run(args, config),
NargoCommand::Inspect(args) => inspect_cmd::run(args),
NargoCommand::Lsp(args) => lsp_cmd::run(args, config),
NargoCommand::Dap(args) => dap_cmd::run(args, config),
NargoCommand::Fmt(args) => fmt_cmd::run(args, config),
Expand Down Expand Up @@ -208,6 +211,7 @@ fn command_scope(cmd: &NargoCommand) -> CommandScope {
}
NargoCommand::New(..)
| NargoCommand::Init(..)
| NargoCommand::Inspect(..)
| NargoCommand::Lsp(..)
| NargoCommand::Dap(..)
| NargoCommand::GenerateCompletionScript(..) => CommandScope::Any,
Expand Down Expand Up @@ -239,6 +243,7 @@ fn needs_lock(cmd: &NargoCommand) -> Option<bool> {
NargoCommand::Fmt(..)
| NargoCommand::New(..)
| NargoCommand::Init(..)
| NargoCommand::Inspect(..)
| NargoCommand::Lsp(..)
| NargoCommand::Dap(..)
| NargoCommand::GenerateCompletionScript(..) => None,
Expand Down
1 change: 1 addition & 0 deletions tooling/nargo_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

mod cli;
mod errors;
mod program_info;

use std::env;

Expand Down
Loading
Loading