Skip to content

Commit

Permalink
feat: add profile info print out (#3425)
Browse files Browse the repository at this point in the history
  • Loading branch information
kobyhallx authored Nov 7, 2023
1 parent 79a2fac commit a8b5fa8
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 2 deletions.
42 changes: 42 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,13 @@ pub struct DebugInfo {
pub locations: BTreeMap<OpcodeLocation, Vec<Location>>,
}

/// Holds OpCodes Counts for Acir and Brillig Opcodes
/// To be printed with `nargo info --profile-info`
pub struct OpCodesCount {
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 +50,38 @@ 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() {
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 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: compiled_artifact.warnings.clone(),
}
}
}

impl<'a> Files<'a> for DebugArtifact {
type FileId = FileId;
type Name = PathString;
Expand Down
74 changes: 73 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,55 @@ pub(crate) fn run(
Ok(())
}

/// Provides profiling information on
///
/// Number of OpCodes in relation to Noir source file
/// and line number information
fn print_span_opcodes(
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() + 1;
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

0 comments on commit a8b5fa8

Please sign in to comment.