diff --git a/tooling/profiler/src/cli/execution_flamegraph_cmd.rs b/tooling/profiler/src/cli/execution_flamegraph_cmd.rs index 43a5ca4680f..b160d494322 100644 --- a/tooling/profiler/src/cli/execution_flamegraph_cmd.rs +++ b/tooling/profiler/src/cli/execution_flamegraph_cmd.rs @@ -127,7 +127,7 @@ fn run_with_generator( &debug_artifact, artifact_path.to_str().unwrap(), "main", - &Path::new(&output_path).join(Path::new(&format!("{}.svg", "main"))), + &Path::new(&output_path).join(Path::new(&format!("{}_brillig_trace.svg", "main"))), )?; Ok(()) diff --git a/tooling/profiler/src/cli/gates_flamegraph_cmd.rs b/tooling/profiler/src/cli/gates_flamegraph_cmd.rs index 23ea15b402a..02ba22e3e06 100644 --- a/tooling/profiler/src/cli/gates_flamegraph_cmd.rs +++ b/tooling/profiler/src/cli/gates_flamegraph_cmd.rs @@ -66,19 +66,24 @@ fn run_with_provider( let backend_gates_response = gates_provider.get_gates(artifact_path).context("Error querying backend for gates")?; - let function_names = program.names.clone(); + let function_names = std::mem::take(&mut program.names); let bytecode = std::mem::take(&mut program.bytecode); let debug_artifact: DebugArtifact = program.into(); - for (func_idx, ((func_gates, func_name), bytecode)) in backend_gates_response - .functions - .into_iter() - .zip(function_names) - .zip(bytecode.functions) - .enumerate() + let num_functions = bytecode.functions.len(); + for (func_idx, (func_gates, circuit)) in + backend_gates_response.functions.into_iter().zip(bytecode.functions).enumerate() { + // We can have repeated names if there are functions with the same name in different + // modules or functions that use generics. Thus, add the unique function index as a suffix. + let function_name = if num_functions > 1 { + format!("{}_{}", function_names[func_idx].as_str(), func_idx) + } else { + function_names[func_idx].to_owned() + }; + println!( "Opcode count: {}, Total gates by opcodes: {}, Circuit size: {}", func_gates.acir_opcodes, @@ -89,7 +94,7 @@ fn run_with_provider( let samples = func_gates .gates_per_opcode .into_iter() - .zip(bytecode.opcodes) + .zip(circuit.opcodes) .enumerate() .map(|(index, (gates, opcode))| CompilationSample { opcode: Some(format_acir_opcode(&opcode)), @@ -100,16 +105,16 @@ fn run_with_provider( .collect(); let output_filename = if let Some(output_filename) = &output_filename { - format!("{}::{}::gates.svg", output_filename, func_name) + format!("{}_{}_gates.svg", output_filename, function_name) } else { - format!("{}::gates.svg", func_name) + format!("{}_gates.svg", function_name) }; flamegraph_generator.generate_flamegraph( samples, &debug_artifact.debug_symbols[func_idx], &debug_artifact, artifact_path.to_str().unwrap(), - &func_name, + &function_name, &Path::new(&output_path).join(Path::new(&output_filename)), )?; } @@ -212,7 +217,7 @@ mod tests { .expect("should run without errors"); // Check that the output file was written to - let output_file = temp_dir.path().join("test_filename::main::gates.svg"); + let output_file = temp_dir.path().join("test_filename_main_gates.svg"); assert!(output_file.exists()); } } diff --git a/tooling/profiler/src/cli/opcodes_flamegraph_cmd.rs b/tooling/profiler/src/cli/opcodes_flamegraph_cmd.rs index 90d5da08c1c..4dace54b123 100644 --- a/tooling/profiler/src/cli/opcodes_flamegraph_cmd.rs +++ b/tooling/profiler/src/cli/opcodes_flamegraph_cmd.rs @@ -45,18 +45,25 @@ fn run_with_generator( let mut program = read_program_from_file(artifact_path).context("Error reading program from file")?; - let function_names = program.names.clone(); + let acir_names = std::mem::take(&mut program.names); + let brillig_names = std::mem::take(&mut program.brillig_names); let bytecode = std::mem::take(&mut program.bytecode); let debug_artifact: DebugArtifact = program.into(); - for (func_idx, (func_name, bytecode)) in - function_names.into_iter().zip(bytecode.functions.iter()).enumerate() - { - println!("Opcode count for {}: {}", func_name, bytecode.opcodes.len()); + for (func_idx, circuit) in bytecode.functions.iter().enumerate() { + // We can have repeated names if there are functions with the same name in different + // modules or functions that use generics. Thus, add the unique function index as a suffix. + let function_name = if bytecode.functions.len() > 1 { + format!("{}_{}", acir_names[func_idx].as_str(), func_idx) + } else { + acir_names[func_idx].to_owned() + }; - let samples = bytecode + println!("Opcode count for {}: {}", function_name, circuit.opcodes.len()); + + let samples = circuit .opcodes .iter() .enumerate() @@ -73,51 +80,55 @@ fn run_with_generator( &debug_artifact.debug_symbols[func_idx], &debug_artifact, artifact_path.to_str().unwrap(), - &func_name, - &Path::new(&output_path).join(Path::new(&format!("{}_acir_opcodes.svg", &func_name))), + &function_name, + &Path::new(&output_path) + .join(Path::new(&format!("{}_acir_opcodes.svg", &function_name))), )?; } - if !skip_brillig { - for (brillig_fn_index, brillig_bytecode) in - bytecode.unconstrained_functions.into_iter().enumerate() - { - let acir_location = locate_brillig_call(brillig_fn_index, &bytecode.functions); - let Some((acir_fn_index, acir_opcode_index)) = acir_location else { - continue; - }; - - println!( - "Opcode count for brillig_{}: {}", - brillig_fn_index, - brillig_bytecode.bytecode.len() - ); - - let samples = brillig_bytecode - .bytecode - .into_iter() - .enumerate() - .map(|(brillig_index, opcode)| CompilationSample { - opcode: Some(format_brillig_opcode(&opcode)), - call_stack: vec![OpcodeLocation::Brillig { - acir_index: acir_opcode_index, - brillig_index, - }], - count: 1, - brillig_function_id: Some(BrilligFunctionId(brillig_fn_index as u32)), - }) - .collect(); - - flamegraph_generator.generate_flamegraph( - samples, - &debug_artifact.debug_symbols[acir_fn_index], - &debug_artifact, - artifact_path.to_str().unwrap(), - &format!("brillig_{}", brillig_fn_index), - &Path::new(&output_path) - .join(Path::new(&format!("{}_brillig_opcodes.svg", &brillig_fn_index))), - )?; - } + if skip_brillig { + return Ok(()); + } + + for (brillig_fn_index, brillig_bytecode) in + bytecode.unconstrained_functions.into_iter().enumerate() + { + let acir_location = locate_brillig_call(brillig_fn_index, &bytecode.functions); + let Some((acir_fn_index, acir_opcode_index)) = acir_location else { + continue; + }; + + // We can have repeated names if there are functions with the same name in different + // modules or functions that use generics. Thus, add the unique function index as a suffix. + let function_name = + format!("{}_{}", brillig_names[brillig_fn_index].as_str(), brillig_fn_index); + + println!("Opcode count for {}_brillig: {}", function_name, brillig_bytecode.bytecode.len()); + + let samples = brillig_bytecode + .bytecode + .into_iter() + .enumerate() + .map(|(brillig_index, opcode)| CompilationSample { + opcode: Some(format_brillig_opcode(&opcode)), + call_stack: vec![OpcodeLocation::Brillig { + acir_index: acir_opcode_index, + brillig_index, + }], + count: 1, + brillig_function_id: Some(BrilligFunctionId(brillig_fn_index as u32)), + }) + .collect(); + + flamegraph_generator.generate_flamegraph( + samples, + &debug_artifact.debug_symbols[acir_fn_index], + &debug_artifact, + artifact_path.to_str().unwrap(), + &function_name, + &Path::new(&output_path) + .join(Path::new(&format!("{}_brillig_opcodes.svg", function_name))), + )?; } Ok(()) @@ -215,12 +226,26 @@ mod tests { let artifact_path = temp_dir.path().join("test.json"); - let acir: Vec> = vec![Opcode::BrilligCall { - id: BrilligFunctionId(0), - inputs: vec![], - outputs: vec![], - predicate: None, - }]; + let acir: Vec> = vec![ + Opcode::BrilligCall { + id: BrilligFunctionId(0), + inputs: vec![], + outputs: vec![], + predicate: None, + }, + Opcode::BrilligCall { + id: BrilligFunctionId(1), + inputs: vec![], + outputs: vec![], + predicate: None, + }, + Opcode::BrilligCall { + id: BrilligFunctionId(2), + inputs: vec![], + outputs: vec![], + predicate: None, + }, + ]; let artifact = ProgramArtifact { noir_version: "0.0.0".to_string(), @@ -228,12 +253,16 @@ mod tests { abi: noirc_abi::Abi::default(), bytecode: Program { functions: vec![Circuit { opcodes: acir, ..Circuit::default() }], - unconstrained_functions: vec![BrilligBytecode::default()], + unconstrained_functions: vec![ + BrilligBytecode::default(), + BrilligBytecode::default(), + BrilligBytecode::default(), + ], }, debug_symbols: ProgramDebugInfo { debug_infos: vec![DebugInfo::default()] }, file_map: BTreeMap::default(), names: vec!["main".to_string()], - brillig_names: vec!["main".to_string()], + brillig_names: vec!["main".to_string(), "main".to_string(), "main_1".to_string()], }; // Write the artifact to a file @@ -245,11 +274,17 @@ mod tests { super::run_with_generator(&artifact_path, &flamegraph_generator, temp_dir.path(), false) .expect("should run without errors"); - // Check that the output files ware written to + // Check that the output files were written let output_file = temp_dir.path().join("main_acir_opcodes.svg"); assert!(output_file.exists()); - let output_file = temp_dir.path().join("0_brillig_opcodes.svg"); + let output_file = temp_dir.path().join("main_0_brillig_opcodes.svg"); + assert!(output_file.exists()); + + let output_file = temp_dir.path().join("main_1_brillig_opcodes.svg"); + assert!(output_file.exists()); + + let output_file = temp_dir.path().join("main_1_2_brillig_opcodes.svg"); assert!(output_file.exists()); } } diff --git a/tooling/profiler/src/flamegraph.rs b/tooling/profiler/src/flamegraph.rs index 38966902314..192539d6517 100644 --- a/tooling/profiler/src/flamegraph.rs +++ b/tooling/profiler/src/flamegraph.rs @@ -112,7 +112,7 @@ impl FlamegraphGenerator for InfernoFlamegraphGenerator { let mut options = Options::default(); options.hash = true; options.deterministic = true; - options.title = format!("{}-{}", artifact_name, function_name); + options.title = format!("Artifact: {}, Function: {}", artifact_name, function_name); options.frame_height = 24; options.color_diffusion = true; options.min_width = 0.0;