# Copyright 2017-2023 Lawrence Livermore National Security, LLC and other
# Hatchet Project Developers. See the top-level LICENSE file for details.
#
# SPDX-License-Identifier: MIT
import matplotlib.cm
import matplotlib.colors
[docs]def trees_to_dot(roots, dataframe, metric, name, rank, thread, threshold):
"""Calls to_dot in turn for each tree in the graph/forest."""
text = (
"strict digraph {\n"
"graph [bgcolor=transparent];\n"
"node [penwidth=4, shape=circle];\n"
"edge [penwidth=2];\n\n"
)
all_nodes = ""
all_edges = ""
# call to_dot for each root in the graph
visited = []
for root in roots:
(nodes, edges) = to_dot(
root, dataframe, metric, name, rank, thread, threshold, visited
)
all_nodes += nodes
all_edges += edges
text += all_nodes + "\n" + all_edges + "\n}\n"
return text
[docs]def to_dot(hnode, dataframe, metric, name, rank, thread, threshold, visited):
"""Write to graphviz dot format."""
colormap = matplotlib.cm.Reds
min_time = dataframe[metric].min()
max_time = dataframe[metric].max()
def add_nodes_and_edges(hnode):
# set dataframe index based on if rank is a part of the index
if "rank" in dataframe.index.names and "thread" in dataframe.index.names:
df_index = (hnode, rank, thread)
elif "rank" in dataframe.index.names:
df_index = (hnode, rank)
elif "thread" in dataframe.index.names:
df_index = (hnode, thread)
else:
df_index = hnode
node_time = dataframe.loc[df_index, metric]
node_name = dataframe.loc[df_index, name]
node_id = hnode._hatchet_nid
weight = (node_time - min_time) / (max_time - min_time)
color = matplotlib.colors.rgb2hex(colormap(weight))
# only display nodes whose metric is greater than some threshold
if (node_time >= threshold * max_time) and (hnode not in visited):
node_string = '"{0}" [color="{1}", label="{2}" shape=oval];\n'.format(
node_id, color, node_name
)
edge_string = ""
# only display those edges where child's metric is greater than
# threshold
children = []
for child in hnode.children:
if (
"rank" in dataframe.index.names
and "thread" in dataframe.index.names
):
df_index = (child, rank, thread)
elif "rank" in dataframe.index.names:
df_index = (child, rank)
elif "thread" in dataframe.index.names:
df_index = (child, thread)
else:
df_index = child
child_time = dataframe.loc[df_index, metric]
if child_time >= threshold * max_time:
children.append(child)
visited.append(hnode)
for child in children:
# add edges
child_id = child._hatchet_nid
edge_string += '"{0}" -> "{1}";\n'.format(node_id, child_id)
(nodes, edges) = add_nodes_and_edges(child)
node_string += nodes
edge_string += edges
else:
node_string = ""
edge_string = ""
return (node_string, edge_string)
# call add_nodes_and_edges on the root
return add_nodes_and_edges(hnode)