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

[Profiling] Visualizations: Cycle flame graph, frequency flame graph, timeline view #2284

Merged
merged 117 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
117 commits
Select commit Hold shift + click to select a range
0732319
emitting JSON at the end of the program instead of after each component
ayakayorihiro Aug 20, 2024
2d39cf1
TDCC emits control info about all components in one JSON
ayakayorihiro Aug 20, 2024
a6e13ed
clippy errors. rust is fun
ayakayorihiro Aug 20, 2024
dd4318c
Support outputting component cell info from TDCC for now
ayakayorihiro Aug 20, 2024
3d9324e
reading cell info from json
ayakayorihiro Aug 21, 2024
081423c
WIP
ayakayorihiro Aug 21, 2024
fbbcda0
mapping from components to all cell instantiations
ayakayorihiro Aug 21, 2024
960f412
WIP; small bug fixes
ayakayorihiro Aug 21, 2024
fd50075
WIP: untangling errors that I introduced and trying to remember what …
ayakayorihiro Aug 22, 2024
bf13c48
clean up unneeded prints
ayakayorihiro Aug 22, 2024
9a8f6f9
Move component cell info generation from TDCC to a backend
ayakayorihiro Aug 22, 2024
ffcc560
Updating script and writing some comments
ayakayorihiro Aug 22, 2024
6201f42
remove deprecated option
ayakayorihiro Aug 22, 2024
59dd635
More comments
ayakayorihiro Aug 22, 2024
2907826
decluttering code and trying to make things more clear
ayakayorihiro Aug 22, 2024
463b6b4
be more precise about the signal names we are looking out for
ayakayorihiro Aug 22, 2024
86500dc
remove more hacks
ayakayorihiro Aug 22, 2024
c74faa9
more cleanup
ayakayorihiro Aug 22, 2024
29ba49a
Make component-cells its own tool
ayakayorihiro Aug 23, 2024
3821172
Fix script to run component-cells tool instead of removed backend
ayakayorihiro Aug 23, 2024
5297024
some fixes
ayakayorihiro Aug 24, 2024
496de99
fixed errors - we can now profile pipelined-macgit add tools/profiler…
ayakayorihiro Aug 24, 2024
6e1f900
[WIP] Change TOP to toplevel for verilator
ayakayorihiro Aug 25, 2024
b1e64df
Update icarus in fud2
ayakayorihiro Aug 25, 2024
2542460
fud2 cleanup
ayakayorihiro Aug 25, 2024
c664f71
Update fud's testbench to use "toplevel" instead of TOP
ayakayorihiro Aug 26, 2024
97f5b60
update tests for multiple drivers
ayakayorihiro Aug 26, 2024
ee91ef9
Update systolic array tests
ayakayorihiro Aug 26, 2024
a46d937
Merge branch 'verilog-toplevel-module' into profiling-multicomponent
ayakayorihiro Aug 26, 2024
4d99caf
Writing the summary to CSV for easier comparison
ayakayorihiro Aug 26, 2024
738917c
small bug fix
ayakayorihiro Aug 26, 2024
7cb306f
sort groups based on running time
ayakayorihiro Aug 26, 2024
331da77
reading in groups that the user defined
ayakayorihiro Aug 26, 2024
e05d839
uniformly order groups based on total cycle counts
ayakayorihiro Aug 27, 2024
46d79d9
include total cycles in program in summary CSV
ayakayorihiro Aug 27, 2024
f302968
first test for profiling
ayakayorihiro Aug 27, 2024
3bcae58
Sort group names alphabetically first to ensure stability
ayakayorihiro Aug 27, 2024
b3d3ee1
merge
ayakayorihiro Aug 27, 2024
0b1d7ad
really small test for par
ayakayorihiro Aug 27, 2024
45e9e3d
Outputted CSV no longer DOS
ayakayorihiro Aug 27, 2024
0dc0a01
merge
ayakayorihiro Aug 27, 2024
a0aae7f
Attempt to change dockerfile to install vcdvcd
ayakayorihiro Aug 27, 2024
f056cf0
Using open parens to describe segment end
ayakayorihiro Aug 27, 2024
c0de05a
merge
ayakayorihiro Aug 27, 2024
5083c02
super simple test with a single seq
ayakayorihiro Aug 27, 2024
16492b0
utility script for seeing program after tdcc
ayakayorihiro Aug 27, 2024
3a147d1
super quick workaround for CI issues
ayakayorihiro Aug 28, 2024
2b4f962
Profiler tests need to be run sequentially
ayakayorihiro Aug 28, 2024
425ef24
Fix yml bug
ayakayorihiro Aug 28, 2024
470f4e6
Restore
ayakayorihiro Aug 28, 2024
3f02823
actually restore the yml file
ayakayorihiro Aug 28, 2024
d0cc6a8
Update rust.yml to exclude profiling
ayakayorihiro Aug 28, 2024
67faa53
using | for excluding two test suites?
ayakayorihiro Aug 29, 2024
84c7c2f
Add profiler tests to rust.yml
ayakayorihiro Aug 29, 2024
08e767f
making sure verilator is run by fud2
ayakayorihiro Aug 29, 2024
ad75841
writing info to json to process for visualizer
ayakayorihiro Aug 29, 2024
e6e5857
remove profiler tests from CI until I figure out CI bug
ayakayorihiro Aug 29, 2024
2bc7ac8
quick script to make visualization
ayakayorihiro Aug 30, 2024
9feb401
Profiler script improvements; now creates visualizations
ayakayorihiro Aug 30, 2024
99aa7e2
cleanup
ayakayorihiro Aug 30, 2024
2d2d441
ignore data files
ayakayorihiro Aug 30, 2024
351c5e0
merge
ayakayorihiro Aug 30, 2024
088fe67
revert script
ayakayorihiro Aug 30, 2024
07db861
[WIP] saving before I pull out the diff
ayakayorihiro Aug 30, 2024
910de26
[WIP] absolute mess but merged with stashed version
ayakayorihiro Aug 30, 2024
8525851
[WIP] decluttering and small bits of debugging
ayakayorihiro Aug 30, 2024
822db49
[WIP] still have some weird stuff going on but GT write shows up as a…
ayakayorihiro Aug 30, 2024
d3d7611
[WIP] started postprocessing function, will fix up the FSM informatio…
ayakayorihiro Sep 1, 2024
3582fca
[WIP] done with most of the overhaul, need to massage TDCC group part
ayakayorihiro Sep 2, 2024
0262680
remove big chunk of commented out code
ayakayorihiro Sep 2, 2024
945da30
[WIP] need to do more fixes and cleanup but the base is down
ayakayorihiro Sep 2, 2024
3b9569e
Update visualization script to show FSM vers differently
ayakayorihiro Sep 2, 2024
5c3f736
CSV should denote FSM
ayakayorihiro Sep 2, 2024
e29d066
[WIP] Need to remove hacks and clean up but simple-par is working!
ayakayorihiro Sep 3, 2024
8792882
[WIP] Breaking the script to handle FSMs more safely
ayakayorihiro Sep 3, 2024
30d73fd
Fix made, need to clean up
ayakayorihiro Sep 3, 2024
b3c47aa
Big cleanup
ayakayorihiro Sep 3, 2024
d2d2642
merge with main
ayakayorihiro Sep 3, 2024
bcfc2b8
small fixes
ayakayorihiro Sep 3, 2024
2bd11b2
Remove file system bits from tests
ayakayorihiro Sep 3, 2024
8d70610
Removing profiler tests from CI
ayakayorihiro Sep 3, 2024
33648cc
Removed wrong file
ayakayorihiro Sep 3, 2024
a8a341e
First pass attempt at flame graph
ayakayorihiro Sep 3, 2024
593350a
Tiny refactoring
ayakayorihiro Sep 4, 2024
d5cf333
main component has to go for a difference between total and active gr…
ayakayorihiro Sep 4, 2024
388c92e
tiny bug fix
ayakayorihiro Sep 5, 2024
a169cc4
hacky workaround for non-invoke multicomponent
ayakayorihiro Sep 5, 2024
3f17fd7
Running flame graph svg creation script and obtaining segments for cells
ayakayorihiro Sep 5, 2024
57b2420
printing out information
ayakayorihiro Sep 6, 2024
fa45dc1
slowly chipping at finding when events are simulatenous
ayakayorihiro Sep 6, 2024
770a9b3
[WIP] more hacking
ayakayorihiro Sep 6, 2024
8e6c3d1
got first hacky stack to work
ayakayorihiro Sep 7, 2024
70adccb
output layers correctly for one multicomponent program. need to try o…
ayakayorihiro Sep 8, 2024
7270c7b
some cleanup
ayakayorihiro Sep 8, 2024
479f9e1
Small bug fixes to get multi-component programs with more than two co…
ayakayorihiro Sep 8, 2024
0ce2dad
[WIP] generating FSM version of flame graph
ayakayorihiro Sep 9, 2024
960051f
Compute and output stacked FSM flame graph
ayakayorihiro Sep 9, 2024
89ac625
working on timeline view with stacks
ayakayorihiro Sep 9, 2024
27788fb
[WIP] timeline view first pass wip
ayakayorihiro Sep 9, 2024
898aade
first pass for timeline view done
ayakayorihiro Sep 9, 2024
91700c9
small bug fixes and seq-ed benchmarks
ayakayorihiro Sep 10, 2024
1d1c31c
exit early on error
ayakayorihiro Sep 10, 2024
3e81a70
Run par-to-seq pass to avoid sed misses
ayakayorihiro Sep 11, 2024
c4b9552
trying to handmake user-actionable flame graphs
ayakayorihiro Sep 11, 2024
8c54eaa
flame graph using line #s
ayakayorihiro Sep 11, 2024
f78f49d
Organizing groups based on what for loop they belonged in
ayakayorihiro Sep 11, 2024
f4278e7
adding layers to ntt-32 flame graph
ayakayorihiro Sep 12, 2024
73a4a2d
ntt-32 with categorizations
ayakayorihiro Sep 12, 2024
d5c9a46
[WIP] Need to modify frequency to account for the same group being ca…
ayakayorihiro Sep 16, 2024
da00114
Frequency flame graphs
ayakayorihiro Sep 16, 2024
3654743
fixing small bugs in frequency flame graph
ayakayorihiro Sep 16, 2024
6270ba9
Use different wording for frequency flame graphs
ayakayorihiro Sep 16, 2024
9c2a9a3
Add compile-repeat
ayakayorihiro Sep 17, 2024
034fcd0
ignore autogenerated svg files
ayakayorihiro Sep 17, 2024
5a458fb
merge
ayakayorihiro Sep 17, 2024
01db5fa
remove unnecessary sequentialized-benchmarks
ayakayorihiro Sep 17, 2024
a23ef17
remove print debugging
ayakayorihiro Sep 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ tools/btor2/btor2i/build/

# profiling ignore
tools/profiler/data
tools/profiler/meta-logs
tools/profiler/fg-tmp
tools/profiler/handmade-flame-graphs/*/*.svg

temp/

Expand Down
43 changes: 0 additions & 43 deletions tools/profiler/convert-dump.py

This file was deleted.

299 changes: 299 additions & 0 deletions tools/profiler/create-visuals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,299 @@
# Takes in a dump file created by parse-vcd.py and creates a JSON file in the Google Trace Event Format
import json
import sys

class FlameInfo:
def __init__(self, name, backptr, cycles, is_fsm):
self.name = name
self.backptr = backptr
self.cycles = cycles
self.is_fsm = is_fsm

def make_folded_log_entry(self):
if self.backptr is not None:
return f'{self.backptr};{self.name} {self.cycles}'
else:
return f'{self.name} {self.cycles}'

# Computes which groups have a FSM-recorded group
def get_fsm_groups(profiled_info):
fsm_groups = set()
all_groups = set()
for group_info in profiled_info:
if group_info["name"] == "TOTAL" or group_info["component"] is None:
continue
all_groups.add(group_info["name"])
if group_info["fsm_name"] is not None:
fsm_groups.add(group_info["name"])
return fsm_groups, all_groups

def create_timeline_map(profiled_info, fsm_groups, all_groups):
summary = list(filter(lambda x : x["name"] == "TOTAL", profiled_info))[0]
total_cycles = summary["total_cycles"]
only_gt_groups = all_groups.difference(fsm_groups)
timeline_map = {i : {} for i in range(total_cycles)}
fsm_timeline_map = {i : {} for i in range(total_cycles)}
group_to_gt_segments = {} # we need segment info for frequency checking
for group_info in profiled_info:
group_name = group_info["name"]
if group_name == "TOTAL" or group_info["component"] is None: # only care about actual groups
continue
for segment in group_info["closed_segments"]:
if group_info["fsm_name"] is None:
if group_name not in group_to_gt_segments:
group_to_gt_segments[group_name] = {} # segment start cycle to segment end cycle
group_to_gt_segments[group_name][segment["start"]] = segment["end"]
for i in range(segment["start"], segment["end"]): # really janky, I wonder if there's a better way to do this?
if group_info["fsm_name"] is not None: # FSM version
fsm_timeline_map[i][group_info["component"]] = group_name
elif group_name in only_gt_groups: # A group that isn't managed by an FSM. In which case it has to be in both FSM and GT
fsm_timeline_map[i][group_info["component"]] = group_name
timeline_map[i][group_info["component"]] = group_name
else: # The ground truth info about a group managed by an FSM.
timeline_map[i][group_info["component"]] = group_name

return timeline_map, fsm_timeline_map, group_to_gt_segments

def create_frequency_flame_graph(main_component, cells_map, timeline, group_to_gt_segments, frequency_flame_out):
main_shortname = main_component.split("TOP.toplevel.")[1]
frequency_stacks = {}
i = 0
while i < len(timeline):
if len(timeline[i]) == 0:
i += 1
continue
group_component = sorted(timeline[i], key=lambda k : timeline[i][k].count("."), reverse=True)[0]
group_full_name = timeline[i][group_component]
stack = ""
group_name = group_full_name.split(".")[-1]
# FIXME: code clone
if group_component == main_shortname:
stack = main_component + ";" + group_name
else:
after_main = group_full_name.split(f"{main_component}.")[1]
after_main_split = after_main.split(".")[:-1]
# first, find the group in main that is simulatenous
if main_shortname not in timeline[i]:
print(f"Error: A group from the main component ({main_shortname}) should be active at cycle {i}!")
exit(1)
backptrs = [main_component]
group_from_main = timeline[i][main_shortname].split(main_component + ".")[-1]
backptrs.append(group_from_main)
prev_component = main_shortname
for cell_name in after_main_split:
cell_component = cells_map[prev_component][cell_name]
group_from_component = timeline[i][cell_component].split(cell_name + ".")[-1]
backptrs.append(f"{cell_component}[{prev_component}.{cell_name}];{group_from_component}")
prev_component = cell_component
stack = ";".join(backptrs)
if stack not in frequency_stacks:
frequency_stacks[stack] = 0
frequency_stacks[stack] += 1
i = group_to_gt_segments[group_full_name][i] # the next segment to check starts at the end time of this segment

write_flame_graph(frequency_flame_out, frequency_stacks)

# attempt to rehash the create_flame_graph to take care of stacks
def create_flame_graph(main_component, cells_map, timeline, fsm_timeline, flame_out, fsm_flame_out):
stacks = compute_flame_stacks(cells_map, timeline, main_component)
write_flame_graph(flame_out, stacks)
fsm_stacks = compute_flame_stacks(cells_map, fsm_timeline, main_component)
write_flame_graph(fsm_flame_out, fsm_stacks)

def create_timeline_stacks(timeline, main_component):
events = []
currently_active = {} # group name to beginning traceEvent entry (so end event can copy)
ts_multiplier = 100 # some arbitrary number to multiply by so that it's easier to see in the viewer
cell_to_stackframe_info = {main_component : (2, 1)} # (stack_number, parent_stack_number)
stack_number_acc = 3 # To guarantee that we get unique stack numbers when we need a new one

# Beginning and end events for main signify the overall running time (stack 1)
main_event_details = {"name": main_component, "sf": 1, "cat": "MAIN", "pid": 1, "tid": 1}
main_start = main_event_details.copy()
main_start["ts"] = 0
main_start["ph"] = "B"
events.append(main_start)
main_end = main_event_details.copy()
main_end["ts"] = len(timeline) * ts_multiplier
main_end["ph"] = "E"
events.append(main_end)
cell_to_stackframe_info["MAIN"] = (1, None)

for i in timeline:
active_this_cycle = set()
# Differently from compute_flame_stacks, we start from the bottom up. (easier to see parent)
sorted_active_groups = list(sorted(timeline[i], key=lambda k : timeline[i][k].count(".")))
for group_component in sorted_active_groups:
group_full_name = timeline[i][group_component]
active_this_cycle.add(group_full_name)
if group_full_name not in currently_active: # first cycle of the group. We need to figure out the stack
group_split = group_full_name.split(".")
group_cell = ".".join(group_split[:-1])
group_shortname = group_split[-1]
stackframe = -1 # FIXME: find the appropriate stack frame
if group_cell in cell_to_stackframe_info:
(stackframe, _) = cell_to_stackframe_info[main_component]
else:
# Since we are iterating from the shortest to longest name (based on cell counts)
# The group's cell's parent *must* be in cell_to_stackframe_info
group_cell_parent = ".".join(group_split[:-2])
(parent_stackframe, _) = cell_to_stackframe_info[group_cell_parent]
stackframe = stack_number_acc
stack_number_acc += 1
cell_to_stackframe_info[group_cell] = (stackframe, parent_stackframe)
start_event = {"name": group_shortname, "cat": group_component, "ph": "B", "pid" : 1, "tid": 1, "ts": i * ts_multiplier, "sf" : stackframe}
events.append(start_event)
currently_active[group_full_name] = start_event
# Any group that was previously active but not active this cycle need to end
for non_active_group in set(currently_active.keys()).difference(active_this_cycle):
end_event = currently_active[non_active_group].copy()
del currently_active[non_active_group]
end_event["ts"] = (i) * ts_multiplier - 1
end_event["ph"] = "E"
events.append(end_event)
# postprocess - add end events for all events still active by the end
for event in currently_active:
end_event = currently_active[event].copy()
end_event["ts"] = (len(timeline)) * ts_multiplier - 1 # only difference w the above
end_event["ph"] = "E"
events.append(end_event)

# "stackFrames" field of the Trace Format JSON
stacks = {}
stack_category = "C"
for cell in cell_to_stackframe_info:
stack_id, parent_stack_id = cell_to_stackframe_info[cell]
if parent_stack_id is None:
stacks[stack_id] = {"name" : "MAIN", "category": stack_category}
else:
stacks[stack_id] = {"name" : cell, "parent": parent_stack_id, "category" : stack_category}

return { "traceEvents": events, "stackFrames": stacks }

def create_timeline_json(timeline, fsm_timeline, main_component, timeline_out, fsm_timeline_out):
timeline_json_data = create_timeline_stacks(timeline, main_component)
with open(timeline_out, "w", encoding="utf-8") as timeline_file:
timeline_file.write(json.dumps(timeline_json_data, indent=4))
fsm_timeline_json_data = create_timeline_stacks(fsm_timeline, main_component)
with open(fsm_timeline_out, "w", encoding="utf-8") as fsm_timeline_file:
fsm_timeline_file.write(json.dumps(fsm_timeline_json_data, indent=4))


def compute_flame_stacks(cells_map, timeline, main_component):
main_shortname = main_component.split("TOP.toplevel.")[1]
stacks = {} # each stack to the # of cycles it was active for
nonactive_cycles = 0 # cycles where no group was active
for i in timeline: # keys in the timeline are clock time stamps
# Right now we are assuming that there are no pars. So for any time stamp, *if there are multiple* groups active,
# we need to find the one that is the longest (since that's the innermost one).
# NOTE: This might be generalizable for even the 1 group active case? Going to try it out
if len(timeline[i]) == 0:
nonactive_cycles += 1
continue
group_component = sorted(timeline[i], key=lambda k : timeline[i][k].count("."), reverse=True)[0]
group_full_name = timeline[i][group_component]
stack = ""
group_name = group_full_name.split(".")[-1]
if group_component == main_shortname:
stack = main_component + ";" + group_name
else:
after_main = group_full_name.split(f"{main_component}.")[1]
after_main_split = after_main.split(".")[:-1]
# first, find the group in main that is simulatenous
if main_shortname not in timeline[i]:
print(f"Error: A group from the main component ({main_shortname}) should be active at cycle {i}!")
exit(1)
backptrs = [main_component]
group_from_main = timeline[i][main_shortname].split(main_component + ".")[-1]
backptrs.append(group_from_main)
prev_component = main_shortname
for cell_name in after_main_split:
cell_component = cells_map[prev_component][cell_name]
group_from_component = timeline[i][cell_component].split(cell_name + ".")[-1]
backptrs.append(f"{cell_component}[{prev_component}.{cell_name}];{group_from_component}")
prev_component = cell_component
stack = ";".join(backptrs)

if stack not in stacks:
stacks[stack] = 0
stacks[stack] += 1

stacks[main_component] = nonactive_cycles
return stacks

def write_flame_graph(flame_out, stacks):
with open(flame_out, "w") as f:
for stack in sorted(stacks, key=lambda k : len(k)): # main needs to come first for flame graph script to not make two boxes for main?
f.write(f"{stack} {stacks[stack]}\n")

# Starting with the JSON array format for now... [Needs to be fixed]
# example
# [ {"name": "Asub", "cat": "PERF", "ph": "B", "pid": 22630, "tid": 22630, "ts": 829},
# {"name": "Asub", "cat": "PERF", "ph": "E", "pid": 22630, "tid": 22630, "ts": 833} ]
def create_timeline_view(profiled_info, out_file):
cat = "GT" # Ground truth category (will overwrite if it's FSM)
events = []
id_acc = 1
ts_multiplier = 100 # some arbitrary number to multiply by so that it's easier to see in the viewer
for group_info in profiled_info:
if group_info["name"] == "TOTAL": # timeline view doesn't need a total time
continue
name = group_info["name"].split("TOP.toplevel.", 1)[1]
if group_info["fsm_name"] is not None:
cat = "FSM"
name = "[FSM] " + name
for segment in group_info["closed_segments"]:
# beginning of segment
begin_time = segment["start"] * ts_multiplier
events.append({"name": name, "cat": cat, "ph": "B", "pid" : id_acc, "tid": id_acc, "ts" : begin_time})
# end of segment
end_time = segment["end"] * ts_multiplier
events.append({"name": name, "cat": cat, "ph": "E", "pid": id_acc, "tid": id_acc, "ts": end_time})
id_acc += 1
with open(out_file, "w") as out:
json.dump(events, out, indent=4)

def build_cells_map(json_file):
cell_json = json.load(open(json_file))
cells_map = {}
for component_entry in cell_json:
inner_cells_map = {}
for cell_entry in component_entry["cell_info"]:
inner_cells_map[cell_entry["cell_name"]] = cell_entry["component_name"]
cells_map[component_entry["component"]] = inner_cells_map
return cells_map

def main(profiler_dump_file, cells_json, timeline_out, fsm_timeline_out, flame_out, fsm_flame_out, frequency_flame_out):
profiled_info = json.load(open(profiler_dump_file, "r"))
fsm_groups, all_groups = get_fsm_groups(profiled_info)
# This cells_map is different from the one in parse-vcd.py
cells_map = build_cells_map(cells_json)
timeline, fsm_timeline, group_to_gt_segments = create_timeline_map(profiled_info, fsm_groups, all_groups)
summary = list(filter(lambda x : x["name"] == "TOTAL", profiled_info))[0]
main_component = summary["main_full_path"]
create_flame_graph(main_component, cells_map, timeline, fsm_timeline, flame_out, fsm_flame_out)
create_timeline_json(timeline, fsm_timeline, main_component, timeline_out, fsm_timeline_out)
create_frequency_flame_graph(main_component, cells_map, timeline, group_to_gt_segments, frequency_flame_out)

if __name__ == "__main__":
if len(sys.argv) > 7:
profiler_dump_json = sys.argv[1]
cells_json = sys.argv[2]
timeline_out = sys.argv[3]
fsm_timeline_out = sys.argv[4]
flame_out = sys.argv[5]
fsm_flame_out = sys.argv[6]
frequency_flame_out = sys.argv[7]
main(profiler_dump_json, cells_json, timeline_out, fsm_timeline_out, flame_out, fsm_flame_out, frequency_flame_out)
else:
args_desc = [
"PROFILER_JSON",
"CELLS_JSON",
"TIMELINE_VIEW_JSON",
"FSM_TIMELINE_VIEW_JSON",
"FLAME_GRAPH_FOLDED",
"FSM_FLAME_GRAPH_FOLDED",
"FREQUENCY_FLAME_GRAPH_FOLDED"
]
print(f"Usage: {sys.argv[0]} {' '.join(args_desc)}")
sys.exit(-1)
Loading
Loading