__init__.py revision 14286
11689SN/A# Copyright (c) 2017-2019 ARM Limited 21689SN/A# All rights reserved. 31689SN/A# 41689SN/A# The license below extends only to copyright in the software and shall 51689SN/A# not be construed as granting a license to any other intellectual 61689SN/A# property including but not limited to intellectual property relating 71689SN/A# to a hardware implementation of the functionality of the software 81689SN/A# licensed hereunder. You may use the software subject to the license 91689SN/A# terms below provided that you ensure that this notice is replicated 101689SN/A# unmodified and in its entirety in all distributions of the software, 111689SN/A# modified or unmodified, in source code or in binary form. 121689SN/A# 131689SN/A# Copyright (c) 2007 The Regents of The University of Michigan 141689SN/A# Copyright (c) 2010 The Hewlett-Packard Development Company 151689SN/A# All rights reserved. 161689SN/A# 171689SN/A# Redistribution and use in source and binary forms, with or without 181689SN/A# modification, are permitted provided that the following conditions are 191689SN/A# met: redistributions of source code must retain the above copyright 201689SN/A# notice, this list of conditions and the following disclaimer; 211689SN/A# redistributions in binary form must reproduce the above copyright 221689SN/A# notice, this list of conditions and the following disclaimer in the 231689SN/A# documentation and/or other materials provided with the distribution; 241689SN/A# neither the name of the copyright holders nor the names of its 251689SN/A# contributors may be used to endorse or promote products derived from 261689SN/A# this software without specific prior written permission. 272665Ssaidi@eecs.umich.edu# 282665Ssaidi@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 292756Sksewell@umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 301689SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 311689SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 322325SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 332325SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 341060SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 351060SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 361060SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 372292SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 382292SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 391681SN/A# 401060SN/A# Authors: Nathan Binkert 412669Sktlim@umich.edu# Andreas Sandberg 421060SN/A 431060SN/Afrom __future__ import print_function 441858SN/Afrom __future__ import absolute_import 452325SN/A 461717SN/Aimport m5 472683Sktlim@umich.edu 481717SN/Aimport _m5.stats 491717SN/Afrom m5.objects import Root 502292SN/Afrom m5.params import isNullPointer 512292SN/Afrom m5.util import attrdict, fatal 521060SN/A 531060SN/A# Stat exports 542316SN/Afrom _m5.stats import schedStatEvent as schedEvent 552316SN/Afrom _m5.stats import periodicStatDump 562680Sktlim@umich.edu 572669Sktlim@umich.eduoutputList = [] 581060SN/A 591060SN/A# Dictionary of stat visitor factories populated by the _url_factory 601060SN/A# visitor. 611060SN/Afactories = { } 621060SN/A 631060SN/A# List of all factories. Contains tuples of (factory, schemes, 641464SN/A# enabled). 651061SN/Aall_factories = [] 662292SN/A 672292SN/Adef _url_factory(schemes, enable=True): 682292SN/A """Wrap a plain Python function with URL parsing helpers 692632Sstever@eecs.umich.edu 702669Sktlim@umich.edu Wrap a plain Python function f(fn, **kwargs) to expect a URL that 711681SN/A has been split using urlparse.urlsplit. First positional argument 721685SN/A is assumed to be a filename, this is created as the concatenation 731681SN/A of the netloc (~hostname) and path in the parsed URL. Keyword 741060SN/A arguments are derived from the query values in the URL. 751060SN/A 762348SN/A Arguments: 772348SN/A schemes: A list of URL schemes to use for this function. 782348SN/A 792348SN/A Keyword arguments: 802348SN/A enable: Enable/disable this factory. Typically used when the 811060SN/A presence of a function depends on some runtime property. 821755SN/A 831060SN/A For example: 841060SN/A wrapped_f(urlparse.urlsplit("text://stats.txt?desc=False")) -> 852669Sktlim@umich.edu f("stats.txt", desc=False) 862669Sktlim@umich.edu 872669Sktlim@umich.edu """ 882325SN/A 891060SN/A from functools import wraps 901060SN/A 911061SN/A def decorator(func): 921060SN/A @wraps(func) 932292SN/A def wrapper(url): 942292SN/A try: 952292SN/A from urllib.parse import parse_qs 962292SN/A except ImportError: 971060SN/A # Python 2 fallback 981060SN/A from urlparse import parse_qs 991060SN/A from ast import literal_eval 1001060SN/A 1011060SN/A qs = parse_qs(url.query, keep_blank_values=True) 1022307SN/A 1032307SN/A # parse_qs returns a list of values for each parameter. Only 1041060SN/A # use the last value since kwargs don't allow multiple values 1051060SN/A # per parameter. Use literal_eval to transform string param 1062292SN/A # values into proper Python types. 1071060SN/A def parse_value(key, values): 1081060SN/A if len(values) == 0 or (len(values) == 1 and not values[0]): 1091060SN/A fatal("%s: '%s' doesn't have a value." % ( 1101060SN/A url.geturl(), key)) 1111060SN/A elif len(values) > 1: 1121060SN/A fatal("%s: '%s' has multiple values." % ( 1132292SN/A url.geturl(), key)) 1141755SN/A else: 1151060SN/A try: 1161060SN/A return key, literal_eval(values[0]) 1172292SN/A except ValueError: 1181755SN/A fatal("%s: %s isn't a valid Python literal" \ 1192292SN/A % (url.geturl(), values[0])) 1202292SN/A 1211060SN/A kwargs = dict([ parse_value(k, v) for k, v in qs.items() ]) 1222292SN/A 1231060SN/A try: 1241060SN/A return func("%s%s" % (url.netloc, url.path), **kwargs) 1251060SN/A except TypeError: 1262292SN/A fatal("Illegal stat visitor parameter specified") 1271060SN/A 1281060SN/A all_factories.append((wrapper, schemes, enable)) 1292292SN/A for scheme in schemes: 1301060SN/A assert scheme not in factories 1311060SN/A factories[scheme] = wrapper if enable else None 1321060SN/A return wrapper 1332307SN/A 1341060SN/A return decorator 1352307SN/A 1361060SN/A@_url_factory([ None, "", "text", "file", ]) 1371060SN/Adef _textFactory(fn, desc=True): 1382292SN/A """Output stats in text format. 1391060SN/A 1401060SN/A Text stat files contain one stat per line with an optional 1411060SN/A description. The description is enabled by default, but can be 1421060SN/A disabled by setting the desc parameter to False. 1431060SN/A 1441060SN/A Parameters: 1451060SN/A * desc (bool): Output stat descriptions (default: True) 1462292SN/A 1472292SN/A Example: 1482292SN/A text://stats.txt?desc=False 1491755SN/A 1501060SN/A """ 1512292SN/A 1521684SN/A return _m5.stats.initText(fn, desc) 1531684SN/A 1542292SN/A@_url_factory([ "h5", ], enable=hasattr(_m5.stats, "initHDF5")) 1552292SN/Adef _hdf5Factory(fn, chunking=10, desc=True, formulas=True): 1562292SN/A """Output stats in HDF5 format. 1571684SN/A 1581684SN/A The HDF5 file format is a structured binary file format. It has 1592292SN/A the multiple benefits over traditional text stat files: 1601060SN/A 1611060SN/A * Efficient storage of time series (multiple stat dumps) 1622292SN/A * Fast lookup of stats 1632292SN/A * Plenty of existing tooling (e.g., Python libraries and graphical 1641060SN/A viewers) 1652292SN/A * File format can be used to store frame buffers together with 1662292SN/A normal stats. 1672292SN/A 1682292SN/A There are some drawbacks compared to the default text format: 1692292SN/A * Large startup cost (single stat dump larger than text equivalent) 1702292SN/A * Stat dumps are slower than text 1712292SN/A 1722292SN/A 1732292SN/A Known limitations: 1742292SN/A * Distributions and histograms currently unsupported. 1752292SN/A * No support for forking. 1762292SN/A 1772292SN/A 1782292SN/A Parameters: 1792292SN/A * chunking (unsigned): Number of time steps to pre-allocate (default: 10) 1802292SN/A * desc (bool): Output stat descriptions (default: True) 1812292SN/A * formulas (bool): Output derived stats (default: True) 1822292SN/A 1832292SN/A Example: 1842292SN/A h5://stats.h5?desc=False;chunking=100;formulas=False 1852292SN/A 1862292SN/A """ 1872292SN/A 1882292SN/A return _m5.stats.initHDF5(fn, chunking, desc, formulas) 1892292SN/A 1902292SN/Adef addStatVisitor(url): 1912292SN/A """Add a stat visitor specified using a URL string 1922292SN/A 1932292SN/A Stat visitors are specified using URLs on the following format: 1942292SN/A format://path[?param=value[;param=value]] 1952292SN/A 1962292SN/A The available formats are listed in the factories list. Factories 1972292SN/A are called with the path as the first positional parameter and the 1982292SN/A parameters are keyword arguments. Parameter values must be valid 1992292SN/A Python literals. 2002292SN/A 2012292SN/A """ 2022292SN/A 2032292SN/A try: 2042292SN/A from urllib.parse import urlsplit 2052292SN/A except ImportError: 2062292SN/A # Python 2 fallback 2072292SN/A from urlparse import urlsplit 2082292SN/A 2092325SN/A parsed = urlsplit(url) 2102292SN/A 2112348SN/A try: 2122307SN/A factory = factories[parsed.scheme] 2132292SN/A except KeyError: 2142348SN/A fatal("Illegal stat file type '%s' specified." % parsed.scheme) 2152316SN/A 2162316SN/A if factory is None: 2172348SN/A fatal("Stat type '%s' disabled at compile time" % parsed.scheme) 2181060SN/A 2191060SN/A outputList.append(factory(parsed)) 2201060SN/A 2212316SN/Adef printStatVisitorTypes(): 2222316SN/A """List available stat visitors and their documentation""" 2231060SN/A 2241858SN/A import inspect 2251060SN/A 2261060SN/A def print_doc(doc): 2271060SN/A for line in doc.splitlines(): 2281060SN/A print("| %s" % line) 2291060SN/A print() 2301060SN/A 2311060SN/A enabled_visitors = [ x for x in all_factories if x[2] ] 2322292SN/A for factory, schemes, _ in enabled_visitors: 2332292SN/A print("%s:" % ", ".join(filter(lambda x: x is not None, schemes))) 2341060SN/A 2351060SN/A # Try to extract the factory doc string 2362292SN/A print_doc(inspect.getdoc(factory)) 2372292SN/A 2381060SN/Adef initSimStats(): 2392292SN/A _m5.stats.initSimStats() 2402292SN/A _m5.stats.registerPythonStatsHandlers() 2412683Sktlim@umich.edu 2421060SN/Adef _visit_groups(visitor, root=None): 2432292SN/A if root is None: 2442292SN/A root = Root.getInstance() 2452683Sktlim@umich.edu for group in root.getStatGroups().values(): 2461060SN/A visitor(group) 2471060SN/A _visit_groups(visitor, root=group) 2481060SN/A 2492348SN/Adef _visit_stats(visitor, root=None): 2501060SN/A def for_each_stat(g): 2511060SN/A for stat in g.getStats(): 2522455SN/A visitor(g, stat) 2531060SN/A _visit_groups(for_each_stat, root=root) 2542455SN/A 2551060SN/Adef _bindStatHierarchy(root): 2562455SN/A def _bind_obj(name, obj): 2572455SN/A if isNullPointer(obj): 2582455SN/A return 2591060SN/A if m5.SimObject.isSimObjectVector(obj): 2601060SN/A for idx, obj in enumerate(obj): 2611060SN/A _bind_obj("{}{}".format(name, idx), obj) 2622669Sktlim@umich.edu else: 2631060SN/A # We need this check because not all obj.getCCObject() is an 2642455SN/A # instance of Stat::Group. For example, sc_core::sc_module, the C++ 2651060SN/A # class of SystemC_ScModule, is not a subclass of Stat::Group. So 2662455SN/A # it will cause a type error if obj is a SystemC_ScModule when 2672455SN/A # calling addStatGroup(). 2682669Sktlim@umich.edu if isinstance(obj.getCCObject(), _m5.stats.Group): 2691060SN/A parent = root 2702292SN/A while parent: 2711060SN/A if hasattr(parent, 'addStatGroup'): 2722292SN/A parent.addStatGroup(name, obj.getCCObject()) 2731060SN/A break 2742292SN/A parent = parent.get_parent(); 2752292SN/A 2762292SN/A _bindStatHierarchy(obj) 2772292SN/A 2782348SN/A for name, obj in root._children.items(): 2792348SN/A _bind_obj(name, obj) 2802348SN/A 2812348SN/Anames = [] 2822348SN/Astats_dict = {} 2832292SN/Astats_list = [] 2842292SN/Adef enable(): 2852292SN/A '''Enable the statistics package. Before the statistics package is 2862292SN/A enabled, all statistics must be created and initialized and once 2872292SN/A the package is enabled, no more statistics can be created.''' 2882292SN/A 2892292SN/A def check_stat(group, stat): 2902292SN/A if not stat.check() or not stat.baseCheck(): 2912348SN/A fatal("statistic '%s' (%d) was not properly initialized " \ 2922292SN/A "by a regStats() function\n", stat.name, stat.id) 2932292SN/A 2942348SN/A if not (stat.flags & flags.display): 2952348SN/A stat.name = "__Stat%06d" % stat.id 2962292SN/A 2972348SN/A 2982292SN/A # Legacy stat 2992292SN/A global stats_list 3002348SN/A stats_list = list(_m5.stats.statsList()) 3012348SN/A 3021060SN/A for stat in stats_list: 3032756Sksewell@umich.edu check_stat(None, stat) 3042756Sksewell@umich.edu 3052756Sksewell@umich.edu stats_list.sort(key=lambda s: s.name.split('.')) 3062756Sksewell@umich.edu for stat in stats_list: 3072756Sksewell@umich.edu stats_dict[stat.name] = stat 3082756Sksewell@umich.edu stat.enable() 3091060SN/A 3101060SN/A 3111060SN/A # New stats 3122292SN/A _visit_stats(check_stat) 3131060SN/A _visit_stats(lambda g, s: s.enable()) 3141060SN/A 3152292SN/A _m5.stats.enable(); 3161060SN/A 3172292SN/Adef prepare(): 3182292SN/A '''Prepare all stats for data access. This must be done before 3191060SN/A dumping and serialization.''' 3202325SN/A 3212325SN/A # Legacy stats 3221060SN/A for stat in stats_list: 3231061SN/A stat.prepare() 3241060SN/A 3251060SN/A # New stats 3262292SN/A _visit_stats(lambda g, s: s.prepare()) 3271060SN/A 3281062SN/Adef _dump_to_visitor(visitor, root=None): 3292292SN/A # Legacy stats 3302292SN/A if root is None: 3312348SN/A for stat in stats_list: 3322292SN/A stat.visit(visitor) 3332292SN/A 3342348SN/A # New stats 3352292SN/A def dump_group(group): 3361062SN/A for stat in group.getStats(): 3372348SN/A stat.visit(visitor) 3381060SN/A 3391060SN/A for n, g in group.getStatGroups().items(): 3401060SN/A visitor.beginGroup(n) 3411060SN/A dump_group(g) 3422292SN/A visitor.endGroup() 3431060SN/A 3442292SN/A if root is not None: 3452292SN/A for p in root.path_list(): 3462292SN/A visitor.beginGroup(p) 3472292SN/A dump_group(root if root is not None else Root.getInstance()) 3482292SN/A if root is not None: 3492325SN/A for p in reversed(root.path_list()): 3502348SN/A visitor.endGroup() 3512348SN/A 3522348SN/AlastDump = 0 3532292SN/A 3542325SN/Adef dump(root=None): 3552292SN/A '''Dump all statistics data to the registered outputs''' 3562325SN/A 3572325SN/A now = m5.curTick() 3582292SN/A global lastDump 3592292SN/A assert lastDump <= now 3602292SN/A new_dump = lastDump != now 3611060SN/A lastDump = now 3621060SN/A 3631060SN/A # Don't allow multiple global stat dumps in the same tick. It's 3641060SN/A # still possible to dump a multiple sub-trees. 3651060SN/A if not new_dump and root is None: 3661060SN/A return 3671060SN/A 3681060SN/A # Only prepare stats the first time we dump them in the same tick. 3691060SN/A if new_dump: 3701060SN/A _m5.stats.processDumpQueue() 3711060SN/A prepare() 3721060SN/A 3731060SN/A for output in outputList: 3741060SN/A if output.valid(): 3751060SN/A output.begin() 3761060SN/A _dump_to_visitor(output, root=root) 3771060SN/A output.end() 3781060SN/A 3791060SN/Adef reset(): 3801060SN/A '''Reset all statistics to the base state''' 3811060SN/A 3821060SN/A # call reset stats on all SimObjects 3831060SN/A root = Root.getInstance() 3842292SN/A if root: 3852292SN/A root.resetStats() 3862292SN/A 3872292SN/A # call any other registered legacy stats reset callbacks 3881060SN/A for stat in stats_list: 3891060SN/A stat.reset() 3901060SN/A 3911060SN/A _m5.stats.processResetQueue() 3922292SN/A 3932292SN/Aflags = attrdict({ 3942292SN/A 'none' : 0x0000, 3952292SN/A 'init' : 0x0001, 3962292SN/A 'display' : 0x0002, 3972292SN/A 'total' : 0x0010, 3981060SN/A 'pdf' : 0x0020, 3992292SN/A 'cdf' : 0x0040, 4002292SN/A 'dist' : 0x0080, 4012292SN/A 'nozero' : 0x0100, 4022292SN/A 'nonan' : 0x0200, 4032292SN/A}) 4042292SN/A