-# 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
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# Authors: Nathan Binkert
-# Andreas Sandberg
from __future__ import print_function
from __future__ import absolute_import
import _m5.stats
from m5.objects import Root
+from m5.params import isNullPointer
from m5.util import attrdict, fatal
# Stat exports
return decorator
@_url_factory([ None, "", "text", "file", ])
-def _textFactory(fn, desc=True):
+def _textFactory(fn, desc=True, spaces=True):
"""Output stats in text format.
Text stat files contain one stat per line with an optional
Parameters:
* desc (bool): Output stat descriptions (default: True)
+ * spaces (bool): Output alignment spaces (default: True)
Example:
- text://stats.txt?desc=False
+ text://stats.txt?desc=False;spaces=False
"""
- return _m5.stats.initText(fn, desc)
+ return _m5.stats.initText(fn, desc, spaces)
@_url_factory([ "h5", ], enable=hasattr(_m5.stats, "initHDF5"))
def _hdf5Factory(fn, chunking=10, desc=True, formulas=True):
def _bindStatHierarchy(root):
def _bind_obj(name, obj):
+ if isNullPointer(obj):
+ return
if m5.SimObject.isSimObjectVector(obj):
- for idx, obj in enumerate(obj):
- _bind_obj("{}{}".format(name, idx), obj)
+ if len(obj) == 1:
+ _bind_obj(name, obj[0])
+ else:
+ for idx, obj in enumerate(obj):
+ _bind_obj("{}{}".format(name, idx), obj)
else:
# We need this check because not all obj.getCCObject() is an
# instance of Stat::Group. For example, sc_core::sc_module, the C++
# 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
# 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.
if new_dump:
_m5.stats.processDumpQueue()
+ # Notify new-style stats group that we are about to dump stats.
+ sim_root = Root.getInstance()
+ if sim_root:
+ sim_root.preDumpStats();
prepare()
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():