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: compile circuits and query circuit sizes in parallel for nargo info #2665

Merged
merged 9 commits into from
Sep 13, 2023
61 changes: 29 additions & 32 deletions tooling/nargo_cli/src/cli/compile_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,52 +63,62 @@ pub(crate) fn run(
let workspace = resolve_workspace_from_toml(&toml_path, selection)?;
let circuit_dir = workspace.target_directory_path();

let (np_language, is_opcode_supported) = backend.get_backend_info()?;

let (binary_packages, contract_packages): (Vec<_>, Vec<_>) = workspace
.members
.iter()
.into_iter()
.filter(|package| !package.is_library())
.cloned()
.partition(|package| package.is_binary());

let (compiled_programs, compiled_contracts) =
compile_workspace(backend, &binary_packages, &contract_packages, &args.compile_options)?;

// Save build artifacts to disk.
for (package, program) in binary_packages.into_iter().zip(compiled_programs) {
save_program(program, &package, &circuit_dir, args.output_debug);
}
for (package, contract) in contract_packages.into_iter().zip(compiled_contracts) {
save_contract(contract, &package, &circuit_dir, args.output_debug);
}

Ok(())
}

pub(super) fn compile_workspace(
backend: &Backend,
binary_packages: &[Package],
contract_packages: &[Package],
compile_options: &CompileOptions,
) -> Result<(Vec<CompiledProgram>, Vec<CompiledContract>), CliError> {
let (np_language, is_opcode_supported) = backend.get_backend_info()?;

// Compile all of the packages in parallel.
let program_results: Vec<(FileManager, CompilationResult<CompiledProgram>)> = binary_packages
.par_iter()
.map(|package| {
compile_program(package, &args.compile_options, np_language, &is_opcode_supported)
})
.map(|package| compile_program(package, compile_options, np_language, &is_opcode_supported))
.collect();
let contract_results: Vec<(FileManager, CompilationResult<CompiledContract>)> =
contract_packages
.par_iter()
.map(|package| {
compile_contract(package, &args.compile_options, np_language, &is_opcode_supported)
compile_contract(package, compile_options, np_language, &is_opcode_supported)
})
.collect();

// Report any warnings/errors which were encountered during compilation.
let compiled_programs: Vec<CompiledProgram> = program_results
.into_iter()
.map(|(file_manager, compilation_result)| {
report_errors(compilation_result, &file_manager, args.compile_options.deny_warnings)
report_errors(compilation_result, &file_manager, compile_options.deny_warnings)
})
.collect::<Result<_, _>>()?;
let compiled_contracts: Vec<CompiledContract> = contract_results
.into_iter()
.map(|(file_manager, compilation_result)| {
report_errors(compilation_result, &file_manager, args.compile_options.deny_warnings)
report_errors(compilation_result, &file_manager, compile_options.deny_warnings)
})
.collect::<Result<_, _>>()?;

// Save build artifacts to disk.
for (package, program) in binary_packages.into_iter().zip(compiled_programs) {
save_program(program, package, &circuit_dir, args.output_debug);
}
for (package, compiled_contract) in contract_packages.into_iter().zip(compiled_contracts) {
save_contract(compiled_contract, package, &circuit_dir, args.output_debug);
}

Ok(())
Ok((compiled_programs, compiled_contracts))
}

pub(crate) fn compile_bin_package(
Expand All @@ -129,19 +139,6 @@ pub(crate) fn compile_bin_package(
Ok(program)
}

pub(crate) fn compile_contract_package(
package: &Package,
compile_options: &CompileOptions,
np_language: Language,
is_opcode_supported: &impl Fn(&Opcode) -> bool,
) -> Result<CompiledContract, CliError> {
let (file_manager, compilation_result) =
compile_contract(package, compile_options, np_language, &is_opcode_supported);
let contract_and_debug_artifact =
report_errors(compilation_result, &file_manager, compile_options.deny_warnings)?;
Ok(contract_and_debug_artifact)
}

fn compile_program(
package: &Package,
compile_options: &CompileOptions,
Expand Down
96 changes: 43 additions & 53 deletions tooling/nargo_cli/src/cli/info_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
use acvm::acir::circuit::Opcode;
use acvm::Language;
use acvm_backend_barretenberg::BackendError;
use clap::Args;
use iter_extended::{try_vecmap, vecmap};
use iter_extended::vecmap;
use nargo::package::Package;
use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection};
use noirc_driver::CompileOptions;
use noirc_driver::{CompileOptions, CompiledContract, CompiledProgram};
use noirc_frontend::graph::CrateName;
use prettytable::{row, table, Row};
use rayon::prelude::*;
use serde::Serialize;

use crate::backends::Backend;
use crate::errors::CliError;

use super::{
compile_cmd::{compile_bin_package, compile_contract_package},
NargoConfig,
};
use super::{compile_cmd::compile_workspace, NargoConfig};

/// Provides detailed information on a circuit
///
Expand Down Expand Up @@ -52,30 +49,30 @@ pub(crate) fn run(
let selection = args.package.map_or(default_selection, PackageSelection::Selected);
let workspace = resolve_workspace_from_toml(&toml_path, selection)?;

let mut info_report = InfoReport::default();

let (np_language, is_opcode_supported) = backend.get_backend_info()?;
for package in &workspace {
if package.is_contract() {
let contract_info = count_opcodes_and_gates_in_contracts(
backend,
package,
&args.compile_options,
np_language,
&is_opcode_supported,
)?;
info_report.contracts.push(contract_info);
} else {
let program_info = count_opcodes_and_gates_in_program(
backend,
package,
&args.compile_options,
np_language,
&is_opcode_supported,
)?;
info_report.programs.push(program_info);
}
}
let (binary_packages, contract_packages): (Vec<_>, Vec<_>) = workspace
.into_iter()
.filter(|package| !package.is_library())
.cloned()
.partition(|package| package.is_binary());

let (compiled_programs, compiled_contracts) =
compile_workspace(backend, &binary_packages, &contract_packages, &args.compile_options)?;

let (np_language, _) = backend.get_backend_info()?;
let program_info = binary_packages
.into_par_iter()
.zip(compiled_programs)
.map(|(package, program)| {
count_opcodes_and_gates_in_program(backend, program, &package, np_language)
})
.collect::<Result<_, _>>()?;

let contract_info = compiled_contracts
.into_par_iter()
.map(|contract| count_opcodes_and_gates_in_contract(backend, contract, np_language))
.collect::<Result<_, _>>()?;

let info_report = InfoReport { programs: program_info, contracts: contract_info };

if args.json {
// Expose machine-readable JSON data.
Expand Down Expand Up @@ -169,15 +166,10 @@ impl From<ContractInfo> for Vec<Row> {

fn count_opcodes_and_gates_in_program(
backend: &Backend,
compiled_program: CompiledProgram,
package: &Package,
compile_options: &CompileOptions,
np_language: Language,
is_opcode_supported: &impl Fn(&Opcode) -> bool,
language: Language,
) -> Result<ProgramInfo, CliError> {
let compiled_program =
compile_bin_package(package, compile_options, np_language, &is_opcode_supported)?;
let (language, _) = backend.get_backend_info()?;

Ok(ProgramInfo {
name: package.name.to_string(),
language,
Expand All @@ -186,24 +178,22 @@ fn count_opcodes_and_gates_in_program(
})
}

fn count_opcodes_and_gates_in_contracts(
fn count_opcodes_and_gates_in_contract(
backend: &Backend,
package: &Package,
compile_options: &CompileOptions,
np_language: Language,
is_opcode_supported: &impl Fn(&Opcode) -> bool,
contract: CompiledContract,
language: Language,
) -> Result<ContractInfo, CliError> {
let contract =
compile_contract_package(package, compile_options, np_language, &is_opcode_supported)?;
let (language, _) = backend.get_backend_info()?;

let functions = try_vecmap(contract.functions, |function| -> Result<_, BackendError> {
Ok(FunctionInfo {
name: function.name,
acir_opcodes: function.bytecode.opcodes.len(),
circuit_size: backend.get_exact_circuit_size(&function.bytecode)?,
let functions = contract
.functions
.into_par_iter()
.map(|function| -> Result<_, BackendError> {
Ok(FunctionInfo {
name: function.name,
acir_opcodes: function.bytecode.opcodes.len(),
circuit_size: backend.get_exact_circuit_size(&function.bytecode)?,
})
})
})?;
.collect::<Result<_, _>>()?;

Ok(ContractInfo { name: contract.name, language, functions })
}
Loading