misc: Add secondary dot output for DVFS domains
authorSascha Bischoff <sascha.bischoff@arm.com>
Tue, 15 Dec 2015 09:40:56 +0000 (09:40 +0000)
committerSascha Bischoff <sascha.bischoff@arm.com>
Tue, 15 Dec 2015 09:40:56 +0000 (09:40 +0000)
This patch adds a secondary dot output file which shows the DVFS domains. This
has been done separately for now to avoid cluttering the already existing
diagram. Due to the way that the clock domains are assigned to components in
gem5, this output must be generated after the C++ objects have been
instantiated. This further motivates the need to generate this file separately
to the current dot output, and not to replace it entirely.

src/python/m5/main.py
src/python/m5/simulate.py
src/python/m5/util/dot_writer.py

index deb4725ac881de385b990d5098c34bf448942302..ea2a06e9e62e18b95f9ec9e41501380603582b19 100644 (file)
@@ -91,6 +91,9 @@ def parse_options():
         help="Create JSON output of the configuration [Default: %default]")
     option("--dot-config", metavar="FILE", default="config.dot",
         help="Create DOT & pdf outputs of the configuration [Default: %default]")
+    option("--dot-dvfs-config", metavar="FILE", default="config_dvfs.dot",
+        help="Create DOT & pdf outputs of the DVFS configuration" + \
+             " [Default: %default]")
 
     # Debugging options
     group("Debugging Options")
index 5d70f4b18a8d61feb4da4bc8fca6f391c9c974b8..1d7ebeb9da6fd3d7c380348f202627d3322f824d 100644 (file)
@@ -51,7 +51,7 @@ import stats
 import SimObject
 import ticks
 import objects
-from m5.util.dot_writer import do_dot
+from m5.util.dot_writer import do_dot, do_dvfs_dot
 from m5.internal.stats import updateEvents as updateStatEvents
 
 from util import fatal
@@ -126,6 +126,11 @@ def instantiate(ckpt_dir=None):
     # Do a fifth pass to connect probe listeners
     for obj in root.descendants(): obj.regProbeListeners()
 
+    # We want to generate the DVFS diagram for the system. This can only be
+    # done once all of the CPP objects have been created and initialised so
+    # that we are able to figure out which object belongs to which domain.
+    do_dvfs_dot(root, options.outdir, options.dot_dvfs_config)
+
     # We're done registering statistics.  Enable the stats package now.
     stats.enable()
 
index f54d6a1ab022806e240b4b46c5113dc3eb59fdd4..f0ad15adf7da25ba722c7c3dae613e1490484cc2 100644 (file)
@@ -35,6 +35,7 @@
 #
 # Authors: Andreas Hansson
 #          Uri Wiener
+#          Sascha Bischoff
 
 #####################################################################
 #
@@ -256,6 +257,96 @@ def dot_gen_colour(simNode, isPort = False):
 def dot_rgb_to_html(r, g, b):
     return "#%.2x%.2x%.2x" % (r, g, b)
 
+# We need to create all of the clock domains. We abuse the alpha channel to get
+# the correct domain colouring.
+def dot_add_clk_domain(c_dom, v_dom):
+    label = "\"" + str(c_dom) + "\ :\ " + str(v_dom) + "\""
+    label = re.sub('\.', '_', str(label))
+    full_path = re.sub('\.', '_', str(c_dom))
+    return pydot.Cluster( \
+                     full_path, \
+                     shape = "Mrecord", \
+                     label = label, \
+                     style = "\"rounded, filled, dashed\"", \
+                     color = "#000000", \
+                     fillcolor = "#AFC8AF8F", \
+                     fontname = "Arial", \
+                     fontsize = "14", \
+                     fontcolor = "#000000" \
+                     )
+
+def dot_create_dvfs_nodes(simNode, callgraph, domain=None):
+    if isRoot(simNode):
+        label = "root"
+    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)
+
+    # create nodes per port
+    for port_name in simNode._ports.keys():
+        port = simNode._port_refs.get(port_name, None)
+        if port != None:
+            full_port_name = full_path + "_" + port_name
+            port_node = dot_create_node(simNode, full_port_name, port_name)
+            cluster.add_node(port_node)
+
+    # Dictionary of DVFS domains
+    dvfs_domains = {}
+
+    # recurse to children
+    if simNode._children:
+        for c in simNode._children:
+            child = simNode._children[c]
+            if isSimObjectVector(child):
+                for obj in child:
+                    try:
+                        c_dom = obj.__getattr__('clk_domain')
+                        v_dom = c_dom.__getattr__('voltage_domain')
+                    except AttributeError:
+                        # Just re-use the domain from above
+                        c_dom = domain
+                        c_dom.__getattr__('voltage_domain')
+                        pass
+
+                    if c_dom == domain or c_dom == None:
+                        dot_create_dvfs_nodes(obj, cluster, domain)
+                    else:
+                        if c_dom not in dvfs_domains:
+                            dvfs_cluster = dot_add_clk_domain(c_dom, v_dom)
+                            dvfs_domains[c_dom] = dvfs_cluster
+                        else:
+                            dvfs_cluster = dvfs_domains[c_dom]
+                        dot_create_dvfs_nodes(obj, dvfs_cluster, c_dom)
+            else:
+                try:
+                    c_dom = child.__getattr__('clk_domain')
+                    v_dom = c_dom.__getattr__('voltage_domain')
+                except AttributeError:
+                    # Just re-use the domain from above
+                    c_dom = domain
+                    c_dom.__getattr__('voltage_domain')
+                    pass
+
+                if c_dom == domain or c_dom == None:
+                    dot_create_dvfs_nodes(child, cluster, domain)
+                else:
+                    if c_dom not in dvfs_domains:
+                        dvfs_cluster = dot_add_clk_domain(c_dom, v_dom)
+                        dvfs_domains[c_dom] = dvfs_cluster
+                    else:
+                        dvfs_cluster = dvfs_domains[c_dom]
+                    dot_create_dvfs_nodes(child, dvfs_cluster, c_dom)
+
+    for key in dvfs_domains:
+        cluster.add_subgraph(dvfs_domains[key])
+
+    callgraph.add_subgraph(cluster)
+
 def do_dot(root, outdir, dotFilename):
     if not pydot:
         return
@@ -275,3 +366,19 @@ def do_dot(root, outdir, dotFilename):
         callgraph.write_pdf(dot_filename + ".pdf")
     except:
         warn("failed to generate dot output from %s", dot_filename)
+
+def do_dvfs_dot(root, outdir, dotFilename):
+    if not pydot:
+        return
+    dvfsgraph = pydot.Dot(graph_type='digraph', ranksep='1.3')
+    dot_create_dvfs_nodes(root, dvfsgraph)
+    dot_create_edges(root, dvfsgraph)
+    dot_filename = os.path.join(outdir, dotFilename)
+    dvfsgraph.write(dot_filename)
+    try:
+        # dot crashes if the figure is extremely wide.
+        # So avoid terminating simulation unnecessarily
+        dvfsgraph.write_svg(dot_filename + ".svg")
+        dvfsgraph.write_pdf(dot_filename + ".pdf")
+    except:
+        warn("failed to generate dot output from %s", dot_filename)