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 profile info print out #3425

Merged
merged 12 commits into from
Nov 7, 2023
41 changes: 41 additions & 0 deletions compiler/noirc_errors/src/debug_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use acvm::compiler::AcirTransformationMap;
use serde_with::serde_as;
use serde_with::DisplayFromStr;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::mem;

use crate::Location;
Expand All @@ -19,6 +20,11 @@ pub struct DebugInfo {
pub locations: BTreeMap<OpcodeLocation, Vec<Location>>,
}

pub struct OpCodesCount {
kobyhallx marked this conversation as resolved.
Show resolved Hide resolved
pub acir_size: usize,
pub brillig_size: usize,
}

impl DebugInfo {
pub fn new(locations: BTreeMap<OpcodeLocation, Vec<Location>>) -> Self {
DebugInfo { locations }
Expand All @@ -42,4 +48,39 @@ impl DebugInfo {
pub fn opcode_location(&self, loc: &OpcodeLocation) -> Option<Vec<Location>> {
self.locations.get(loc).cloned()
}

pub fn count_span_opcodes(&self) -> HashMap<&Location, OpCodesCount> {
let mut accumulator: HashMap<&Location, Vec<&OpcodeLocation>> = HashMap::new();

for (opcode_location, locations) in self.locations.iter() {
guipublic marked this conversation as resolved.
Show resolved Hide resolved
for location in locations.iter() {
let opcodes = accumulator.entry(location).or_insert(Vec::new());
opcodes.push(opcode_location);
}
}

let counted_opcodes = accumulator
.iter()
.map(|(location, opcodes)| {
let acir_opcodes: Vec<_> = opcodes
.iter()
.filter(|opcode_location| matches!(opcode_location, OpcodeLocation::Acir(_)))
.collect();
let brillig_opcodes: Vec<_> = opcodes
.iter()
.filter(|opcode_location| {
matches!(opcode_location, OpcodeLocation::Brillig { .. })
})
.collect();
// let (acir_opcodes, brillig_opcodes): (Vec<OpcodeLocation>, Vec<OpcodeLocation>) = opcodes.iter().partition(|opc| matches!(opc, OpcodeLocation::Acir(_)));
kobyhallx marked this conversation as resolved.
Show resolved Hide resolved
let opcodes_count = OpCodesCount {
acir_size: acir_opcodes.len(),
brillig_size: brillig_opcodes.len(),
};
(*location, opcodes_count)
})
.collect();

counted_opcodes
}
}
28 changes: 27 additions & 1 deletion tooling/nargo/src/artifacts/debug.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use codespan_reporting::files::{Error, Files, SimpleFile};
use noirc_driver::DebugFile;
use noirc_driver::{CompiledContract, CompiledProgram, DebugFile};
use noirc_errors::{debug_info::DebugInfo, Location};
use noirc_evaluator::errors::SsaReport;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -96,6 +96,32 @@ impl DebugArtifact {
}
}

impl From<CompiledProgram> for DebugArtifact {
fn from(compiled_program: CompiledProgram) -> Self {
DebugArtifact {
debug_symbols: vec![compiled_program.debug],
file_map: compiled_program.file_map,
warnings: compiled_program.warnings,
}
}
}

impl From<&CompiledContract> for DebugArtifact {
fn from(compiled_artifact: &CompiledContract) -> Self {
let all_functions_debug: Vec<DebugInfo> = compiled_artifact
.functions
.iter()
.map(|contract_function| contract_function.debug.clone())
.collect();

DebugArtifact {
debug_symbols: all_functions_debug,
file_map: compiled_artifact.file_map.clone(),
warnings: Vec::new(),
kobyhallx marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

impl<'a> Files<'a> for DebugArtifact {
type FileId = FileId;
type Name = PathString;
Expand Down
70 changes: 69 additions & 1 deletion tooling/nargo_cli/src/cli/info_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
use std::collections::HashMap;

use acvm::Language;
use backend_interface::BackendError;
use clap::Args;
use iter_extended::vecmap;
use nargo::package::Package;
use nargo::{artifacts::debug::DebugArtifact, package::Package};
use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection};
use noirc_driver::{
CompileOptions, CompiledContract, CompiledProgram, NOIR_ARTIFACT_VERSION_STRING,
};
use noirc_errors::{debug_info::OpCodesCount, Location};
use noirc_frontend::graph::CrateName;
use prettytable::{row, table, Row};
use rayon::prelude::*;
Expand Down Expand Up @@ -36,6 +39,9 @@ pub(crate) struct InfoCommand {
#[clap(long, hide = true)]
json: bool,

#[clap(long, hide = true)]
profile_info: bool,

#[clap(flatten)]
compile_options: CompileOptions,
}
Expand Down Expand Up @@ -71,6 +77,23 @@ pub(crate) fn run(
&args.compile_options,
)?;

if args.profile_info {
for compiled_program in &compiled_programs {
let span_opcodes = compiled_program.debug.count_span_opcodes();
let debug_artifact: DebugArtifact = compiled_program.clone().into();
print_span_opcodes(&span_opcodes, &debug_artifact);
}

for compiled_contract in &compiled_contracts {
let debug_artifact: DebugArtifact = compiled_contract.clone().into();
let functions = &compiled_contract.functions;
for contract_function in functions {
let span_opcodes = contract_function.debug.count_span_opcodes();
print_span_opcodes(&span_opcodes, &debug_artifact);
}
}
}

let program_info = binary_packages
.into_par_iter()
.zip(compiled_programs)
Expand Down Expand Up @@ -121,6 +144,51 @@ pub(crate) fn run(
Ok(())
}

fn print_span_opcodes(
guipublic marked this conversation as resolved.
Show resolved Hide resolved
span_opcodes_map: &HashMap<&Location, OpCodesCount>,
debug_artifact: &DebugArtifact,
) {
let mut pairs: Vec<(&&Location, &OpCodesCount)> = span_opcodes_map.iter().collect();

pairs.sort_by(|a, b| {
a.1.acir_size.cmp(&b.1.acir_size).then_with(|| a.1.brillig_size.cmp(&b.1.brillig_size))
});

for (location, opcodes_count) in pairs {
let debug_file = debug_artifact.file_map.get(&location.file).unwrap();

let start_byte = byte_index(&debug_file.source, location.span.start() + 1);
let end_byte = byte_index(&debug_file.source, location.span.end() + 1);
let range = start_byte..end_byte;
let span_content = &debug_file.source[range];
let line = debug_artifact.location_line_index(**location).unwrap();
println!(
"Ln. {}: {} (ACIR:{}, Brillig:{} opcode|s) in file: {}",
line,
span_content,
opcodes_count.acir_size,
opcodes_count.brillig_size,
debug_file.path.to_str().unwrap()
);
}
}
fn byte_index(string: &str, index: u32) -> usize {
let mut byte_index = 0;
let mut char_index = 0;

#[allow(clippy::explicit_counter_loop)]
for (byte_offset, _) in string.char_indices() {
if char_index == index {
return byte_index;
}

byte_index = byte_offset;
char_index += 1;
}

byte_index
}

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