diff options
-rw-r--r-- | src/base/SConscript | 2 | ||||
-rw-r--r-- | src/base/statistics.cc | 70 | ||||
-rw-r--r-- | src/base/statistics.hh | 204 | ||||
-rw-r--r-- | src/base/stats/group.cc | 129 | ||||
-rw-r--r-- | src/base/stats/group.hh | 175 | ||||
-rw-r--r-- | src/base/stats/output.hh | 16 | ||||
-rw-r--r-- | src/base/stats/text.cc | 53 | ||||
-rw-r--r-- | src/base/stats/text.hh | 41 | ||||
-rw-r--r-- | src/python/m5/SimObject.py | 4 | ||||
-rw-r--r-- | src/python/m5/simulate.py | 3 | ||||
-rw-r--r-- | src/python/m5/stats/__init__.py | 73 | ||||
-rw-r--r-- | src/python/pybind11/stats.cc | 16 | ||||
-rw-r--r-- | src/sim/sim_object.cc | 17 | ||||
-rw-r--r-- | src/sim/sim_object.hh | 14 |
14 files changed, 704 insertions, 113 deletions
diff --git a/src/base/SConscript b/src/base/SConscript index 9449a3d4e..96f7b5b50 100644 --- a/src/base/SConscript +++ b/src/base/SConscript @@ -81,6 +81,7 @@ Source('loader/object_file.cc') Source('loader/raw_object.cc') Source('loader/symtab.cc') +Source('stats/group.cc') Source('stats/text.cc') GTest('addr_range.test', 'addr_range.test.cc') @@ -101,6 +102,7 @@ DebugFlag('GDBRecv', "Messages received from the remote application") DebugFlag('GDBSend', "Messages sent to the remote application") DebugFlag('GDBWrite', "Writes to the remote address space") DebugFlag('SQL', "SQL queries sent to the server") +DebugFlag('Stats', "Statistics management") DebugFlag('StatEvents', "Statistics event tracking") CompoundFlag('GDBAll', diff --git a/src/base/statistics.cc b/src/base/statistics.cc index 123351b80..a186f9763 100644 --- a/src/base/statistics.cc +++ b/src/base/statistics.cc @@ -1,4 +1,16 @@ /* + * Copyright (c) 2019 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) 2003-2005 The Regents of The University of Michigan * All rights reserved. * @@ -67,10 +79,18 @@ statsMap() } void -InfoAccess::setInfo(Info *info) +InfoAccess::setInfo(Group *parent, Info *info) { - if (statsMap().find(this) != statsMap().end()) - panic("shouldn't register stat twice!"); + panic_if(statsMap().find(this) != statsMap().end() || + _info != nullptr, + "shouldn't register stat twice!"); + + // New-style stats are reachable through the hierarchy and + // shouldn't be added to the global lists. + if (parent) { + _info = info; + return; + } statsList().push_back(info); @@ -97,17 +117,29 @@ InfoAccess::setInit() Info * InfoAccess::info() { - MapType::const_iterator i = statsMap().find(this); - assert(i != statsMap().end()); - return (*i).second; + if (_info) { + // New-style stats + return _info; + } else { + // Legacy stats + MapType::const_iterator i = statsMap().find(this); + assert(i != statsMap().end()); + return (*i).second; + } } const Info * InfoAccess::info() const { - MapType::const_iterator i = statsMap().find(this); - assert(i != statsMap().end()); - return (*i).second; + if (_info) { + // New-style stats + return _info; + } else { + // Legacy stats + MapType::const_iterator i = statsMap().find(this); + assert(i != statsMap().end()); + return (*i).second; + } } StorageParams::~StorageParams() @@ -224,7 +256,8 @@ Info::baseCheck() const #endif panic("Not all stats have been initialized.\n" "You may need to add <ParentClass>::regStats() to a" - " new SimObject's regStats() function."); + " new SimObject's regStats() function. Name: %s", + name); return false; } @@ -376,19 +409,23 @@ HistStor::add(HistStor *hs) cvec[i] += hs->cvec[i]; } -Formula::Formula() +Formula::Formula(Group *parent, const char *name, const char *desc) + : DataWrapVec<Formula, FormulaInfoProxy>(parent, name, desc) + { } -Formula::Formula(Temp r) + + +Formula::Formula(Group *parent, const char *name, const char *desc, + const Temp &r) + : DataWrapVec<Formula, FormulaInfoProxy>(parent, name, desc) { - root = r.getNodePtr(); - setInit(); - assert(size()); + *this = r; } const Formula & -Formula::operator=(Temp r) +Formula::operator=(const Temp &r) { assert(!root && "Can't change formulas"); root = r.getNodePtr(); @@ -421,6 +458,7 @@ Formula::operator/=(Temp r) return *this; } + void Formula::result(VResult &vec) const { diff --git a/src/base/statistics.hh b/src/base/statistics.hh index 6ddf7ff17..f4fa123e9 100644 --- a/src/base/statistics.hh +++ b/src/base/statistics.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2019 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) 2003-2005 The Regents of The University of Michigan * Copyright (c) 2017, Centre National de la Recherche Scientifique * All rights reserved. @@ -63,6 +75,7 @@ #include <string> #include <vector> +#include "base/stats/group.hh" #include "base/stats/info.hh" #include "base/stats/output.hh" #include "base/stats/types.hh" @@ -172,9 +185,12 @@ struct StorageParams class InfoAccess { + private: + Info *_info; + protected: /** Set up an info class for this statistic */ - void setInfo(Info *info); + void setInfo(Group *parent, Info *info); /** Save Storage class parameters if any */ void setParams(const StorageParams *params); /** Save Storage class parameters if any */ @@ -186,6 +202,9 @@ class InfoAccess const Info *info() const; public: + InfoAccess() + : _info(nullptr) {}; + /** * Reset the stat to the default state. */ @@ -228,21 +247,27 @@ class DataWrap : public InfoAccess return safe_cast<const Info *>(InfoAccess::info()); } - protected: - /** - * Copy constructor, copies are not allowed. - */ - DataWrap(const DataWrap &stat) = delete; + public: + DataWrap() = delete; + DataWrap(const DataWrap &) = delete; + DataWrap &operator=(const DataWrap &) = delete; - /** - * Can't copy stats. - */ - void operator=(const DataWrap &) {} - public: - DataWrap() + DataWrap(Group *parent, const char *name, const char *desc) { - this->setInfo(new Info(self())); + auto info = new Info(self()); + this->setInfo(parent, info); + + if (parent) + parent->addStat(info); + + if (name) { + info->setName(name); + info->flags.set(display); + } + + if (desc) + info->desc = desc; } /** @@ -335,13 +360,9 @@ class DataWrapVec : public DataWrap<Derived, InfoProxyType> public: typedef InfoProxyType<Derived> Info; - DataWrapVec() - {} - - DataWrapVec(const DataWrapVec &ref) - {} - - void operator=(const DataWrapVec &) + DataWrapVec(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : DataWrap<Derived, InfoProxyType>(parent, name, desc) {} // The following functions are specific to vectors. If you use them @@ -420,6 +441,11 @@ class DataWrapVec2d : public DataWrapVec<Derived, InfoProxyType> public: typedef InfoProxyType<Derived> Info; + DataWrapVec2d(Group *parent, const char *name, const char *desc) + : DataWrapVec<Derived, InfoProxyType>(parent, name, desc) + { + } + /** * @warning This makes the assumption that if you're gonna subnames a 2d * vector, you're subnaming across all y @@ -677,7 +703,9 @@ class ScalarBase : public DataWrap<Derived, ScalarInfoProxy> Counter value() const { return data()->value(); } public: - ScalarBase() + ScalarBase(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : DataWrap<Derived, ScalarInfoProxy>(parent, name, desc) { this->doInit(); } @@ -807,7 +835,12 @@ class ValueBase : public DataWrap<Derived, ScalarInfoProxy> ProxyInfo *proxy; public: - ValueBase() : proxy(NULL) { } + ValueBase(Group *parent, const char *name, const char *desc) + : DataWrap<Derived, ScalarInfoProxy>(parent, name, desc), + proxy(NULL) + { + } + ~ValueBase() { if (proxy) delete proxy; } template <class T> @@ -1095,8 +1128,9 @@ class VectorBase : public DataWrapVec<Derived, VectorInfoProxy> } public: - VectorBase() - : storage(nullptr), _size(0) + VectorBase(Group *parent, const char *name, const char *desc) + : DataWrapVec<Derived, VectorInfoProxy>(parent, name, desc), + storage(nullptr), _size(0) {} ~VectorBase() @@ -1235,8 +1269,9 @@ class Vector2dBase : public DataWrapVec2d<Derived, Vector2dInfoProxy> const Storage *data(off_type index) const { return &storage[index]; } public: - Vector2dBase() - : x(0), y(0), _size(0), storage(nullptr) + Vector2dBase(Group *parent, const char *name, const char *desc) + : DataWrapVec2d<Derived, Vector2dInfoProxy>(parent, name, desc), + x(0), y(0), _size(0), storage(nullptr) {} ~Vector2dBase() @@ -1851,7 +1886,10 @@ class DistBase : public DataWrap<Derived, DistInfoProxy> } public: - DistBase() { } + DistBase(Group *parent, const char *name, const char *desc) + : DataWrap<Derived, DistInfoProxy>(parent, name, desc) + { + } /** * Add a value to the distribtion n times. Calls sample on the storage @@ -1945,8 +1983,9 @@ class VectorDistBase : public DataWrapVec<Derived, VectorDistInfoProxy> } public: - VectorDistBase() - : storage(NULL) + VectorDistBase(Group *parent, const char *name, const char *desc) + : DataWrapVec<Derived, VectorDistInfoProxy>(parent, name, desc), + storage(NULL) {} ~VectorDistBase() @@ -2472,6 +2511,12 @@ class Scalar : public ScalarBase<Scalar, StatStor> { public: using ScalarBase<Scalar, StatStor>::operator=; + + Scalar(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : ScalarBase<Scalar, StatStor>(parent, name, desc) + { + } }; /** @@ -2482,10 +2527,22 @@ class Average : public ScalarBase<Average, AvgStor> { public: using ScalarBase<Average, AvgStor>::operator=; + + Average(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : ScalarBase<Average, AvgStor>(parent, name, desc) + { + } }; class Value : public ValueBase<Value> { + public: + Value(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : ValueBase<Value>(parent, name, desc) + { + } }; /** @@ -2494,6 +2551,12 @@ class Value : public ValueBase<Value> */ class Vector : public VectorBase<Vector, StatStor> { + public: + Vector(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : VectorBase<Vector, StatStor>(parent, name, desc) + { + } }; /** @@ -2502,6 +2565,12 @@ class Vector : public VectorBase<Vector, StatStor> */ class AverageVector : public VectorBase<AverageVector, AvgStor> { + public: + AverageVector(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : VectorBase<AverageVector, AvgStor>(parent, name, desc) + { + } }; /** @@ -2510,6 +2579,12 @@ class AverageVector : public VectorBase<AverageVector, AvgStor> */ class Vector2d : public Vector2dBase<Vector2d, StatStor> { + public: + Vector2d(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : Vector2dBase<Vector2d, StatStor>(parent, name, desc) + { + } }; /** @@ -2519,6 +2594,12 @@ class Vector2d : public Vector2dBase<Vector2d, StatStor> class Distribution : public DistBase<Distribution, DistStor> { public: + Distribution(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : DistBase<Distribution, DistStor>(parent, name, desc) + { + } + /** * Set the parameters of this distribution. @sa DistStor::Params * @param min The minimum value of the distribution. @@ -2550,6 +2631,12 @@ class Distribution : public DistBase<Distribution, DistStor> class Histogram : public DistBase<Histogram, HistStor> { public: + Histogram(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : DistBase<Histogram, HistStor>(parent, name, desc) + { + } + /** * Set the parameters of this histogram. @sa HistStor::Params * @param size The number of buckets in the histogram @@ -2576,7 +2663,9 @@ class StandardDeviation : public DistBase<StandardDeviation, SampleStor> /** * Construct and initialize this distribution. */ - StandardDeviation() + StandardDeviation(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : DistBase<StandardDeviation, SampleStor>(parent, name, desc) { SampleStor::Params *params = new SampleStor::Params; this->doInit(); @@ -2594,7 +2683,9 @@ class AverageDeviation : public DistBase<AverageDeviation, AvgSampleStor> /** * Construct and initialize this distribution. */ - AverageDeviation() + AverageDeviation(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : DistBase<AverageDeviation, AvgSampleStor>(parent, name, desc) { AvgSampleStor::Params *params = new AvgSampleStor::Params; this->doInit(); @@ -2609,6 +2700,12 @@ class AverageDeviation : public DistBase<AverageDeviation, AvgSampleStor> class VectorDistribution : public VectorDistBase<VectorDistribution, DistStor> { public: + VectorDistribution(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : VectorDistBase<VectorDistribution, DistStor>(parent, name, desc) + { + } + /** * Initialize storage and parameters for this distribution. * @param size The size of the vector (the number of distributions). @@ -2639,6 +2736,13 @@ class VectorStandardDeviation : public VectorDistBase<VectorStandardDeviation, SampleStor> { public: + VectorStandardDeviation(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : VectorDistBase<VectorStandardDeviation, SampleStor>(parent, name, + desc) + { + } + /** * Initialize storage for this distribution. * @param size The size of the vector. @@ -2662,6 +2766,13 @@ class VectorAverageDeviation : public VectorDistBase<VectorAverageDeviation, AvgSampleStor> { public: + VectorAverageDeviation(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : VectorDistBase<VectorAverageDeviation, AvgSampleStor>(parent, name, + desc) + { + } + /** * Initialize storage for this distribution. * @param size The size of the vector. @@ -2753,7 +2864,10 @@ class SparseHistBase : public DataWrap<Derived, SparseHistInfoProxy> } public: - SparseHistBase() { } + SparseHistBase(Group *parent, const char *name, const char *desc) + : DataWrap<Derived, SparseHistInfoProxy>(parent, name, desc) + { + } /** * Add a value to the distribtion n times. Calls sample on the storage @@ -2870,6 +2984,12 @@ class SparseHistStor class SparseHistogram : public SparseHistBase<SparseHistogram, SparseHistStor> { public: + SparseHistogram(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : SparseHistBase<SparseHistogram, SparseHistStor>(parent, name, desc) + { + } + /** * Set the parameters of this histogram. @sa HistStor::Params * @param size The number of buckets in the histogram @@ -2902,21 +3022,25 @@ class Formula : public DataWrapVec<Formula, FormulaInfoProxy> /** * Create and initialize thie formula, and register it with the database. */ - Formula(); + Formula(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr); - /** - * Create a formula with the given root node, register it with the - * database. - * @param r The root of the expression tree. - */ - Formula(Temp r); + Formula(Group *parent, const char *name, const char *desc, + const Temp &r); /** * Set an unitialized Formula to the given root. * @param r The root of the expression tree. * @return a reference to this formula. */ - const Formula &operator=(Temp r); + const Formula &operator=(const Temp &r); + + template<typename T> + const Formula &operator=(const T &v) + { + *this = Temp(v); + return *this; + } /** * Add the given tree to the existing one. diff --git a/src/base/stats/group.cc b/src/base/stats/group.cc new file mode 100644 index 000000000..2bfc89d00 --- /dev/null +++ b/src/base/stats/group.cc @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2019 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. + * + * 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: Andreas Sandberg + */ + +#include "base/stats/group.hh" + +#include <cassert> + +#include "base/stats/info.hh" +#include "base/trace.hh" +#include "debug/Stats.hh" +#include "sim/sim_object.hh" + +namespace Stats { + +Group::Group(Group *parent, const char *name) + : mergedParent(name ? nullptr : parent) +{ + if (parent && name) { + parent->addStatGroup(name, this); + } else if (parent && !name) { + parent->mergeStatGroup(this); + } +} + +Group::~Group() +{ +} + +void +Group::regStats() +{ + for (auto &g : mergedStatGroups) + g->regStats(); + + for (auto &g : statGroups) { + if (DTRACE(Stats)) { + const SimObject *so = dynamic_cast<const SimObject *>(this); + DPRINTF(Stats, "%s: regStats in group %s\n", + so ? so->name() : "?", + g.first); + } + g.second->regStats(); + } +} + +void +Group::resetStats() +{ + for (auto &s : stats) + s->reset(); + + for (auto &g : mergedStatGroups) + g->resetStats(); + + for (auto &g : statGroups) + g.second->resetStats(); +} + +void +Group::addStat(Stats::Info *info) +{ + stats.push_back(info); + if (mergedParent) + mergedParent->addStat(info); +} + +void +Group::addStatGroup(const char *name, Group *block) +{ + assert(statGroups.find(name) == statGroups.end()); + + statGroups[name] = block; +} + +void +Group::mergeStatGroup(Group *block) +{ + mergedStatGroups.push_back(block); +} + +const std::map<std::string, Group *> & +Group::getStatGroups() const +{ + return statGroups; +} + +const std::vector<Info *> & +Group::getStats() const +{ + return stats; +} + +} // namespace Stats diff --git a/src/base/stats/group.hh b/src/base/stats/group.hh new file mode 100644 index 000000000..f65e46448 --- /dev/null +++ b/src/base/stats/group.hh @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2019 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. + * + * 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: Andreas Sandberg + */ + +#ifndef __BASE_STATS_GROUP_HH__ +#define __BASE_STATS_GROUP_HH__ + +#include <map> +#include <vector> +#include <string> + +/** + * Convenience macro to add a stat to a statistics group. + * + * This macro is used to add a stat to a Stats::Group in the + * initilization list in the Group's constructor. The macro + * automatically assigns the stat to the current group and gives it + * the same name as in the class. For example: + * + * \code + * struct MyStats : public Stats::Group + * { + * Stats::Scalar scalar0; + * Stats::Scalar scalar1; + * + * Group() + * : ADD_STAT(scalar0, "Description of scalar0"), + * scalar1(this, "scalar1", "Description of scalar1") + * { + * } + * }; + * \endcode + */ +#define ADD_STAT(n, ...) n(this, # n, __VA_ARGS__) + +namespace Stats { + +class Info; + +/** + * Statistics container. + * + * A stat group is a hierarchical structure that contain statistics + * and other groups. Groups are used by the stat system to reflect + * gem5's SimObject hierarchy and to expose internal hierarchy within + * an object. They can also be used to conveniently group stats into + * their own class/struct and then be merged into the parent group + * (typically a SimObject). + */ +class Group +{ + public: + Group() = delete; + Group(const Group &) = delete; + Group &operator=(const Group &) = delete; + + /** + * Construct a new statistics group. + * + * The constructor takes two parameters, a parent and a name. The + * parent group should typically be specified. However, there are + * special cases where the parent group may be null. One such + * special case is SimObjects where the Python code performs late + * binding of the group parent. + * + * If the name parameter is NULL, the group gets merged into the + * parent group instead of creating a sub-group. Stats belonging + * to a merged group behave as if they have been added directly to + * the parent group. + * + * @param parent Parent group to associate this object to. + * @param name Name of this group, can be NULL to merge this group + * with the parent group. + */ + Group(Group *parent, const char *name = nullptr); + + virtual ~Group(); + + /** + * Callback to set stat parameters. + * + * This callback is typically used for complex stats (e.g., + * distributions) that need parameters in addition to a name and a + * description. Stat names and descriptions should typically be + * set from the constructor usingo from the constructor using the + * ADD_STAT macro. + */ + virtual void regStats(); + + /** + * Callback to reset stats. + */ + virtual void resetStats(); + + /** + * Register a stat with this group. This method is normally called + * automatically when a stat is instantiated. + */ + void addStat(Stats::Info *info); + + /** + * Get all child groups associated with this object. + */ + const std::map<std::string, Group *> &getStatGroups() const; + + /** + * Get all stats associated with this object. + */ + const std::vector<Info *> &getStats() const; + + /** + * Add a stat block as a child of this block + * + * This method may only be called from a Group constructor or from + * regStats. It's typically only called explicitly from Python + * when setting up the SimObject hierarchy. + */ + void addStatGroup(const char *name, Group *block); + + private: + /** + * Merge the contents (stats & children) of a block to this block. + * + * This is called on a parent group by the child when it is being + * merged into the parent. + */ + void mergeStatGroup(Group *block); + + private: + /** Parent pointer if merged into parent */ + Group *const mergedParent; + + std::map<std::string, Group *> statGroups; + std::vector<Group *> mergedStatGroups; + std::vector<Info *> stats; +}; + +} // namespace Stats + +#endif // __BASE_STATS_GROUP_HH__ diff --git a/src/base/stats/output.hh b/src/base/stats/output.hh index 9cd33a5f9..fe3860dfb 100644 --- a/src/base/stats/output.hh +++ b/src/base/stats/output.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2019 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) 2004-2005 The Regents of The University of Michigan * All rights reserved. * @@ -48,10 +60,14 @@ class SparseHistInfo; // Sparse histogram struct Output { virtual ~Output() {} + virtual void begin() = 0; virtual void end() = 0; virtual bool valid() const = 0; + virtual void beginGroup(const char *name) = 0; + virtual void endGroup() = 0; + virtual void visit(const ScalarInfo &info) = 0; virtual void visit(const VectorInfo &info) = 0; virtual void visit(const DistInfo &info) = 0; diff --git a/src/base/stats/text.cc b/src/base/stats/text.cc index 10e94a770..da68188bd 100644 --- a/src/base/stats/text.cc +++ b/src/base/stats/text.cc @@ -1,4 +1,16 @@ /* + * Copyright (c) 2019 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) 2004-2005 The Regents of The University of Michigan * All rights reserved. * @@ -153,6 +165,32 @@ Text::end() stream->flush(); } +std::string +Text::statName(const std::string &name) const +{ + if (path.empty()) + return name; + else + return csprintf("%s.%s", path.top(), name); +} + +void +Text::beginGroup(const char *name) +{ + if (path.empty()) { + path.push(name); + } else { + path.push(csprintf("%s.%s", path.top(), name)); + } +} + +void +Text::endGroup() +{ + assert(!path.empty()); + path.pop(); +} + bool Text::noOutput(const Info &info) { @@ -368,7 +406,7 @@ DistPrint::DistPrint(const Text *text, const VectorDistInfo &info, int i) void DistPrint::init(const Text *text, const Info &info) { - name = info.name; + name = text->statName(info.name); separatorString = info.separatorString; desc = info.desc; flags = info.flags; @@ -511,7 +549,7 @@ Text::visit(const ScalarInfo &info) ScalarPrint print; print.value = info.result(); - print.name = info.name; + print.name = statName(info.name); print.desc = info.desc; print.flags = info.flags; print.descriptions = descriptions; @@ -531,7 +569,7 @@ Text::visit(const VectorInfo &info) size_type size = info.size(); VectorPrint print; - print.name = info.name; + print.name = statName(info.name); print.separatorString = info.separatorString; print.desc = info.desc; print.flags = info.flags; @@ -606,8 +644,9 @@ Text::visit(const Vector2dInfo &info) total += yvec[j]; } - print.name = info.name + "_" + - (havesub ? info.subnames[i] : std::to_string(i)); + print.name = statName( + info.name + "_" + + (havesub ? info.subnames[i] : std::to_string(i))); print.desc = info.desc; print.vec = yvec; print.total = total; @@ -619,7 +658,7 @@ Text::visit(const Vector2dInfo &info) total_subname.push_back("total"); if (info.flags.isSet(::Stats::total) && (info.x > 1)) { - print.name = info.name; + print.name = statName(info.name); print.subnames = total_subname; print.desc = info.desc; print.vec = VResult(1, info.total()); @@ -687,7 +726,7 @@ SparseHistPrint::SparseHistPrint(const Text *text, const SparseHistInfo &info) void SparseHistPrint::init(const Text *text, const Info &info) { - name = info.name; + name = text->statName(info.name); separatorString = info.separatorString; desc = info.desc; flags = info.flags; diff --git a/src/base/stats/text.hh b/src/base/stats/text.hh index 8bb290a99..c8fba5a19 100644 --- a/src/base/stats/text.hh +++ b/src/base/stats/text.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2019 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) 2004-2005 The Regents of The University of Michigan * All rights reserved. * @@ -32,6 +44,7 @@ #define __BASE_STATS_TEXT_HH__ #include <iosfwd> +#include <stack> #include <string> #include "base/stats/output.hh" @@ -46,6 +59,9 @@ class Text : public Output bool mystream; std::ostream *stream; + // Object/group path + std::stack<std::string> path; + protected: bool noOutput(const Info &info); @@ -60,20 +76,25 @@ class Text : public Output void open(std::ostream &stream); void open(const std::string &file); + std::string statName(const std::string &name) const; // Implement Visit - virtual void visit(const ScalarInfo &info); - virtual void visit(const VectorInfo &info); - virtual void visit(const DistInfo &info); - virtual void visit(const VectorDistInfo &info); - virtual void visit(const Vector2dInfo &info); - virtual void visit(const FormulaInfo &info); - virtual void visit(const SparseHistInfo &info); + void visit(const ScalarInfo &info) override; + void visit(const VectorInfo &info) override; + void visit(const DistInfo &info) override; + void visit(const VectorDistInfo &info) override; + void visit(const Vector2dInfo &info) override; + void visit(const FormulaInfo &info) override; + void visit(const SparseHistInfo &info) override; + + // Group handling + void beginGroup(const char *name) override; + void endGroup() override; // Implement Output - virtual bool valid() const; - virtual void begin(); - virtual void end(); + bool valid() const override; + void begin() override; + void end() override; }; std::string ValueToString(Result value, int precision); diff --git a/src/python/m5/SimObject.py b/src/python/m5/SimObject.py index 317ae6c33..3d2f123b9 100644 --- a/src/python/m5/SimObject.py +++ b/src/python/m5/SimObject.py @@ -1086,7 +1086,7 @@ class SimObject(object): abstract = True cxx_header = "sim/sim_object.hh" - cxx_extra_bases = [ "Drainable", "Serializable" ] + cxx_extra_bases = [ "Drainable", "Serializable", "Stats::Group" ] eventq_index = Param.UInt32(Parent.eventq_index, "Event Queue Index") cxx_exports = [ @@ -1094,8 +1094,6 @@ class SimObject(object): PyBindMethod("initState"), PyBindMethod("memInvalidate"), PyBindMethod("memWriteback"), - PyBindMethod("regStats"), - PyBindMethod("resetStats"), PyBindMethod("regProbePoints"), PyBindMethod("regProbeListeners"), PyBindMethod("startup"), diff --git a/src/python/m5/simulate.py b/src/python/m5/simulate.py index f8da1fb32..1369fb5ed 100644 --- a/src/python/m5/simulate.py +++ b/src/python/m5/simulate.py @@ -124,7 +124,8 @@ def instantiate(ckpt_dir=None): for obj in root.descendants(): obj.init() # Do a third pass to initialize statistics - for obj in root.descendants(): obj.regStats() + stats._bindStatHierarchy(root) + root.regStats() # Do a fourth pass to initialize probe points for obj in root.descendants(): obj.regProbePoints() diff --git a/src/python/m5/stats/__init__.py b/src/python/m5/stats/__init__.py index 019c7ebb8..d9174d387 100644 --- a/src/python/m5/stats/__init__.py +++ b/src/python/m5/stats/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017 ARM Limited +# Copyright (c) 2017, 2019 Arm Limited # All rights reserved. # # The license below extends only to copyright in the software and shall @@ -158,6 +158,29 @@ def initSimStats(): _m5.stats.initSimStats() _m5.stats.registerPythonStatsHandlers() +def _visit_groups(root, visitor): + for group in root.getStatGroups().values(): + visitor(group) + _visit_groups(group, visitor) + +def _visit_stats(root, visitor): + def for_each_stat(g): + for stat in g.getStats(): + visitor(g, stat) + _visit_groups(root, for_each_stat) + +def _bindStatHierarchy(root): + def _bind_obj(name, obj): + if m5.SimObject.isSimObjectVector(obj): + for idx, obj in enumerate(obj): + _bind_obj("{}{}".format(name, idx), obj) + else: + root.addStatGroup(name, obj.getCCObject()) + _bindStatHierarchy(obj) + + for name, obj in root._children.items(): + _bind_obj(name, obj) + names = [] stats_dict = {} stats_list = [] @@ -166,10 +189,7 @@ def enable(): 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: + def check_stat(group, stat): 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) @@ -177,21 +197,57 @@ def enable(): if not (stat.flags & flags.display): stat.name = "__Stat%06d" % stat.id + + # Legacy stat + global stats_list + stats_list = list(_m5.stats.statsList()) + + for stat in stats_list: + check_stat(None, stat) + stats_list.sort(key=lambda s: s.name.split('.')) for stat in stats_list: stats_dict[stat.name] = stat stat.enable() + + # New stats + _visit_stats(Root.getInstance(), check_stat) + _visit_stats(Root.getInstance(), lambda g, s: s.enable()) + _m5.stats.enable(); def prepare(): '''Prepare all stats for data access. This must be done before dumping and serialization.''' + # Legacy stats for stat in stats_list: stat.prepare() + # New stats + _visit_stats(Root.getInstance(), lambda g, s: s.prepare()) + lastDump = 0 + +def _dump_to_visitor(visitor): + # Legacy stats + for stat in stats_list: + stat.visit(visitor) + + # 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() + + dump_group(Root.getInstance()) + + def dump(): '''Dump all statistics data to the registered outputs''' @@ -210,8 +266,7 @@ def dump(): for output in outputList: if output.valid(): output.begin() - for stat in stats_list: - stat.visit(output) + _dump_to_visitor(output) output.end() def reset(): @@ -220,9 +275,9 @@ def reset(): # call reset stats on all SimObjects root = Root.getInstance() if root: - for obj in root.descendants(): obj.resetStats() + root.resetStats() - # call any other registered stats reset callbacks + # call any other registered legacy stats reset callbacks for stat in stats_list: stat.reset() diff --git a/src/python/pybind11/stats.cc b/src/python/pybind11/stats.cc index 39d9ce873..1302c7cc5 100644 --- a/src/python/pybind11/stats.cc +++ b/src/python/pybind11/stats.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited + * Copyright (c) 2017, 2019 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -93,9 +93,12 @@ pybind_init_stats(py::module &m_native) .def("begin", &Stats::Output::begin) .def("end", &Stats::Output::end) .def("valid", &Stats::Output::valid) + .def("beginGroup", &Stats::Output::beginGroup) + .def("endGroup", &Stats::Output::endGroup) ; - py::class_<Stats::Info>(m, "Info") + py::class_<Stats::Info, std::unique_ptr<Stats::Info, py::nodelete>>( + m, "Info") .def_readwrite("name", &Stats::Info::name) .def_readonly("desc", &Stats::Info::desc) .def_readonly("id", &Stats::Info::id) @@ -110,4 +113,13 @@ pybind_init_stats(py::module &m_native) .def("zero", &Stats::Info::zero) .def("visit", &Stats::Info::visit) ; + + py::class_<Stats::Group, std::unique_ptr<Stats::Group, py::nodelete>>( + m, "Group") + .def("regStats", &Stats::Group::regStats) + .def("resetStats", &Stats::Group::resetStats) + .def("getStats", &Stats::Group::getStats) + .def("getStatGroups", &Stats::Group::getStatGroups) + .def("addStatGroup", &Stats::Group::addStatGroup) + ; } diff --git a/src/sim/sim_object.cc b/src/sim/sim_object.cc index 7b794a0b7..eb6e15ae1 100644 --- a/src/sim/sim_object.cc +++ b/src/sim/sim_object.cc @@ -56,7 +56,9 @@ SimObject::SimObjectList SimObject::simObjectList; // SimObject constructor: used to maintain static simObjectList // SimObject::SimObject(const Params *p) - : EventManager(getEventQueue(p->eventq_index)), _params(p) + : EventManager(getEventQueue(p->eventq_index)), + Stats::Group(nullptr), + _params(p) { #ifdef DEBUG doDebugBreak = false; @@ -98,19 +100,6 @@ SimObject::startup() { } -// -// no default statistics, so nothing to do in base implementation -// -void -SimObject::regStats() -{ -} - -void -SimObject::resetStats() -{ -} - /** * No probe points by default, so do nothing in base. */ diff --git a/src/sim/sim_object.hh b/src/sim/sim_object.hh index 5c9bf0019..c938ba5e5 100644 --- a/src/sim/sim_object.hh +++ b/src/sim/sim_object.hh @@ -52,6 +52,7 @@ #include <string> #include <vector> +#include "base/stats/group.hh" #include "params/SimObject.hh" #include "sim/drain.hh" #include "sim/eventq.hh" @@ -92,7 +93,8 @@ class ProbeManager; * SimObject.py). This has the effect of calling the method on the * parent node <i>before</i> its children. */ -class SimObject : public EventManager, public Serializable, public Drainable +class SimObject : public EventManager, public Serializable, public Drainable, + public Stats::Group { private: typedef std::vector<SimObject *> SimObjectList; @@ -146,16 +148,6 @@ class SimObject : public EventManager, public Serializable, public Drainable virtual void initState(); /** - * Register statistics for this object. - */ - virtual void regStats(); - - /** - * Reset statistics associated with this object. - */ - virtual void resetStats(); - - /** * Register probe points for this object. */ virtual void regProbePoints(); |