stats: add --stats-root option to dump only under some SimObjects
authorCiro Santilli <ciro.santilli@arm.com>
Tue, 17 Mar 2020 16:51:14 +0000 (16:51 +0000)
committerCiro Santilli <ciro.santilli@arm.com>
Wed, 1 Jul 2020 13:22:52 +0000 (13:22 +0000)
This commit makes it possible to make invocations such as:

gem5.opt se.py --stats-root 'system.cpu[:].dtb' --stats-root 'system.membus'

When --stats-root is given, only stats that are under any of the root
SimObjects get dumped. E.g. the above invocation would dump stats such as:

system.cpu0.dtb.walker.pwrStateResidencyTicks::UNDEFINED
system.cpu1.dtb.walker.pwrStateResidencyTicks::UNDEFINED
system.membus.pwrStateResidencyTicks::UNDEFINED
system.membus.trans_dist::ReadReq

but not for example `system.clk_domain.clock`.

If the --stats-root is given, only new stats as defined at:
Idc8ff448b9f70a796427b4a5231e7371485130b4 get dumped, and old ones are
ignored. The commits following that one have done some initial conversion
work, but many stats are still in the old format.

Change-Id: Iadaef26edf9a678b39f774515600884fbaeec497
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/28628
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
RELEASE-NOTES.md
configs/common/Options.py
configs/common/Simulation.py
src/python/m5/SimObject.py
src/python/m5/stats/__init__.py

index 3542de9fe7c2361cd3a8ae89e6b7e4fa5737cd11..adf33b295ab2ca057297ff6ce63abeb63fa97af2 100644 (file)
@@ -1,3 +1,7 @@
+# Version 20.1.0.0
+
+* m5.stats.dump() root argument renamed to roots to reflect the fact that it now takes a list of SimObjects
+
 # Version 20.0.0.2
 
 **[HOTFIX]** A patch was applied to fix the RubyPrefetcher with MESI_Three_Level. Prior to this fix a segfault occurred.
index 3eff04bf9a4cd68d78ab0542457fc900924a9c18..0409fb80987b85a7c87ade6bdd2bb43dbac8192a 100644 (file)
@@ -361,6 +361,14 @@ def addCommonOptions(parser):
     parser.add_option("--arm-iset", default="arm", type="choice",
                       choices=["arm", "thumb", "aarch64"],
                       help="ARM instruction set.")
+    parser.add_option("--stats-root", action="append", default=[], help=
+        "If given, dump only stats of objects under the given SimObject. "
+        "SimObjects are identified with Python notation as in: "
+        "system.cpu[0].dtb. All elements of an array can be selected at "
+        "once with: system.cpu[:].dtb. If given multiple times, dump stats "
+        "that are present under any of the roots. If not given, dump all "
+        "stats. "
+    )
 
 
 def addSEOptions(parser):
index e53c755c6c09e1e5528158eaa29966641cd1a8bc..e7fb8789ed95350145b184165ebef2f3b087ab9a 100644 (file)
@@ -451,6 +451,12 @@ def run(options, root, testsys, cpu_class):
     if options.repeat_switch and options.take_checkpoints:
         fatal("Can't specify both --repeat-switch and --take-checkpoints")
 
+    # Setup global stat filtering.
+    stat_root_simobjs = []
+    for stat_root_str in options.stats_root:
+        stat_root_simobjs.extend(root.get_simobj(stat_root_str))
+    m5.stats.global_dump_roots = stat_root_simobjs
+
     np = options.num_cpus
     switch_cpus = None
 
index a045fb7b0eb6aa0c1ece70eefebad0000186c300..7f12856be9256e68814b964ea969eafb0897465e 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2017-2019 ARM Limited
+# Copyright (c) 2017-2020 ARM Limited
 # All rights reserved.
 #
 # The license below extends only to copyright in the software and shall
@@ -1071,6 +1071,9 @@ class SimObjectCliWrapper(object):
                 out.extend(sim_object[i] for i in _range)
         return SimObjectCliWrapper(out)
 
+    def __iter__(self):
+        return iter(self._sim_objects)
+
 # The SimObject class is the root of the special hierarchy.  Most of
 # the code in this class deals with the configuration hierarchy itself
 # (parent/child node relationships).
@@ -1695,6 +1698,18 @@ class SimObject(object):
         for param in params:
             exec(param, d)
 
+    def get_simobj(self, simobj_path):
+        """
+        Get all sim objects that match a given string.
+
+        The format is the same as that supported by SimObjectCliWrapper.
+
+        :param simobj_path: Current state to be in.
+        :type simobj_path: str
+        """
+        d = self._apply_config_get_dict()
+        return eval(simobj_path, d)
+
 # Function to provide to C++ so it can look up instances based on paths
 def resolveSimObject(name):
     obj = instanceDict[name]
index 1e37a14b3c3cac032d8f6291c80bcc64494999b3..6c4a42cb8b4eb1dbc98ac08fea8bfa878dc79398 100644 (file)
@@ -326,35 +326,45 @@ def prepare():
     # New stats
     _visit_stats(lambda g, s: s.prepare())
 
-def _dump_to_visitor(visitor, root=None):
-    # Legacy stats
-    if root is None:
-        for stat in stats_list:
-            stat.visit(visitor)
-
+def _dump_to_visitor(visitor, roots=None):
     # New stats
     def dump_group(group):
         for stat in group.getStats():
             stat.visit(visitor)
-
         for n, g in group.getStatGroups().items():
             visitor.beginGroup(n)
             dump_group(g)
             visitor.endGroup()
 
-    if root is not None:
-        for p in root.path_list():
-            visitor.beginGroup(p)
-    dump_group(root if root is not None else Root.getInstance())
-    if root is not None:
-        for p in reversed(root.path_list()):
-            visitor.endGroup()
+    if roots:
+        # New stats from selected subroots.
+        for root in roots:
+            for p in root.path_list():
+                visitor.beginGroup(p)
+            dump_group(root)
+            for p in reversed(root.path_list()):
+                visitor.endGroup()
+    else:
+        # Legacy stats
+        for stat in stats_list:
+            stat.visit(visitor)
+
+        # New stats starting from root.
+        dump_group(Root.getInstance())
 
 lastDump = 0
+# List[SimObject].
+global_dump_roots = []
 
-def dump(root=None):
+def dump(roots=None):
     '''Dump all statistics data to the registered outputs'''
 
+    all_roots = []
+    if roots is not None:
+        all_roots.extend(roots)
+    global global_dump_roots
+    all_roots.extend(global_dump_roots)
+
     now = m5.curTick()
     global lastDump
     assert lastDump <= now
@@ -363,7 +373,7 @@ def dump(root=None):
 
     # Don't allow multiple global stat dumps in the same tick. It's
     # still possible to dump a multiple sub-trees.
-    if not new_dump and root is None:
+    if not new_dump and not all_roots:
         return
 
     # Only prepare stats the first time we dump them in the same tick.
@@ -378,7 +388,7 @@ def dump(root=None):
     for output in outputList:
         if output.valid():
             output.begin()
-            _dump_to_visitor(output, root=root)
+            _dump_to_visitor(output, roots=all_roots)
             output.end()
 
 def reset():