1 # Copyright (c) 2017-2019 ARM Limited
4 # The license below extends only to copyright in the software and shall
5 # not be construed as granting a license to any other intellectual
6 # property including but not limited to intellectual property relating
7 # to a hardware implementation of the functionality of the software
8 # licensed hereunder. You may use the software subject to the license
9 # terms below provided that you ensure that this notice is replicated
10 # unmodified and in its entirety in all distributions of the software,
11 # modified or unmodified, in source code or in binary form.
13 # Copyright (c) 2007 The Regents of The University of Michigan
14 # Copyright (c) 2010 The Hewlett-Packard Development Company
15 # All rights reserved.
17 # Redistribution and use in source and binary forms, with or without
18 # modification, are permitted provided that the following conditions are
19 # met: redistributions of source code must retain the above copyright
20 # notice, this list of conditions and the following disclaimer;
21 # redistributions in binary form must reproduce the above copyright
22 # notice, this list of conditions and the following disclaimer in the
23 # documentation and/or other materials provided with the distribution;
24 # neither the name of the copyright holders nor the names of its
25 # contributors may be used to endorse or promote products derived from
26 # this software without specific prior written permission.
28 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 # Authors: Nathan Binkert
43 from __future__
import print_function
44 from __future__
import absolute_import
49 from m5
.objects
import Root
50 from m5
.util
import attrdict
, fatal
53 from _m5
.stats
import schedStatEvent
as schedEvent
54 from _m5
.stats
import periodicStatDump
58 # Dictionary of stat visitor factories populated by the _url_factory
62 # List of all factories. Contains tuples of (factory, schemes,
66 def _url_factory(schemes
, enable
=True):
67 """Wrap a plain Python function with URL parsing helpers
69 Wrap a plain Python function f(fn, **kwargs) to expect a URL that
70 has been split using urlparse.urlsplit. First positional argument
71 is assumed to be a filename, this is created as the concatenation
72 of the netloc (~hostname) and path in the parsed URL. Keyword
73 arguments are derived from the query values in the URL.
76 schemes: A list of URL schemes to use for this function.
79 enable: Enable/disable this factory. Typically used when the
80 presence of a function depends on some runtime property.
83 wrapped_f(urlparse.urlsplit("text://stats.txt?desc=False")) ->
84 f("stats.txt", desc=False)
88 from functools
import wraps
94 from urllib
.parse
import parse_qs
97 from urlparse
import parse_qs
98 from ast
import literal_eval
100 qs
= parse_qs(url
.query
, keep_blank_values
=True)
102 # parse_qs returns a list of values for each parameter. Only
103 # use the last value since kwargs don't allow multiple values
104 # per parameter. Use literal_eval to transform string param
105 # values into proper Python types.
106 def parse_value(key
, values
):
107 if len(values
) == 0 or (len(values
) == 1 and not values
[0]):
108 fatal("%s: '%s' doesn't have a value." % (
110 elif len(values
) > 1:
111 fatal("%s: '%s' has multiple values." % (
115 return key
, literal_eval(values
[0])
117 fatal("%s: %s isn't a valid Python literal" \
118 % (url
.geturl(), values
[0]))
120 kwargs
= dict([ parse_value(k
, v
) for k
, v
in qs
.items() ])
123 return func("%s%s" % (url
.netloc
, url
.path
), **kwargs
)
125 fatal("Illegal stat visitor parameter specified")
127 all_factories
.append((wrapper
, schemes
, enable
))
128 for scheme
in schemes
:
129 assert scheme
not in factories
130 factories
[scheme
] = wrapper
if enable
else None
135 @_url_factory([ None, "", "text", "file", ])
136 def _textFactory(fn
, desc
=True):
137 """Output stats in text format.
139 Text stat files contain one stat per line with an optional
140 description. The description is enabled by default, but can be
141 disabled by setting the desc parameter to False.
144 * desc (bool): Output stat descriptions (default: True)
147 text://stats.txt?desc=False
151 return _m5
.stats
.initText(fn
, desc
)
153 @_url_factory([ "h5", ], enable
=hasattr(_m5
.stats
, "initHDF5"))
154 def _hdf5Factory(fn
, chunking
=10, desc
=True, formulas
=True):
155 """Output stats in HDF5 format.
157 The HDF5 file format is a structured binary file format. It has
158 the multiple benefits over traditional text stat files:
160 * Efficient storage of time series (multiple stat dumps)
161 * Fast lookup of stats
162 * Plenty of existing tooling (e.g., Python libraries and graphical
164 * File format can be used to store frame buffers together with
167 There are some drawbacks compared to the default text format:
168 * Large startup cost (single stat dump larger than text equivalent)
169 * Stat dumps are slower than text
173 * Distributions and histograms currently unsupported.
174 * No support for forking.
178 * chunking (unsigned): Number of time steps to pre-allocate (default: 10)
179 * desc (bool): Output stat descriptions (default: True)
180 * formulas (bool): Output derived stats (default: True)
183 h5://stats.h5?desc=False;chunking=100;formulas=False
187 return _m5
.stats
.initHDF5(fn
, chunking
, desc
, formulas
)
189 def addStatVisitor(url
):
190 """Add a stat visitor specified using a URL string
192 Stat visitors are specified using URLs on the following format:
193 format://path[?param=value[;param=value]]
195 The available formats are listed in the factories list. Factories
196 are called with the path as the first positional parameter and the
197 parameters are keyword arguments. Parameter values must be valid
203 from urllib
.parse
import urlsplit
206 from urlparse
import urlsplit
208 parsed
= urlsplit(url
)
211 factory
= factories
[parsed
.scheme
]
213 fatal("Illegal stat file type '%s' specified." % parsed
.scheme
)
216 fatal("Stat type '%s' disabled at compile time" % parsed
.scheme
)
218 outputList
.append(factory(parsed
))
220 def printStatVisitorTypes():
221 """List available stat visitors and their documentation"""
226 for line
in doc
.splitlines():
230 enabled_visitors
= [ x
for x
in all_factories
if x
[2] ]
231 for factory
, schemes
, _
in enabled_visitors
:
232 print("%s:" % ", ".join(filter(lambda x
: x
is not None, schemes
)))
234 # Try to extract the factory doc string
235 print_doc(inspect
.getdoc(factory
))
238 _m5
.stats
.initSimStats()
239 _m5
.stats
.registerPythonStatsHandlers()
241 def _visit_groups(visitor
, root
=None):
243 root
= Root
.getInstance()
244 for group
in root
.getStatGroups().values():
246 _visit_groups(visitor
, root
=group
)
248 def _visit_stats(visitor
, root
=None):
249 def for_each_stat(g
):
250 for stat
in g
.getStats():
252 _visit_groups(for_each_stat
, root
=root
)
254 def _bindStatHierarchy(root
):
255 def _bind_obj(name
, obj
):
256 if m5
.SimObject
.isSimObjectVector(obj
):
257 for idx
, obj
in enumerate(obj
):
258 _bind_obj("{}{}".format(name
, idx
), obj
)
260 root
.addStatGroup(name
, obj
.getCCObject())
261 _bindStatHierarchy(obj
)
263 for name
, obj
in root
._children
.items():
270 '''Enable the statistics package. Before the statistics package is
271 enabled, all statistics must be created and initialized and once
272 the package is enabled, no more statistics can be created.'''
274 def check_stat(group
, stat
):
275 if not stat
.check() or not stat
.baseCheck():
276 fatal("statistic '%s' (%d) was not properly initialized " \
277 "by a regStats() function\n", stat
.name
, stat
.id)
279 if not (stat
.flags
& flags
.display
):
280 stat
.name
= "__Stat%06d" % stat
.id
285 stats_list
= list(_m5
.stats
.statsList())
287 for stat
in stats_list
:
288 check_stat(None, stat
)
290 stats_list
.sort(key
=lambda s
: s
.name
.split('.'))
291 for stat
in stats_list
:
292 stats_dict
[stat
.name
] = stat
297 _visit_stats(check_stat
)
298 _visit_stats(lambda g
, s
: s
.enable())
303 '''Prepare all stats for data access. This must be done before
304 dumping and serialization.'''
307 for stat
in stats_list
:
311 _visit_stats(lambda g
, s
: s
.prepare())
313 def _dump_to_visitor(visitor
, root
=None):
316 for stat
in stats_list
:
320 def dump_group(group
):
321 for stat
in group
.getStats():
324 for n
, g
in group
.getStatGroups().items():
325 visitor
.beginGroup(n
)
330 for p
in root
.path_list():
331 visitor
.beginGroup(p
)
332 dump_group(root
if root
is not None else Root
.getInstance())
334 for p
in reversed(root
.path_list()):
340 '''Dump all statistics data to the registered outputs'''
344 assert lastDump
<= now
345 new_dump
= lastDump
!= now
348 # Don't allow multiple global stat dumps in the same tick. It's
349 # still possible to dump a multiple sub-trees.
350 if not new_dump
and root
is None:
353 # Only prepare stats the first time we dump them in the same tick.
355 _m5
.stats
.processDumpQueue()
358 for output
in outputList
:
361 _dump_to_visitor(output
, root
=root
)
365 '''Reset all statistics to the base state'''
367 # call reset stats on all SimObjects
368 root
= Root
.getInstance()
372 # call any other registered legacy stats reset callbacks
373 for stat
in stats_list
:
376 _m5
.stats
.processResetQueue()