statistics.cc revision 6000:4f887be9e1b6
1/*
2 * Copyright (c) 2003-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Nathan Binkert
29 */
30
31#include <iomanip>
32#include <fstream>
33#include <list>
34#include <map>
35#include <string>
36
37#include "base/callback.hh"
38#include "base/cprintf.hh"
39#include "base/debug.hh"
40#include "base/hostinfo.hh"
41#include "base/misc.hh"
42#include "base/statistics.hh"
43#include "base/str.hh"
44#include "base/time.hh"
45#include "base/trace.hh"
46
47using namespace std;
48
49namespace Stats {
50
51typedef map<const void *, Info *> MapType;
52
53// We wrap these in a function to make sure they're built in time.
54list<Info *> &
55statsList()
56{
57    static list<Info *> the_list;
58    return the_list;
59}
60
61MapType &
62statsMap()
63{
64    static MapType the_map;
65    return the_map;
66}
67
68void
69InfoAccess::setInfo(Info *info)
70{
71    if (statsMap().find(this) != statsMap().end())
72        panic("shouldn't register stat twice!");
73
74    statsList().push_back(info);
75
76#ifndef NDEBUG
77    pair<MapType::iterator, bool> result =
78#endif
79        statsMap().insert(make_pair(this, info));
80    assert(result.second && "this should never fail");
81    assert(statsMap().find(this) != statsMap().end());
82}
83
84void
85InfoAccess::setParams(const StorageParams *params)
86{
87    info()->storageParams = params;
88}
89
90void
91InfoAccess::setInit()
92{
93    info()->flags |= init;
94}
95
96Info *
97InfoAccess::info()
98{
99    MapType::const_iterator i = statsMap().find(this);
100    assert(i != statsMap().end());
101    return (*i).second;
102}
103
104const Info *
105InfoAccess::info() const
106{
107    MapType::const_iterator i = statsMap().find(this);
108    assert(i != statsMap().end());
109    return (*i).second;
110}
111
112StorageParams::~StorageParams()
113{
114}
115
116int Info::id_count = 0;
117
118int debug_break_id = -1;
119
120Info::Info()
121    : flags(none), precision(-1), prereq(0), storageParams(NULL)
122{
123    id = id_count++;
124    if (debug_break_id >= 0 and debug_break_id == id)
125        debug_break();
126}
127
128Info::~Info()
129{
130}
131
132bool
133Info::less(Info *stat1, Info *stat2)
134{
135    const string &name1 = stat1->name;
136    const string &name2 = stat2->name;
137
138    vector<string> v1;
139    vector<string> v2;
140
141    tokenize(v1, name1, '.');
142    tokenize(v2, name2, '.');
143
144    size_type last = min(v1.size(), v2.size()) - 1;
145    for (off_type i = 0; i < last; ++i)
146        if (v1[i] != v2[i])
147            return v1[i] < v2[i];
148
149    // Special compare for last element.
150    if (v1[last] == v2[last])
151        return v1.size() < v2.size();
152    else
153        return v1[last] < v2[last];
154
155    return false;
156}
157
158bool
159Info::baseCheck() const
160{
161    if (!(flags & Stats::init)) {
162#ifdef DEBUG
163        cprintf("this is stat number %d\n", id);
164#endif
165        panic("Not all stats have been initialized");
166        return false;
167    }
168
169    if ((flags & print) && name.empty()) {
170        panic("all printable stats must be named");
171        return false;
172    }
173
174    return true;
175}
176
177
178Formula::Formula()
179{
180    setInit();
181}
182
183Formula::Formula(Temp r)
184{
185    root = r;
186    assert(size());
187}
188
189const Formula &
190Formula::operator=(Temp r)
191{
192    assert(!root && "Can't change formulas");
193    root = r;
194    assert(size());
195    return *this;
196}
197
198const Formula &
199Formula::operator+=(Temp r)
200{
201    if (root)
202        root = NodePtr(new BinaryNode<std::plus<Result> >(root, r));
203    else
204        root = r;
205    assert(size());
206    return *this;
207}
208
209void
210Formula::result(VResult &vec) const
211{
212    if (root)
213        vec = root->result();
214}
215
216Result
217Formula::total() const
218{
219    return root ? root->total() : 0.0;
220}
221
222size_type
223Formula::size() const
224{
225    if (!root)
226        return 0;
227    else
228        return root->size();
229}
230
231void
232Formula::reset()
233{
234}
235
236bool
237Formula::zero() const
238{
239    VResult vec;
240    result(vec);
241    for (off_t i = 0; i < vec.size(); ++i)
242        if (vec[i] != 0.0)
243            return false;
244    return true;
245}
246
247void
248Formula::update()
249{
250}
251
252string
253Formula::str() const
254{
255    return root ? root->str() : "";
256}
257
258void
259check()
260{
261    typedef list<Info *>::iterator iter_t;
262
263    iter_t i, end = statsList().end();
264    for (i = statsList().begin(); i != end; ++i) {
265        Info *info = *i;
266        assert(info);
267        if (!info->check() || !info->baseCheck())
268            panic("stat check failed for '%s' %d\n", info->name, info->id);
269    }
270
271    off_t j = 0;
272    for (i = statsList().begin(); i != end; ++i) {
273        Info *info = *i;
274        if (!(info->flags & print))
275            info->name = "__Stat" + to_string(j++);
276    }
277
278    statsList().sort(Info::less);
279
280    if (i == end)
281        return;
282
283    iter_t last = i;
284    ++i;
285
286    for (i = statsList().begin(); i != end; ++i) {
287        if ((*i)->name == (*last)->name)
288            panic("same name used twice! name=%s\n", (*i)->name);
289
290        last = i;
291    }
292}
293
294CallbackQueue resetQueue;
295
296void
297reset()
298{
299    list<Info *>::iterator i = statsList().begin();
300    list<Info *>::iterator end = statsList().end();
301    while (i != end) {
302        Info *info = *i;
303        info->reset();
304        ++i;
305    }
306
307    resetQueue.process();
308}
309
310void
311registerResetCallback(Callback *cb)
312{
313    resetQueue.add(cb);
314}
315
316/* namespace Stats */ }
317