__init__.py revision 14209
114209Sandreas.sandberg@arm.com# Copyright (c) 2017-2019 ARM Limited 211878Sandreas.sandberg@arm.com# All rights reserved. 311878Sandreas.sandberg@arm.com# 411878Sandreas.sandberg@arm.com# The license below extends only to copyright in the software and shall 511878Sandreas.sandberg@arm.com# not be construed as granting a license to any other intellectual 611878Sandreas.sandberg@arm.com# property including but not limited to intellectual property relating 711878Sandreas.sandberg@arm.com# to a hardware implementation of the functionality of the software 811878Sandreas.sandberg@arm.com# licensed hereunder. You may use the software subject to the license 911878Sandreas.sandberg@arm.com# terms below provided that you ensure that this notice is replicated 1011878Sandreas.sandberg@arm.com# unmodified and in its entirety in all distributions of the software, 1111878Sandreas.sandberg@arm.com# modified or unmodified, in source code or in binary form. 1211878Sandreas.sandberg@arm.com# 134126SN/A# Copyright (c) 2007 The Regents of The University of Michigan 148295Snate@binkert.org# Copyright (c) 2010 The Hewlett-Packard Development Company 154126SN/A# All rights reserved. 164126SN/A# 174126SN/A# Redistribution and use in source and binary forms, with or without 184126SN/A# modification, are permitted provided that the following conditions are 194126SN/A# met: redistributions of source code must retain the above copyright 204126SN/A# notice, this list of conditions and the following disclaimer; 214126SN/A# redistributions in binary form must reproduce the above copyright 224126SN/A# notice, this list of conditions and the following disclaimer in the 234126SN/A# documentation and/or other materials provided with the distribution; 244126SN/A# neither the name of the copyright holders nor the names of its 254126SN/A# contributors may be used to endorse or promote products derived from 264126SN/A# this software without specific prior written permission. 274126SN/A# 284126SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 294126SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 304126SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 314126SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 324126SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 334126SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 344126SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 354126SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 364126SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 374126SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 384126SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 394126SN/A# 404126SN/A# Authors: Nathan Binkert 4111878Sandreas.sandberg@arm.com# Andreas Sandberg 424126SN/A 438296Snate@binkert.orgimport m5 448296Snate@binkert.org 4511802Sandreas.sandberg@arm.comimport _m5.stats 468295Snate@binkert.orgfrom m5.objects import Root 478296Snate@binkert.orgfrom m5.util import attrdict, fatal 484126SN/A 4911766Sandreas.sandberg@arm.com# Stat exports 5011802Sandreas.sandberg@arm.comfrom _m5.stats import schedStatEvent as schedEvent 5111802Sandreas.sandberg@arm.comfrom _m5.stats import periodicStatDump 5211766Sandreas.sandberg@arm.com 538296Snate@binkert.orgoutputList = [] 5411878Sandreas.sandberg@arm.com 5511878Sandreas.sandberg@arm.comdef _url_factory(func): 5611878Sandreas.sandberg@arm.com """Wrap a plain Python function with URL parsing helpers 5711878Sandreas.sandberg@arm.com 5811878Sandreas.sandberg@arm.com Wrap a plain Python function f(fn, **kwargs) to expect a URL that 5911878Sandreas.sandberg@arm.com has been split using urlparse.urlsplit. First positional argument 6011878Sandreas.sandberg@arm.com is assumed to be a filename, this is created as the concatenation 6111878Sandreas.sandberg@arm.com of the netloc (~hostname) and path in the parsed URL. Keyword 6211878Sandreas.sandberg@arm.com arguments are derived from the query values in the URL. 6311878Sandreas.sandberg@arm.com 6411878Sandreas.sandberg@arm.com For example: 6511878Sandreas.sandberg@arm.com wrapped_f(urlparse.urlsplit("text://stats.txt?desc=False")) -> 6611878Sandreas.sandberg@arm.com f("stats.txt", desc=False) 6711878Sandreas.sandberg@arm.com 6811878Sandreas.sandberg@arm.com """ 6911878Sandreas.sandberg@arm.com 7011878Sandreas.sandberg@arm.com from functools import wraps 7111878Sandreas.sandberg@arm.com 7211878Sandreas.sandberg@arm.com @wraps(func) 7311878Sandreas.sandberg@arm.com def wrapper(url): 7413712Sandreas.sandberg@arm.com try: 7513712Sandreas.sandberg@arm.com from urllib.parse import parse_qs 7613712Sandreas.sandberg@arm.com except ImportError: 7713712Sandreas.sandberg@arm.com # Python 2 fallback 7813712Sandreas.sandberg@arm.com from urlparse import parse_qs 7911878Sandreas.sandberg@arm.com from ast import literal_eval 8011878Sandreas.sandberg@arm.com 8111878Sandreas.sandberg@arm.com qs = parse_qs(url.query, keep_blank_values=True) 8211878Sandreas.sandberg@arm.com 8311878Sandreas.sandberg@arm.com # parse_qs returns a list of values for each parameter. Only 8411878Sandreas.sandberg@arm.com # use the last value since kwargs don't allow multiple values 8511878Sandreas.sandberg@arm.com # per parameter. Use literal_eval to transform string param 8611878Sandreas.sandberg@arm.com # values into proper Python types. 8711878Sandreas.sandberg@arm.com def parse_value(key, values): 8811878Sandreas.sandberg@arm.com if len(values) == 0 or (len(values) == 1 and not values[0]): 8911878Sandreas.sandberg@arm.com fatal("%s: '%s' doesn't have a value." % (url.geturl(), key)) 9011878Sandreas.sandberg@arm.com elif len(values) > 1: 9111878Sandreas.sandberg@arm.com fatal("%s: '%s' has multiple values." % (url.geturl(), key)) 9211878Sandreas.sandberg@arm.com else: 9311878Sandreas.sandberg@arm.com try: 9411878Sandreas.sandberg@arm.com return key, literal_eval(values[0]) 9511878Sandreas.sandberg@arm.com except ValueError: 9611878Sandreas.sandberg@arm.com fatal("%s: %s isn't a valid Python literal" \ 9711878Sandreas.sandberg@arm.com % (url.geturl(), values[0])) 9811878Sandreas.sandberg@arm.com 9911878Sandreas.sandberg@arm.com kwargs = dict([ parse_value(k, v) for k, v in qs.items() ]) 10011878Sandreas.sandberg@arm.com 10111878Sandreas.sandberg@arm.com try: 10211878Sandreas.sandberg@arm.com return func("%s%s" % (url.netloc, url.path), **kwargs) 10311878Sandreas.sandberg@arm.com except TypeError: 10411878Sandreas.sandberg@arm.com fatal("Illegal stat visitor parameter specified") 10511878Sandreas.sandberg@arm.com 10611878Sandreas.sandberg@arm.com return wrapper 10711878Sandreas.sandberg@arm.com 10811878Sandreas.sandberg@arm.com@_url_factory 10911878Sandreas.sandberg@arm.comdef _textFactory(fn, desc=True): 11011878Sandreas.sandberg@arm.com """Output stats in text format. 11111878Sandreas.sandberg@arm.com 11211878Sandreas.sandberg@arm.com Text stat files contain one stat per line with an optional 11311878Sandreas.sandberg@arm.com description. The description is enabled by default, but can be 11411878Sandreas.sandberg@arm.com disabled by setting the desc parameter to False. 11511878Sandreas.sandberg@arm.com 11611878Sandreas.sandberg@arm.com Example: text://stats.txt?desc=False 11711878Sandreas.sandberg@arm.com 11811878Sandreas.sandberg@arm.com """ 11911878Sandreas.sandberg@arm.com 12011878Sandreas.sandberg@arm.com return _m5.stats.initText(fn, desc) 12111878Sandreas.sandberg@arm.com 12214209Sandreas.sandberg@arm.com@_url_factory 12314209Sandreas.sandberg@arm.comdef _hdf5Factory(fn, chunking=10, desc=True, formulas=True): 12414209Sandreas.sandberg@arm.com """Output stats in HDF5 format. 12514209Sandreas.sandberg@arm.com 12614209Sandreas.sandberg@arm.com The HDF5 file format is a structured binary file format. It has 12714209Sandreas.sandberg@arm.com the multiple benefits over traditional text stat files: 12814209Sandreas.sandberg@arm.com 12914209Sandreas.sandberg@arm.com * Efficient storage of time series (multiple stat dumps) 13014209Sandreas.sandberg@arm.com * Fast lookup of stats 13114209Sandreas.sandberg@arm.com * Plenty of existing tooling (e.g., Python libraries and graphical 13214209Sandreas.sandberg@arm.com viewers) 13314209Sandreas.sandberg@arm.com * File format can be used to store frame buffers together with 13414209Sandreas.sandberg@arm.com normal stats. 13514209Sandreas.sandberg@arm.com 13614209Sandreas.sandberg@arm.com There are some drawbacks compared to the default text format: 13714209Sandreas.sandberg@arm.com * Large startup cost (single stat dump larger than text equivalent) 13814209Sandreas.sandberg@arm.com * Stat dumps are slower than text 13914209Sandreas.sandberg@arm.com 14014209Sandreas.sandberg@arm.com 14114209Sandreas.sandberg@arm.com Known limitations: 14214209Sandreas.sandberg@arm.com * Distributions and histograms currently unsupported. 14314209Sandreas.sandberg@arm.com * No support for forking. 14414209Sandreas.sandberg@arm.com 14514209Sandreas.sandberg@arm.com 14614209Sandreas.sandberg@arm.com Parameters: 14714209Sandreas.sandberg@arm.com * chunking (unsigned): Number of time steps to pre-allocate (default: 10) 14814209Sandreas.sandberg@arm.com * desc (bool): Output stat descriptions (default: True) 14914209Sandreas.sandberg@arm.com * formulas (bool): Output derived stats (default: True) 15014209Sandreas.sandberg@arm.com 15114209Sandreas.sandberg@arm.com Example: 15214209Sandreas.sandberg@arm.com h5://stats.h5?desc=False;chunking=100;formulas=False 15314209Sandreas.sandberg@arm.com 15414209Sandreas.sandberg@arm.com """ 15514209Sandreas.sandberg@arm.com 15614209Sandreas.sandberg@arm.com if hasattr(_m5.stats, "initHDF5"): 15714209Sandreas.sandberg@arm.com return _m5.stats.initHDF5(fn, chunking, desc, formulas) 15814209Sandreas.sandberg@arm.com else: 15914209Sandreas.sandberg@arm.com fatal("HDF5 support not enabled at compile time") 16014209Sandreas.sandberg@arm.com 16111878Sandreas.sandberg@arm.comfactories = { 16211878Sandreas.sandberg@arm.com # Default to the text factory if we're given a naked path 16311878Sandreas.sandberg@arm.com "" : _textFactory, 16411878Sandreas.sandberg@arm.com "file" : _textFactory, 16511878Sandreas.sandberg@arm.com "text" : _textFactory, 16614209Sandreas.sandberg@arm.com "h5" : _hdf5Factory, 16711878Sandreas.sandberg@arm.com} 16811878Sandreas.sandberg@arm.com 16914209Sandreas.sandberg@arm.com 17011878Sandreas.sandberg@arm.comdef addStatVisitor(url): 17111878Sandreas.sandberg@arm.com """Add a stat visitor specified using a URL string 17211878Sandreas.sandberg@arm.com 17311878Sandreas.sandberg@arm.com Stat visitors are specified using URLs on the following format: 17411878Sandreas.sandberg@arm.com format://path[?param=value[;param=value]] 17511878Sandreas.sandberg@arm.com 17611878Sandreas.sandberg@arm.com The available formats are listed in the factories list. Factories 17711878Sandreas.sandberg@arm.com are called with the path as the first positional parameter and the 17811878Sandreas.sandberg@arm.com parameters are keyword arguments. Parameter values must be valid 17911878Sandreas.sandberg@arm.com Python literals. 18011878Sandreas.sandberg@arm.com 18111878Sandreas.sandberg@arm.com """ 18211878Sandreas.sandberg@arm.com 18313712Sandreas.sandberg@arm.com try: 18413712Sandreas.sandberg@arm.com from urllib.parse import urlsplit 18513712Sandreas.sandberg@arm.com except ImportError: 18613712Sandreas.sandberg@arm.com # Python 2 fallback 18713712Sandreas.sandberg@arm.com from urlparse import urlsplit 18811878Sandreas.sandberg@arm.com 18911878Sandreas.sandberg@arm.com parsed = urlsplit(url) 19011878Sandreas.sandberg@arm.com 19111878Sandreas.sandberg@arm.com try: 19211878Sandreas.sandberg@arm.com factory = factories[parsed.scheme] 19311878Sandreas.sandberg@arm.com except KeyError: 19411878Sandreas.sandberg@arm.com fatal("Illegal stat file type specified.") 19511878Sandreas.sandberg@arm.com 19611878Sandreas.sandberg@arm.com outputList.append(factory(parsed)) 1974126SN/A 1986001SN/Adef initSimStats(): 19911802Sandreas.sandberg@arm.com _m5.stats.initSimStats() 20011802Sandreas.sandberg@arm.com _m5.stats.registerPythonStatsHandlers() 2016001SN/A 20214206Sandreas.sandberg@arm.comdef _visit_groups(visitor, root=None): 20314206Sandreas.sandberg@arm.com if root is None: 20414206Sandreas.sandberg@arm.com root = Root.getInstance() 20514205Sandreas.sandberg@arm.com for group in root.getStatGroups().values(): 20614205Sandreas.sandberg@arm.com visitor(group) 20714206Sandreas.sandberg@arm.com _visit_groups(visitor, root=group) 20814205Sandreas.sandberg@arm.com 20914206Sandreas.sandberg@arm.comdef _visit_stats(visitor, root=None): 21014205Sandreas.sandberg@arm.com def for_each_stat(g): 21114205Sandreas.sandberg@arm.com for stat in g.getStats(): 21214205Sandreas.sandberg@arm.com visitor(g, stat) 21314206Sandreas.sandberg@arm.com _visit_groups(for_each_stat, root=root) 21414205Sandreas.sandberg@arm.com 21514205Sandreas.sandberg@arm.comdef _bindStatHierarchy(root): 21614205Sandreas.sandberg@arm.com def _bind_obj(name, obj): 21714205Sandreas.sandberg@arm.com if m5.SimObject.isSimObjectVector(obj): 21814205Sandreas.sandberg@arm.com for idx, obj in enumerate(obj): 21914205Sandreas.sandberg@arm.com _bind_obj("{}{}".format(name, idx), obj) 22014205Sandreas.sandberg@arm.com else: 22114205Sandreas.sandberg@arm.com root.addStatGroup(name, obj.getCCObject()) 22214205Sandreas.sandberg@arm.com _bindStatHierarchy(obj) 22314205Sandreas.sandberg@arm.com 22414205Sandreas.sandberg@arm.com for name, obj in root._children.items(): 22514205Sandreas.sandberg@arm.com _bind_obj(name, obj) 22614205Sandreas.sandberg@arm.com 2278295Snate@binkert.orgnames = [] 2288295Snate@binkert.orgstats_dict = {} 2298295Snate@binkert.orgstats_list = [] 2306001SN/Adef enable(): 2318295Snate@binkert.org '''Enable the statistics package. Before the statistics package is 2328295Snate@binkert.org enabled, all statistics must be created and initialized and once 2338295Snate@binkert.org the package is enabled, no more statistics can be created.''' 2348295Snate@binkert.org 23514205Sandreas.sandberg@arm.com def check_stat(group, stat): 2368296Snate@binkert.org if not stat.check() or not stat.baseCheck(): 23710169SCurtis.Dunham@arm.com fatal("statistic '%s' (%d) was not properly initialized " \ 23810169SCurtis.Dunham@arm.com "by a regStats() function\n", stat.name, stat.id) 2398296Snate@binkert.org 2408296Snate@binkert.org if not (stat.flags & flags.display): 2418296Snate@binkert.org stat.name = "__Stat%06d" % stat.id 2428296Snate@binkert.org 24314205Sandreas.sandberg@arm.com 24414205Sandreas.sandberg@arm.com # Legacy stat 24514205Sandreas.sandberg@arm.com global stats_list 24614205Sandreas.sandberg@arm.com stats_list = list(_m5.stats.statsList()) 24714205Sandreas.sandberg@arm.com 24814205Sandreas.sandberg@arm.com for stat in stats_list: 24914205Sandreas.sandberg@arm.com check_stat(None, stat) 25014205Sandreas.sandberg@arm.com 25113681Sandreas.sandberg@arm.com stats_list.sort(key=lambda s: s.name.split('.')) 2528295Snate@binkert.org for stat in stats_list: 2538295Snate@binkert.org stats_dict[stat.name] = stat 2548296Snate@binkert.org stat.enable() 2558295Snate@binkert.org 25614205Sandreas.sandberg@arm.com 25714205Sandreas.sandberg@arm.com # New stats 25814206Sandreas.sandberg@arm.com _visit_stats(check_stat) 25914206Sandreas.sandberg@arm.com _visit_stats(lambda g, s: s.enable()) 26014205Sandreas.sandberg@arm.com 26111802Sandreas.sandberg@arm.com _m5.stats.enable(); 2628986SAli.Saidi@ARM.com 2638296Snate@binkert.orgdef prepare(): 2648296Snate@binkert.org '''Prepare all stats for data access. This must be done before 2658296Snate@binkert.org dumping and serialization.''' 2666001SN/A 26714205Sandreas.sandberg@arm.com # Legacy stats 2688296Snate@binkert.org for stat in stats_list: 2698296Snate@binkert.org stat.prepare() 2708296Snate@binkert.org 27114205Sandreas.sandberg@arm.com # New stats 27214206Sandreas.sandberg@arm.com _visit_stats(lambda g, s: s.prepare()) 27314205Sandreas.sandberg@arm.com 27414206Sandreas.sandberg@arm.comdef _dump_to_visitor(visitor, root=None): 27514205Sandreas.sandberg@arm.com # Legacy stats 27614206Sandreas.sandberg@arm.com if root is None: 27714206Sandreas.sandberg@arm.com for stat in stats_list: 27814206Sandreas.sandberg@arm.com stat.visit(visitor) 27914205Sandreas.sandberg@arm.com 28014205Sandreas.sandberg@arm.com # New stats 28114205Sandreas.sandberg@arm.com def dump_group(group): 28214205Sandreas.sandberg@arm.com for stat in group.getStats(): 28314205Sandreas.sandberg@arm.com stat.visit(visitor) 28414205Sandreas.sandberg@arm.com 28514205Sandreas.sandberg@arm.com for n, g in group.getStatGroups().items(): 28614205Sandreas.sandberg@arm.com visitor.beginGroup(n) 28714205Sandreas.sandberg@arm.com dump_group(g) 28814205Sandreas.sandberg@arm.com visitor.endGroup() 28914205Sandreas.sandberg@arm.com 29014206Sandreas.sandberg@arm.com if root is not None: 29114206Sandreas.sandberg@arm.com for p in root.path_list(): 29214206Sandreas.sandberg@arm.com visitor.beginGroup(p) 29314206Sandreas.sandberg@arm.com dump_group(root if root is not None else Root.getInstance()) 29414206Sandreas.sandberg@arm.com if root is not None: 29514206Sandreas.sandberg@arm.com for p in reversed(root.path_list()): 29614206Sandreas.sandberg@arm.com visitor.endGroup() 29714205Sandreas.sandberg@arm.com 29814206Sandreas.sandberg@arm.comlastDump = 0 29914205Sandreas.sandberg@arm.com 30014206Sandreas.sandberg@arm.comdef dump(root=None): 3018296Snate@binkert.org '''Dump all statistics data to the registered outputs''' 3026001SN/A 30314206Sandreas.sandberg@arm.com now = m5.curTick() 30414206Sandreas.sandberg@arm.com global lastDump 30514206Sandreas.sandberg@arm.com assert lastDump <= now 30614206Sandreas.sandberg@arm.com new_dump = lastDump != now 30714206Sandreas.sandberg@arm.com lastDump = now 3088296Snate@binkert.org 30914206Sandreas.sandberg@arm.com # Don't allow multiple global stat dumps in the same tick. It's 31014206Sandreas.sandberg@arm.com # still possible to dump a multiple sub-trees. 31114206Sandreas.sandberg@arm.com if not new_dump and root is None: 3128296Snate@binkert.org return 3138296Snate@binkert.org 31414206Sandreas.sandberg@arm.com # Only prepare stats the first time we dump them in the same tick. 31514206Sandreas.sandberg@arm.com if new_dump: 31614206Sandreas.sandberg@arm.com _m5.stats.processDumpQueue() 31714206Sandreas.sandberg@arm.com prepare() 3188296Snate@binkert.org 3198296Snate@binkert.org for output in outputList: 3208296Snate@binkert.org if output.valid(): 3218296Snate@binkert.org output.begin() 32214206Sandreas.sandberg@arm.com _dump_to_visitor(output, root=root) 3238296Snate@binkert.org output.end() 3246001SN/A 3256001SN/Adef reset(): 3268296Snate@binkert.org '''Reset all statistics to the base state''' 3278296Snate@binkert.org 3287527SN/A # call reset stats on all SimObjects 3297527SN/A root = Root.getInstance() 3307802SN/A if root: 33114205Sandreas.sandberg@arm.com root.resetStats() 3327802SN/A 33314205Sandreas.sandberg@arm.com # call any other registered legacy stats reset callbacks 3348296Snate@binkert.org for stat in stats_list: 3358296Snate@binkert.org stat.reset() 3368296Snate@binkert.org 33711802Sandreas.sandberg@arm.com _m5.stats.processResetQueue() 3388295Snate@binkert.org 3398295Snate@binkert.orgflags = attrdict({ 3408295Snate@binkert.org 'none' : 0x0000, 3418295Snate@binkert.org 'init' : 0x0001, 3428295Snate@binkert.org 'display' : 0x0002, 3438295Snate@binkert.org 'total' : 0x0010, 3448295Snate@binkert.org 'pdf' : 0x0020, 3458295Snate@binkert.org 'cdf' : 0x0040, 3468295Snate@binkert.org 'dist' : 0x0080, 3478295Snate@binkert.org 'nozero' : 0x0100, 3488295Snate@binkert.org 'nonan' : 0x0200, 3498295Snate@binkert.org}) 350