util: Add class name to dot graph and output to svg
authorAndreas Hansson <andreas.hansson@arm.com>
Wed, 4 Sep 2013 17:22:58 +0000 (13:22 -0400)
committerAndreas Hansson <andreas.hansson@arm.com>
Wed, 4 Sep 2013 17:22:58 +0000 (13:22 -0400)
This patch adds the class name to the label, creates some more space
by increasing the rank separation, and additionally outputs the graph
as an editable SVG in addition to the PDF.

src/python/m5/util/dot_writer.py

index 52d0b4b62145f74db4bdf7639b4ecd1ad4e720d0..fbeb655ca2125ed5be6f7a0e4450bac64117a49d 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2012 ARM Limited
+# Copyright (c) 2012-2013 ARM Limited
 # All rights reserved.
 #
 # The license below extends only to copyright in the software and shall
 # System visualization using DOT
 #
 # While config.ini and config.json provide an almost complete listing
-# of a system's components and connectivity, they lack a birds-eye view.
-# The output generated by do_dot() is a DOT-based figure (pdf) and its
-# source dot code. Nodes are components, and edges represent
-# the memory hierarchy: the edges are directed, from a master to a slave.
-# Initially all nodes are generated, and then all edges are added.
-# do_dot should be called with the top-most SimObject (namely root
-# but not necessarily), the output folder and the output dot source
-# filename. From the given node, both processes (node and edge creation)
-# is performed recursivly, traversing all children of the given root.
+# of a system's components and connectivity, they lack a birds-eye
+# view. The output generated by do_dot() is a DOT-based figure (as a
+# pdf and an editable svg file) and its source dot code. Nodes are
+# components, and edges represent the memory hierarchy: the edges are
+# directed, from a master to slave. Initially all nodes are
+# generated, and then all edges are added. do_dot should be called
+# with the top-most SimObject (namely root but not necessarily), the
+# output folder and the output dot source filename. From the given
+# node, both processes (node and edge creation) is performed
+# recursivly, traversing all children of the given root.
 #
 # pydot is required. When missing, no output will be generated.
 #
@@ -70,6 +71,8 @@ def dot_create_nodes(simNode, callgraph):
     else:
         label = simNode._name
     full_path = re.sub('\.', '_', simNode.path())
+    # add class name under the label
+    label = "\"" + label + " \\n: " + simNode.__class__.__name__ + "\""
 
     # each component is a sub-graph (cluster)
     cluster = dot_create_cluster(simNode, full_path, label)
@@ -155,19 +158,28 @@ def dot_create_node(simNode, full_path, label):
                          )
 
 # generate color for nodes
-# currently a simple grayscale. placeholder for aesthetic programmers.
 def dot_gen_color(simNode):
+    # start off with white
+    base = (256, 256, 256)
+    # scale the color based on the depth
     depth = len(simNode.path().split('.'))
-    depth = 256 - depth * 16 * 3
-    return dot_rgb_to_html(simNode, depth, depth, depth)
+    # slightly arbitrary, but assume that the depth is less than six
+    # levels
+    r, g, b = map(lambda x: x * max(1 - depth / 6.0, 0.3), base)
 
-def dot_rgb_to_html(simNode, r, g, b):
+    return dot_rgb_to_html(r, g, b)
+
+def dot_rgb_to_html(r, g, b):
     return "#%.2x%.2x%.2x" % (r, g, b)
 
 def do_dot(root, outdir, dotFilename):
     if not pydot:
         return
-    callgraph = pydot.Dot(graph_type='digraph')
+    # * use ranksep > 1.0 for for vertical separation between nodes
+    # especially useful if you need to annotate edges using e.g. visio
+    # which accepts svg format
+    # * no need for hoizontal separation as nothing moves horizonally
+    callgraph = pydot.Dot(graph_type='digraph', ranksep='1.3')
     dot_create_nodes(root, callgraph)
     dot_create_edges(root, callgraph)
     dot_filename = os.path.join(outdir, dotFilename)
@@ -175,6 +187,7 @@ def do_dot(root, outdir, dotFilename):
     try:
         # dot crashes if the figure is extremely wide.
         # So avoid terminating simulation unnecessarily
+        callgraph.write_svg(dot_filename + ".svg")
         callgraph.write_pdf(dot_filename + ".pdf")
     except:
         warn("failed to generate pdf output from %s", dot_filename)