| # Copyright (c) 2017 ARM Limited | |
| # All rights reserved. | |
| # | |
| # The license below extends only to copyright in the software and shall | |
| # not be construed as granting a license to any other intellectual | |
| # property including but not limited to intellectual property relating | |
| # to a hardware implementation of the functionality of the software | |
| # licensed hereunder. You may use the software subject to the license | |
| # terms below provided that you ensure that this notice is replicated | |
| # unmodified and in its entirety in all distributions of the software, | |
| # modified or unmodified, in source code or in binary form. | |
| # | |
| # Copyright (c) 2007 The Regents of The University of Michigan | |
| # Copyright (c) 2010 The Hewlett-Packard Development Company | |
| # All rights reserved. | |
| # | |
| # Redistribution and use in source and binary forms, with or without | |
| # modification, are permitted provided that the following conditions are | |
| # met: redistributions of source code must retain the above copyright | |
| # notice, this list of conditions and the following disclaimer; | |
| # redistributions in binary form must reproduce the above copyright | |
| # notice, this list of conditions and the following disclaimer in the | |
| # documentation and/or other materials provided with the distribution; | |
| # neither the name of the copyright holders nor the names of its | |
| # contributors may be used to endorse or promote products derived from | |
| # this software without specific prior written permission. | |
| # | |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| # 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 | |
| import m5 | |
| import _m5.stats | |
| from m5.objects import Root | |
| from m5.util import attrdict, fatal | |
| # Stat exports | |
| from _m5.stats import schedStatEvent as schedEvent | |
| from _m5.stats import periodicStatDump | |
| outputList = [] | |
| def _url_factory(func): | |
| """Wrap a plain Python function with URL parsing helpers | |
| Wrap a plain Python function f(fn, **kwargs) to expect a URL that | |
| has been split using urlparse.urlsplit. First positional argument | |
| is assumed to be a filename, this is created as the concatenation | |
| of the netloc (~hostname) and path in the parsed URL. Keyword | |
| arguments are derived from the query values in the URL. | |
| For example: | |
| wrapped_f(urlparse.urlsplit("text://stats.txt?desc=False")) -> | |
| f("stats.txt", desc=False) | |
| """ | |
| from functools import wraps | |
| @wraps(func) | |
| def wrapper(url): | |
| from urlparse import parse_qs | |
| from ast import literal_eval | |
| qs = parse_qs(url.query, keep_blank_values=True) | |
| # parse_qs returns a list of values for each parameter. Only | |
| # use the last value since kwargs don't allow multiple values | |
| # per parameter. Use literal_eval to transform string param | |
| # values into proper Python types. | |
| def parse_value(key, values): | |
| if len(values) == 0 or (len(values) == 1 and not values[0]): | |
| fatal("%s: '%s' doesn't have a value." % (url.geturl(), key)) | |
| elif len(values) > 1: | |
| fatal("%s: '%s' has multiple values." % (url.geturl(), key)) | |
| else: | |
| try: | |
| return key, literal_eval(values[0]) | |
| except ValueError: | |
| fatal("%s: %s isn't a valid Python literal" \ | |
| % (url.geturl(), values[0])) | |
| kwargs = dict([ parse_value(k, v) for k, v in qs.items() ]) | |
| try: | |
| return func("%s%s" % (url.netloc, url.path), **kwargs) | |
| except TypeError: | |
| fatal("Illegal stat visitor parameter specified") | |
| return wrapper | |
| @_url_factory | |
| def _textFactory(fn, desc=True): | |
| """Output stats in text format. | |
| Text stat files contain one stat per line with an optional | |
| description. The description is enabled by default, but can be | |
| disabled by setting the desc parameter to False. | |
| Example: text://stats.txt?desc=False | |
| """ | |
| return _m5.stats.initText(fn, desc) | |
| factories = { | |
| # Default to the text factory if we're given a naked path | |
| "" : _textFactory, | |
| "file" : _textFactory, | |
| "text" : _textFactory, | |
| } | |
| def addStatVisitor(url): | |
| """Add a stat visitor specified using a URL string | |
| Stat visitors are specified using URLs on the following format: | |
| format://path[?param=value[;param=value]] | |
| The available formats are listed in the factories list. Factories | |
| are called with the path as the first positional parameter and the | |
| parameters are keyword arguments. Parameter values must be valid | |
| Python literals. | |
| """ | |
| from urlparse import urlsplit | |
| parsed = urlsplit(url) | |
| try: | |
| factory = factories[parsed.scheme] | |
| except KeyError: | |
| fatal("Illegal stat file type specified.") | |
| outputList.append(factory(parsed)) | |
| def initSimStats(): | |
| _m5.stats.initSimStats() | |
| _m5.stats.registerPythonStatsHandlers() | |
| names = [] | |
| stats_dict = {} | |
| stats_list = [] | |
| def enable(): | |
| '''Enable the statistics package. Before the statistics package is | |
| enabled, all statistics must be created and initialized and once | |
| the package is enabled, no more statistics can be created.''' | |
| global stats_list | |
| stats_list = list(_m5.stats.statsList()) | |
| for stat in stats_list: | |
| if not stat.check() or not stat.baseCheck(): | |
| fatal("statistic '%s' (%d) was not properly initialized " \ | |
| "by a regStats() function\n", stat.name, stat.id) | |
| if not (stat.flags & flags.display): | |
| stat.name = "__Stat%06d" % stat.id | |
| def less(stat1, stat2): | |
| v1 = stat1.name.split('.') | |
| v2 = stat2.name.split('.') | |
| return v1 < v2 | |
| stats_list.sort(less) | |
| for stat in stats_list: | |
| stats_dict[stat.name] = stat | |
| stat.enable() | |
| _m5.stats.enable(); | |
| def prepare(): | |
| '''Prepare all stats for data access. This must be done before | |
| dumping and serialization.''' | |
| for stat in stats_list: | |
| stat.prepare() | |
| lastDump = 0 | |
| def dump(): | |
| '''Dump all statistics data to the registered outputs''' | |
| curTick = m5.curTick() | |
| global lastDump | |
| assert lastDump <= curTick | |
| if lastDump == curTick: | |
| return | |
| lastDump = curTick | |
| _m5.stats.processDumpQueue() | |
| prepare() | |
| for output in outputList: | |
| if output.valid(): | |
| output.begin() | |
| for stat in stats_list: | |
| stat.visit(output) | |
| output.end() | |
| def reset(): | |
| '''Reset all statistics to the base state''' | |
| # call reset stats on all SimObjects | |
| root = Root.getInstance() | |
| if root: | |
| for obj in root.descendants(): obj.resetStats() | |
| # call any other registered stats reset callbacks | |
| for stat in stats_list: | |
| stat.reset() | |
| _m5.stats.processResetQueue() | |
| flags = attrdict({ | |
| 'none' : 0x0000, | |
| 'init' : 0x0001, | |
| 'display' : 0x0002, | |
| 'total' : 0x0010, | |
| 'pdf' : 0x0020, | |
| 'cdf' : 0x0040, | |
| 'dist' : 0x0080, | |
| 'nozero' : 0x0100, | |
| 'nonan' : 0x0200, | |
| }) |