statistics.cc revision 8986
112855Sgabeblack@google.com/*
212855Sgabeblack@google.com * Copyright (c) 2003-2005 The Regents of The University of Michigan
312855Sgabeblack@google.com * All rights reserved.
412855Sgabeblack@google.com *
512855Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
612855Sgabeblack@google.com * modification, are permitted provided that the following conditions are
712855Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
812855Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
912855Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
1012855Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
1112855Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
1212855Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
1312855Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
1412855Sgabeblack@google.com * this software without specific prior written permission.
1512855Sgabeblack@google.com *
1612855Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1712855Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1812855Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1912855Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2012855Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2112855Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2212855Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2312855Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2412855Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2512855Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2612855Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2712855Sgabeblack@google.com *
2812855Sgabeblack@google.com * Authors: Nathan Binkert
2912855Sgabeblack@google.com */
3012855Sgabeblack@google.com
3112855Sgabeblack@google.com#include <fstream>
3212855Sgabeblack@google.com#include <iomanip>
3312855Sgabeblack@google.com#include <list>
3412855Sgabeblack@google.com#include <map>
3512855Sgabeblack@google.com#include <string>
3612855Sgabeblack@google.com
3712855Sgabeblack@google.com#include "base/callback.hh"
3812855Sgabeblack@google.com#include "base/cprintf.hh"
3912855Sgabeblack@google.com#include "base/debug.hh"
4012855Sgabeblack@google.com#include "base/hostinfo.hh"
4112855Sgabeblack@google.com#include "base/misc.hh"
4212855Sgabeblack@google.com#include "base/statistics.hh"
4312855Sgabeblack@google.com#include "base/str.hh"
4412855Sgabeblack@google.com#include "base/time.hh"
4512855Sgabeblack@google.com#include "base/trace.hh"
4612855Sgabeblack@google.com
4712855Sgabeblack@google.comusing namespace std;
4812855Sgabeblack@google.com
4912855Sgabeblack@google.comnamespace Stats {
5012855Sgabeblack@google.com
5112855Sgabeblack@google.comstd::string Info::separatorString = "::";
5212855Sgabeblack@google.comtypedef map<const void *, Info *> MapType;
5312855Sgabeblack@google.com
5412855Sgabeblack@google.com// We wrap these in a function to make sure they're built in time.
5512855Sgabeblack@google.comlist<Info *> &
5612855Sgabeblack@google.comstatsList()
5712855Sgabeblack@google.com{
5812855Sgabeblack@google.com    static list<Info *> the_list;
5912855Sgabeblack@google.com    return the_list;
6012855Sgabeblack@google.com}
6112855Sgabeblack@google.com
6212855Sgabeblack@google.comMapType &
6312855Sgabeblack@google.comstatsMap()
6412855Sgabeblack@google.com{
6512855Sgabeblack@google.com    static MapType the_map;
6612855Sgabeblack@google.com    return the_map;
6712855Sgabeblack@google.com}
6812855Sgabeblack@google.com
6912855Sgabeblack@google.comvoid
7012855Sgabeblack@google.comInfoAccess::setInfo(Info *info)
7112855Sgabeblack@google.com{
7212855Sgabeblack@google.com    if (statsMap().find(this) != statsMap().end())
7312855Sgabeblack@google.com        panic("shouldn't register stat twice!");
7412855Sgabeblack@google.com
7512855Sgabeblack@google.com    statsList().push_back(info);
7612855Sgabeblack@google.com
7712855Sgabeblack@google.com#ifndef NDEBUG
7812855Sgabeblack@google.com    pair<MapType::iterator, bool> result =
7912855Sgabeblack@google.com#endif
8012855Sgabeblack@google.com        statsMap().insert(make_pair(this, info));
8112855Sgabeblack@google.com    assert(result.second && "this should never fail");
8212855Sgabeblack@google.com    assert(statsMap().find(this) != statsMap().end());
8312855Sgabeblack@google.com}
8412855Sgabeblack@google.com
8512855Sgabeblack@google.comvoid
8612855Sgabeblack@google.comInfoAccess::setParams(const StorageParams *params)
8712855Sgabeblack@google.com{
8812855Sgabeblack@google.com    info()->storageParams = params;
8912855Sgabeblack@google.com}
9012855Sgabeblack@google.com
9112855Sgabeblack@google.comvoid
9212855Sgabeblack@google.comInfoAccess::setInit()
9312855Sgabeblack@google.com{
9412855Sgabeblack@google.com    info()->flags.set(init);
9512855Sgabeblack@google.com}
9612855Sgabeblack@google.com
9712855Sgabeblack@google.comInfo *
9812855Sgabeblack@google.comInfoAccess::info()
9912855Sgabeblack@google.com{
10012855Sgabeblack@google.com    MapType::const_iterator i = statsMap().find(this);
10112855Sgabeblack@google.com    assert(i != statsMap().end());
10212855Sgabeblack@google.com    return (*i).second;
10312855Sgabeblack@google.com}
10412855Sgabeblack@google.com
10512855Sgabeblack@google.comconst Info *
10612855Sgabeblack@google.comInfoAccess::info() const
10712855Sgabeblack@google.com{
10812855Sgabeblack@google.com    MapType::const_iterator i = statsMap().find(this);
10912855Sgabeblack@google.com    assert(i != statsMap().end());
11012855Sgabeblack@google.com    return (*i).second;
11112855Sgabeblack@google.com}
11212855Sgabeblack@google.com
11312855Sgabeblack@google.comStorageParams::~StorageParams()
11412855Sgabeblack@google.com{
11512855Sgabeblack@google.com}
11612855Sgabeblack@google.com
11712855Sgabeblack@google.comtypedef map<std::string, Info *> NameMapType;
11812855Sgabeblack@google.comNameMapType &
11912855Sgabeblack@google.comnameMap()
12012855Sgabeblack@google.com{
12112855Sgabeblack@google.com    static NameMapType the_map;
12212855Sgabeblack@google.com    return the_map;
12312855Sgabeblack@google.com}
12412855Sgabeblack@google.com
12512855Sgabeblack@google.comint Info::id_count = 0;
12612855Sgabeblack@google.com
12712855Sgabeblack@google.comint debug_break_id = -1;
12812855Sgabeblack@google.com
12912855Sgabeblack@google.comInfo::Info()
13012855Sgabeblack@google.com    : flags(none), precision(-1), prereq(0), storageParams(NULL)
13112855Sgabeblack@google.com{
13212855Sgabeblack@google.com    id = id_count++;
13312855Sgabeblack@google.com    if (debug_break_id >= 0 and debug_break_id == id)
13412855Sgabeblack@google.com        Debug::breakpoint();
13512855Sgabeblack@google.com}
13612855Sgabeblack@google.com
13712855Sgabeblack@google.comInfo::~Info()
13812855Sgabeblack@google.com{
13912855Sgabeblack@google.com}
14012855Sgabeblack@google.com
14112855Sgabeblack@google.combool
14212855Sgabeblack@google.comvalidateStatName(const string &name)
14312855Sgabeblack@google.com{
14412855Sgabeblack@google.com    if (name.empty())
14512855Sgabeblack@google.com        return false;
14612855Sgabeblack@google.com
14712855Sgabeblack@google.com    vector<string> vec;
14812855Sgabeblack@google.com    tokenize(vec, name, '.');
14912855Sgabeblack@google.com    vector<string>::const_iterator item = vec.begin();
15012855Sgabeblack@google.com    while (item != vec.end()) {
15112855Sgabeblack@google.com        if (item->empty())
15212855Sgabeblack@google.com            return false;
15312855Sgabeblack@google.com
15412855Sgabeblack@google.com        string::const_iterator c = item->begin();
15512855Sgabeblack@google.com
15612855Sgabeblack@google.com        // The first character is different
15712855Sgabeblack@google.com        if (!isalpha(*c) && *c != '_')
15812855Sgabeblack@google.com            return false;
15912855Sgabeblack@google.com
16012855Sgabeblack@google.com        // The rest of the characters have different rules.
16112855Sgabeblack@google.com        while (++c != item->end()) {
16212855Sgabeblack@google.com            if (!isalnum(*c) && *c != '_')
16312855Sgabeblack@google.com                return false;
16412855Sgabeblack@google.com        }
16512855Sgabeblack@google.com
16612855Sgabeblack@google.com        ++item;
16712855Sgabeblack@google.com    }
16812855Sgabeblack@google.com
16912855Sgabeblack@google.com    return true;
170}
171
172void
173Info::setName(const string &name)
174{
175    if (!validateStatName(name))
176        panic("invalid stat name '%s'", name);
177
178    pair<NameMapType::iterator, bool> p =
179        nameMap().insert(make_pair(name, this));
180
181    Info *other = p.first->second;
182    bool result = p.second;
183
184    if (!result) {
185        // using other->name instead of just name to avoid a compiler
186        // warning.  They should be the same.
187        panic("same statistic name used twice! name=%s\n", other->name);
188    }
189
190    this->name = name;
191}
192
193bool
194Info::less(Info *stat1, Info *stat2)
195{
196    const string &name1 = stat1->name;
197    const string &name2 = stat2->name;
198
199    vector<string> v1;
200    vector<string> v2;
201
202    tokenize(v1, name1, '.');
203    tokenize(v2, name2, '.');
204
205    size_type last = min(v1.size(), v2.size()) - 1;
206    for (off_type i = 0; i < last; ++i)
207        if (v1[i] != v2[i])
208            return v1[i] < v2[i];
209
210    // Special compare for last element.
211    if (v1[last] == v2[last])
212        return v1.size() < v2.size();
213    else
214        return v1[last] < v2[last];
215
216    return false;
217}
218
219bool
220Info::baseCheck() const
221{
222    if (!(flags & Stats::init)) {
223#ifdef DEBUG
224        cprintf("this is stat number %d\n", id);
225#endif
226        panic("Not all stats have been initialized");
227        return false;
228    }
229
230    if ((flags & display) && name.empty()) {
231        panic("all printable stats must be named");
232        return false;
233    }
234
235    return true;
236}
237
238void
239Info::enable()
240{
241}
242
243void
244VectorInfo::enable()
245{
246    size_type s = size();
247    if (subnames.size() < s)
248        subnames.resize(s);
249    if (subdescs.size() < s)
250        subdescs.resize(s);
251}
252
253void
254VectorDistInfo::enable()
255{
256    size_type s = size();
257    if (subnames.size() < s)
258        subnames.resize(s);
259    if (subdescs.size() < s)
260        subdescs.resize(s);
261}
262
263void
264Vector2dInfo::enable()
265{
266    if (subnames.size() < x)
267        subnames.resize(x);
268    if (subdescs.size() < x)
269        subdescs.resize(x);
270    if (y_subnames.size() < y)
271        y_subnames.resize(y);
272}
273
274void
275HistStor::grow_out()
276{
277    int size = cvec.size();
278    int zero = size / 2; // round down!
279    int top_half = zero + (size - zero + 1) / 2; // round up!
280    int bottom_half = (size - zero) / 2; // round down!
281
282    // grow down
283    int low_pair = zero - 1;
284    for (int i = zero - 1; i >= bottom_half; i--) {
285        cvec[i] = cvec[low_pair];
286        if (low_pair - 1 >= 0)
287            cvec[i] += cvec[low_pair - 1];
288        low_pair -= 2;
289    }
290    assert(low_pair == 0 || low_pair == -1 || low_pair == -2);
291
292    for (int i = bottom_half - 1; i >= 0; i--)
293        cvec[i] = Counter();
294
295    // grow up
296    int high_pair = zero;
297    for (int i = zero; i < top_half; i++) {
298        cvec[i] = cvec[high_pair];
299        if (high_pair + 1 < size)
300            cvec[i] += cvec[high_pair + 1];
301        high_pair += 2;
302    }
303    assert(high_pair == size || high_pair == size + 1);
304
305    for (int i = top_half; i < size; i++)
306        cvec[i] = Counter();
307
308    max_bucket *= 2;
309    min_bucket *= 2;
310    bucket_size *= 2;
311}
312
313void
314HistStor::grow_convert()
315{
316    int size = cvec.size();
317    int half = (size + 1) / 2; // round up!
318    //bool even = (size & 1) == 0;
319
320    int pair = size - 1;
321    for (int i = size - 1; i >= half; --i) {
322        cvec[i] = cvec[pair];
323        if (pair - 1 >= 0)
324            cvec[i] += cvec[pair - 1];
325        pair -= 2;
326    }
327
328    for (int i = half - 1; i >= 0; i--)
329        cvec[i] = Counter();
330
331    min_bucket = -max_bucket;// - (even ? bucket_size : 0);
332    bucket_size *= 2;
333}
334
335void
336HistStor::grow_up()
337{
338    int size = cvec.size();
339    int half = (size + 1) / 2; // round up!
340
341    int pair = 0;
342    for (int i = 0; i < half; i++) {
343        cvec[i] = cvec[pair];
344        if (pair + 1 < size)
345            cvec[i] += cvec[pair + 1];
346        pair += 2;
347    }
348    assert(pair == size || pair == size + 1);
349
350    for (int i = half; i < size; i++)
351        cvec[i] = Counter();
352
353    max_bucket *= 2;
354    bucket_size *= 2;
355}
356
357Formula::Formula()
358{
359}
360
361Formula::Formula(Temp r)
362{
363    root = r;
364    setInit();
365    assert(size());
366}
367
368const Formula &
369Formula::operator=(Temp r)
370{
371    assert(!root && "Can't change formulas");
372    root = r;
373    setInit();
374    assert(size());
375    return *this;
376}
377
378const Formula &
379Formula::operator+=(Temp r)
380{
381    if (root)
382        root = NodePtr(new BinaryNode<std::plus<Result> >(root, r));
383    else {
384        root = r;
385        setInit();
386    }
387
388    assert(size());
389    return *this;
390}
391
392void
393Formula::result(VResult &vec) const
394{
395    if (root)
396        vec = root->result();
397}
398
399Result
400Formula::total() const
401{
402    return root ? root->total() : 0.0;
403}
404
405size_type
406Formula::size() const
407{
408    if (!root)
409        return 0;
410    else
411        return root->size();
412}
413
414void
415Formula::reset()
416{
417}
418
419bool
420Formula::zero() const
421{
422    VResult vec;
423    result(vec);
424    for (VResult::size_type i = 0; i < vec.size(); ++i)
425        if (vec[i] != 0.0)
426            return false;
427    return true;
428}
429
430string
431Formula::str() const
432{
433    return root ? root->str() : "";
434}
435
436CallbackQueue resetQueue;
437
438void
439registerResetCallback(Callback *cb)
440{
441    resetQueue.add(cb);
442}
443
444bool _enabled = false;
445
446bool
447enabled()
448{
449    return _enabled;
450}
451
452void
453enable()
454{
455    if (_enabled)
456        fatal("Stats are already enabled");
457
458    _enabled = true;
459}
460
461} // namespace Stats
462
463void
464debugDumpStats()
465{
466    Stats::dump();
467}
468