From 9115305c3135087a08164613889e37762cb89b94 Mon Sep 17 00:00:00 2001 From: Ayaka Yorihiro Date: Tue, 14 Jan 2025 11:25:38 -0500 Subject: [PATCH] Tinkering with adl-only flame graph --- .../tests__test@plan_edsl-profiler.snap | 68 +++++++++++++++++++ tools/profiler/profiler-process.py | 41 +++++++---- 2 files changed, 94 insertions(+), 15 deletions(-) create mode 100644 fud2/tests/snapshots/tests__test@plan_edsl-profiler.snap diff --git a/fud2/tests/snapshots/tests__test@plan_edsl-profiler.snap b/fud2/tests/snapshots/tests__test@plan_edsl-profiler.snap new file mode 100644 index 000000000..540e03b5d --- /dev/null +++ b/fud2/tests/snapshots/tests__test@plan_edsl-profiler.snap @@ -0,0 +1,68 @@ +--- +source: fud2/tests/tests.rs +description: "emit plan: edsl-profiler" +snapshot_kind: text +--- +build-tool = fud2 +rule get-rsrc + command = $build-tool get-rsrc $out + +calyx-base = /test/calyx +calyx-exe = $calyx-base/target/debug/calyx +calyx-lib-path = $calyx-base +args = +rule calyx + command = $calyx-exe -l $calyx-lib-path -b $backend $args $in > $out +rule calyx-pass + command = $calyx-exe -l $calyx-lib-path -p $pass $args $in > $out +cider-calyx-passes = -p none +rule calyx-cider + command = $calyx-exe -l $calyx-lib-path $cider-calyx-passes $args $in > $out + +cells = cells.json +passes = -p all +component_cells = $calyx-base/target/debug/component_cells +rule component-cells + command = $component_cells -l $calyx-base $in > $out +parse-vcd-script = $calyx-base/tools/profiler/profiler-process.py +rule parse-vcd + command = python3 $parse-vcd-script $in $cells NA profiler-out $out + +verilator = verilator +cycle-limit = 500000000 +rule verilator-compile-standalone-tb + command = $verilator $in tb.sv --trace --binary --top-module toplevel -fno-inline -Mdir $out-dir +rule verilator-compile-custom-tb + command = $verilator $in tb.sv memories.sv --trace --binary --top-module toplevel -fno-inline -Mdir $out-dir +rule cp + command = cp $in $out + +python = python3 +build json-dat.py: get-rsrc +rule hex-data + command = $python json-dat.py --from-json $in $out +rule json-data + command = $python json-dat.py --to-json $out $in +sim_data = /test/data.json +datadir = sim_data +build $datadir: hex-data $sim_data | json-dat.py +rule sim-run + command = ./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out +cycle-limit = 500000000 + +build calyx.futil: edsl-to-calyx /input.ext +build $metadata-mapping-json: parse-metadata calyx.futil +build $cells: component-cells calyx.futil +build instrumented.sv: calyx calyx.futil + backend = verilog + args = -p static-inline -p compile-static -p compile-repeat -p compile-invoke -p profiler-instrumentation $passes +build verilator-out/Vtoplevel: verilator-compile-standalone-tb instrumented.sv | tb.sv + out-dir = verilator-out +build instrumented.exe: cp verilator-out/Vtoplevel +build sim.log instrumented.vcd: sim-run instrumented.exe $datadir + bin = instrumented.exe + args = +NOTRACE=0 +OUT=instrumented.vcd +build flamegraph.folded: parse-vcd-from-adl instrumented.vcd | $cells $metadata-mapping-json +build /output.ext: create-visuals flamegraph.folded + +default /output.ext diff --git a/tools/profiler/profiler-process.py b/tools/profiler/profiler-process.py index 96b981354..333c28161 100644 --- a/tools/profiler/profiler-process.py +++ b/tools/profiler/profiler-process.py @@ -650,41 +650,50 @@ def read_adl_mapping_file(adl_mapping_file): def convert_trace(trace, adl_mapping_file): component_map, cell_map, group_map = read_adl_mapping_file(adl_mapping_file) - adl_trace = {i : [] for i in trace} + mixed_trace = {i : [] for i in trace} # contains both calyx group/cell/component name and ADL source location. + adl_only_trace = {i: [] for i in trace} # contains only the ADL source location (NOTE: would be nice to have the construct name within the ADL?) # trace should probably be more principled than this... lol for i in trace: for stack in trace[i]: - adl_stack = [] + adl_only_stack = [] + mixed_stack = [] curr_component = None for stack_elem in stack: # going to start by assuming "main" is the entrypoint. if stack_elem == "main": curr_component = stack_elem sourceloc = component_map[stack_elem] - new_stack_elem = f"main {{{sourceloc}}}" + mixed_stack_elem = f"main {{{sourceloc}}}" + adl_stack_elem = mixed_stack_elem elif "[" in stack_elem: # invocation of component cell cell = stack_elem.split("[")[0].strip() cell_sourceloc = cell_map[curr_component][cell] cell_component = stack_elem.split("[")[1].split("]")[0] cell_component_sourceloc = component_map[cell_component] - new_stack_elem = f"{cell} {{{cell_sourceloc}}} [{cell_component} {{{cell_component_sourceloc}}}]" + mixed_stack_elem = f"{cell} {{{cell_sourceloc}}} [{cell_component} {{{cell_component_sourceloc}}}]" + adl_stack_elem = f"{cell_sourceloc} [{cell_component_sourceloc}]" curr_component = cell_component elif "(primitive)" in stack_elem: # primitive primitive = stack_elem.split("(primitive)")[0].strip() primitive_sourceloc = cell_map[curr_component][primitive] - new_stack_elem = f"{stack_elem} {{{primitive_sourceloc}}}" + mixed_stack_elem = f"{stack_elem} {{{primitive_sourceloc}}}" + adl_stack_elem = f"{{{primitive_sourceloc}}}" else: # group # ignore compiler-generated groups (invokes) for now... if stack_elem in group_map[curr_component]: sourceloc = group_map[curr_component][stack_elem] + adl_stack_elem = f"{{{sourceloc}}}" else: sourceloc = "compiler-generated" - new_stack_elem = f"{stack_elem} {{{sourceloc}}}" - adl_stack.append(new_stack_elem) - adl_trace[i].append(adl_stack) + adl_stack_elem = sourceloc + mixed_stack_elem = f"{stack_elem} {{{sourceloc}}}" + adl_only_stack.append(adl_stack_elem) + mixed_stack.append(mixed_stack_elem) + adl_only_trace[i].append(adl_only_stack) + mixed_trace[i].append(mixed_stack) - return adl_trace + return adl_only_trace, mixed_trace def main(vcd_filename, cells_json_file, adl_mapping_file, out_dir, flame_out, cells_for_timeline): print(f"Start time: {datetime.now()}") @@ -714,13 +723,15 @@ def main(vcd_filename, cells_json_file, adl_mapping_file, out_dir, flame_out, ce print(f"End time: {datetime.now()}") write_cell_stats(converter.cell_to_active_cycles, out_dir) - if adl_mapping_file != "NA": - # do adl mapping stuff... + if adl_mapping_file != "NA": # emit ADL flame graphs. print("Computing ADL flames...") - adl_trace = convert_trace(converter.trace, adl_mapping_file) - flat_adl_flame = os.path.join(out_dir, "adl-flat-flame.folded") - scaled_adl_flame = os.path.join(out_dir, "adl-scaled-flame.folded") - create_flame_groups(adl_trace, flat_adl_flame, out_dir, scaled_flame_out_file=scaled_adl_flame) + adl_trace, mixed_trace = convert_trace(converter.trace, adl_mapping_file) + adl_flat_flame = os.path.join(out_dir, f"adl-flat-flame.folded") + adl_scaled_flame = os.path.join(out_dir, f"adl-scaled-flame.folded") + create_flame_groups(adl_trace, adl_flat_flame, out_dir, scaled_flame_out_file=adl_scaled_flame) + mixed_flat_flame = os.path.join(out_dir, f"mixed-flat-flame.folded") + mixed_scaled_flame = os.path.join(out_dir, f"mixed-scaled-flame.folded") + create_flame_groups(mixed_trace, mixed_flat_flame, out_dir, scaled_flame_out_file=mixed_scaled_flame) if __name__ == "__main__": if len(sys.argv) > 5: