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 2 commits
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
28 changes: 28 additions & 0 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ members = [
"tooling/nargo_cli",
"tooling/nargo_toml",
"tooling/noirc_artifacts",
"tooling/noirc_artifacts_info",
"tooling/noirc_abi",
"tooling/noirc_abi_wasm",
"tooling/acvm_cli",
"tooling/profiler",
"tooling/inspector",
# ACVM
"acvm-repo/acir_field",
"acvm-repo/acir",
Expand Down Expand Up @@ -83,6 +85,7 @@ noir_lsp = { path = "tooling/lsp" }
noir_debugger = { path = "tooling/debugger" }
noirc_abi = { path = "tooling/noirc_abi" }
noirc_artifacts = { path = "tooling/noirc_artifacts" }
noirc_artifacts_info = { path = "tooling/noirc_artifacts_info" }

# Arkworks
ark-bn254 = { version = "^0.5.0", default-features = false, features = [
Expand Down
26 changes: 26 additions & 0 deletions tooling/inspector/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "noir_inspector"
description = "Inspector for noir build artifacts"
version.workspace = true
authors.workspace = true
edition.workspace = true
license.workspace = true
rust-version.workspace = true
repository.workspace = true

[lints]
workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[[bin]]
name = "noir-inspector"
path = "src/main.rs"

[dependencies]
clap.workspace = true
serde.workspace = true
serde_json.workspace = true
acir.workspace = true
noirc_artifacts.workspace = true
noirc_artifacts_info.workspace = true
77 changes: 77 additions & 0 deletions tooling/inspector/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use std::{path::PathBuf, process::exit};

use acir::circuit::ExpressionWidth;
use clap::Parser;
use noirc_artifacts::program::ProgramArtifact;
use noirc_artifacts_info::{count_opcodes_and_gates_in_program, show_info_report, InfoReport};

#[derive(Debug, Clone, Parser)]
pub(crate) struct Args {
asterite marked this conversation as resolved.
Show resolved Hide resolved
/// 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 const DEFAULT_EXPRESSION_WIDTH: ExpressionWidth = ExpressionWidth::Bounded { width: 4 };
TomAFrench marked this conversation as resolved.
Show resolved Hide resolved

fn main() {
let args = Args::parse();

let file = match std::fs::File::open(args.artifact.clone()) {
Ok(file) => file,
Err(err) => {
println!("Cannot open file `{}`: {}", args.artifact.to_string_lossy(), err,);
exit(1);
}
};
let artifact: ProgramArtifact = match serde_json::from_reader(file) {
Ok(artifact) => artifact,
Err(error) => {
println!("Cannot deserialize artifact: {}", error);
exit(1);
}
};

if args.print_acir {
println!("Compiled ACIR for main:");
println!("{}", artifact.bytecode);
}
asterite marked this conversation as resolved.
Show resolved Hide resolved

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);
}

fn parse_expression_width(input: &str) -> Result<ExpressionWidth, std::io::Error> {
use std::io::{Error, ErrorKind};

let width = input
.parse::<usize>()
.map_err(|err| Error::new(ErrorKind::InvalidInput, err.to_string()))?;

match width {
0 => Ok(ExpressionWidth::Unbounded),
_ => Ok(ExpressionWidth::Bounded { width }),
}
}
1 change: 1 addition & 0 deletions tooling/nargo_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ noirc_frontend = { workspace = true, features = ["bn254"] }
noirc_abi.workspace = true
noirc_errors.workspace = true
noirc_artifacts.workspace = true
noirc_artifacts_info.workspace = true
acvm = { workspace = true, features = ["bn254"] }
bn254_blackbox_solver.workspace = true
toml.workspace = true
Expand Down
118 changes: 7 additions & 111 deletions tooling/nargo_cli/src/cli/info_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ use nargo::{
use nargo_toml::{get_package_manifest, resolve_workspace_from_toml};
use noirc_abi::input_parser::Format;
use noirc_artifacts::program::ProgramArtifact;
use noirc_artifacts_info::{
count_opcodes_and_gates_in_program, show_info_report, FunctionInfo, InfoReport, ProgramInfo,
};
use noirc_driver::{CompileOptions, NOIR_ARTIFACT_VERSION_STRING};
use prettytable::{row, table, Row};
use prettytable::{row, Row};
use rayon::prelude::*;
use serde::Serialize;

Expand Down Expand Up @@ -94,74 +97,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 +118,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 +131,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
22 changes: 22 additions & 0 deletions tooling/noirc_artifacts_info/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "noirc_artifacts_info"
description = "The logic for `nargo info` and `nargo-inspector`"
version.workspace = true
authors.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true

[lints]
workspace = true

[dependencies]
clap.workspace = true
serde.workspace = true
serde_json.workspace = true
acir.workspace = true
noirc_artifacts.workspace = true
rayon.workspace = true
acvm = { workspace = true, features = ["bn254"] }
iter-extended.workspace = true
prettytable-rs = "0.10"
Loading
Loading