text.cc revision 8666:97d873b8b13e
1/*
2 * Copyright (c) 2004-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#if defined(__APPLE__)
32#define _GLIBCPP_USE_C99 1
33#endif
34
35#if defined(__sun)
36#include <math.h>
37#endif
38
39#include <cassert>
40#ifdef __SUNPRO_CC
41#include <math.h>
42#endif
43#include <cmath>
44#include <fstream>
45#include <iostream>
46#include <sstream>
47#include <string>
48
49#include "base/stats/info.hh"
50#include "base/stats/text.hh"
51#include "base/cast.hh"
52#include "base/misc.hh"
53#include "base/str.hh"
54
55using namespace std;
56
57#ifndef NAN
58float __nan();
59/** Define Not a number. */
60#define NAN (__nan())
61/** Need to define __nan() */
62#define __M5_NAN
63#endif
64
65#ifdef __M5_NAN
66float
67__nan()
68{
69    union {
70        uint32_t ui;
71        float f;
72    } nan;
73
74    nan.ui = 0x7fc00000;
75    return nan.f;
76}
77#endif
78
79namespace Stats {
80
81std::list<Info *> &statsList();
82
83Text::Text()
84    : mystream(false), stream(NULL), descriptions(false)
85{
86}
87
88Text::Text(std::ostream &stream)
89    : mystream(false), stream(NULL), descriptions(false)
90{
91    open(stream);
92}
93
94Text::Text(const std::string &file)
95    : mystream(false), stream(NULL), descriptions(false)
96{
97    open(file);
98}
99
100
101Text::~Text()
102{
103    if (mystream) {
104        assert(stream);
105        delete stream;
106    }
107}
108
109void
110Text::open(std::ostream &_stream)
111{
112    if (stream)
113        panic("stream already set!");
114
115    mystream = false;
116    stream = &_stream;
117    if (!valid())
118        fatal("Unable to open output stream for writing\n");
119}
120
121void
122Text::open(const std::string &file)
123{
124    if (stream)
125        panic("stream already set!");
126
127    mystream = true;
128    stream = new ofstream(file.c_str(), ios::trunc);
129    if (!valid())
130        fatal("Unable to open statistics file for writing\n");
131}
132
133bool
134Text::valid() const
135{
136    return stream != NULL && stream->good();
137}
138
139void
140Text::begin()
141{
142    ccprintf(*stream, "\n---------- Begin Simulation Statistics ----------\n");
143}
144
145void
146Text::end()
147{
148    ccprintf(*stream, "\n---------- End Simulation Statistics   ----------\n");
149    stream->flush();
150}
151
152bool
153Text::noOutput(const Info &info)
154{
155    if (!info.flags.isSet(display))
156        return true;
157
158    if (info.prereq && info.prereq->zero())
159        return true;
160
161    return false;
162}
163
164string
165ValueToString(Result value, int precision)
166{
167    stringstream val;
168
169    if (!isnan(value)) {
170        if (precision != -1)
171            val.precision(precision);
172        else if (value == rint(value))
173            val.precision(0);
174
175        val.unsetf(ios::showpoint);
176        val.setf(ios::fixed);
177        val << value;
178    } else {
179        val << "no_value";
180    }
181
182    return val.str();
183}
184
185struct ScalarPrint
186{
187    Result value;
188    string name;
189    string desc;
190    Flags flags;
191    bool descriptions;
192    int precision;
193    Result pdf;
194    Result cdf;
195
196    void update(Result val, Result total);
197    void operator()(ostream &stream) const;
198};
199
200void
201ScalarPrint::update(Result val, Result total)
202{
203    value = val;
204    if (total) {
205        pdf = val / total;
206        cdf += pdf;
207    }
208}
209
210void
211ScalarPrint::operator()(ostream &stream) const
212{
213    if ((flags.isSet(nozero) && value == 0.0) ||
214        (flags.isSet(nonan) && isnan(value)))
215        return;
216
217    stringstream pdfstr, cdfstr;
218
219    if (!isnan(pdf))
220        ccprintf(pdfstr, "%.2f%%", pdf * 100.0);
221
222    if (!isnan(cdf))
223        ccprintf(cdfstr, "%.2f%%", cdf * 100.0);
224
225    ccprintf(stream, "%-40s %12s %10s %10s", name,
226             ValueToString(value, precision), pdfstr, cdfstr);
227
228    if (descriptions) {
229        if (!desc.empty())
230            ccprintf(stream, " # %s", desc);
231    }
232    stream << endl;
233}
234
235struct VectorPrint
236{
237    string name;
238    string separatorString;
239    string desc;
240    vector<string> subnames;
241    vector<string> subdescs;
242    Flags flags;
243    bool descriptions;
244    int precision;
245    VResult vec;
246    Result total;
247
248    void operator()(ostream &stream) const;
249};
250
251void
252VectorPrint::operator()(std::ostream &stream) const
253{
254    size_type _size = vec.size();
255    Result _total = 0.0;
256
257    if (flags.isSet(pdf | cdf)) {
258        for (off_type i = 0; i < _size; ++i) {
259            _total += vec[i];
260        }
261    }
262
263    string base = name + separatorString;
264
265    ScalarPrint print;
266    print.name = name;
267    print.desc = desc;
268    print.precision = precision;
269    print.descriptions = descriptions;
270    print.flags = flags;
271    print.pdf = _total ? 0.0 : NAN;
272    print.cdf = _total ? 0.0 : NAN;
273
274    bool havesub = !subnames.empty();
275
276    if (_size == 1) {
277        print.value = vec[0];
278        print(stream);
279        return;
280    }
281
282    for (off_type i = 0; i < _size; ++i) {
283        if (havesub && (i >= subnames.size() || subnames[i].empty()))
284            continue;
285
286        print.name = base + (havesub ? subnames[i] : to_string(i));
287        print.desc = subdescs.empty() ? desc : subdescs[i];
288
289        print.update(vec[i], _total);
290        print(stream);
291    }
292
293    if (flags.isSet(::Stats::total)) {
294        print.pdf = NAN;
295        print.cdf = NAN;
296        print.name = base + "total";
297        print.desc = desc;
298        print.value = total;
299        print(stream);
300    }
301}
302
303struct DistPrint
304{
305    string name;
306    string separatorString;
307    string desc;
308    Flags flags;
309    bool descriptions;
310    int precision;
311
312    const DistData &data;
313
314    DistPrint(const Text *text, const DistInfo &info);
315    DistPrint(const Text *text, const VectorDistInfo &info, int i);
316    void init(const Text *text, const Info &info);
317    void operator()(ostream &stream) const;
318};
319
320DistPrint::DistPrint(const Text *text, const DistInfo &info)
321    : data(info.data)
322{
323    init(text, info);
324}
325
326DistPrint::DistPrint(const Text *text, const VectorDistInfo &info, int i)
327    : data(info.data[i])
328{
329    init(text, info);
330
331    name = info.name + "_" +
332        (info.subnames[i].empty() ? (to_string(i)) : info.subnames[i]);
333
334    if (!info.subdescs[i].empty())
335        desc = info.subdescs[i];
336}
337
338void
339DistPrint::init(const Text *text, const Info &info)
340{
341    name = info.name;
342    separatorString = info.separatorString;
343    desc = info.desc;
344    flags = info.flags;
345    precision = info.precision;
346    descriptions = text->descriptions;
347}
348
349void
350DistPrint::operator()(ostream &stream) const
351{
352    string base = name + separatorString;
353
354    ScalarPrint print;
355    print.precision = precision;
356    print.flags = flags;
357    print.descriptions = descriptions;
358    print.desc = desc;
359    print.pdf = NAN;
360    print.cdf = NAN;
361
362    print.name = base + "samples";
363    print.value = data.samples;
364    print(stream);
365
366    print.name = base + "mean";
367    print.value = data.samples ? data.sum / data.samples : NAN;
368    print(stream);
369
370    if (data.type == Hist) {
371        print.name = base + "gmean";
372        print.value = data.samples ? exp(data.logs / data.samples) : NAN;
373        print(stream);
374    }
375
376    Result stdev = NAN;
377    if (data.samples)
378        stdev = sqrt((data.samples * data.squares - data.sum * data.sum) /
379                     (data.samples * (data.samples - 1.0)));
380    print.name = base + "stdev";
381    print.value = stdev;
382    print(stream);
383
384    if (data.type == Deviation)
385        return;
386
387    size_t size = data.cvec.size();
388
389    Result total = 0.0;
390    if (data.type == Dist && data.underflow != NAN)
391        total += data.underflow;
392    for (off_type i = 0; i < size; ++i)
393        total += data.cvec[i];
394    if (data.type == Dist && data.overflow != NAN)
395        total += data.overflow;
396
397    if (total) {
398        print.pdf = 0.0;
399        print.cdf = 0.0;
400    }
401
402    if (data.type == Dist && data.underflow != NAN) {
403        print.name = base + "underflows";
404        print.update(data.underflow, total);
405        print(stream);
406    }
407
408    for (off_type i = 0; i < size; ++i) {
409        stringstream namestr;
410        namestr << base;
411
412        Counter low = i * data.bucket_size + data.min;
413        Counter high = ::min(low + data.bucket_size - 1.0, data.max);
414        namestr << low;
415        if (low < high)
416            namestr << "-" << high;
417
418        print.name = namestr.str();
419        print.update(data.cvec[i], total);
420        print(stream);
421    }
422
423    if (data.type == Dist && data.overflow != NAN) {
424        print.name = base + "overflows";
425        print.update(data.overflow, total);
426        print(stream);
427    }
428
429    print.pdf = NAN;
430    print.cdf = NAN;
431
432    if (data.type == Dist && data.min_val != NAN) {
433        print.name = base + "min_value";
434        print.value = data.min_val;
435        print(stream);
436    }
437
438    if (data.type == Dist && data.max_val != NAN) {
439        print.name = base + "max_value";
440        print.value = data.max_val;
441        print(stream);
442    }
443
444    print.name = base + "total";
445    print.value = total;
446    print(stream);
447}
448
449void
450Text::visit(const ScalarInfo &info)
451{
452    if (noOutput(info))
453        return;
454
455    ScalarPrint print;
456    print.value = info.result();
457    print.name = info.name;
458    print.desc = info.desc;
459    print.flags = info.flags;
460    print.descriptions = descriptions;
461    print.precision = info.precision;
462    print.pdf = NAN;
463    print.cdf = NAN;
464
465    print(*stream);
466}
467
468void
469Text::visit(const VectorInfo &info)
470{
471    if (noOutput(info))
472        return;
473
474    size_type size = info.size();
475    VectorPrint print;
476
477    print.name = info.name;
478    print.separatorString = info.separatorString;
479    print.desc = info.desc;
480    print.flags = info.flags;
481    print.descriptions = descriptions;
482    print.precision = info.precision;
483    print.vec = info.result();
484    print.total = info.total();
485
486    if (!info.subnames.empty()) {
487        for (off_type i = 0; i < size; ++i) {
488            if (!info.subnames[i].empty()) {
489                print.subnames = info.subnames;
490                print.subnames.resize(size);
491                for (off_type i = 0; i < size; ++i) {
492                    if (!info.subnames[i].empty() &&
493                        !info.subdescs[i].empty()) {
494                        print.subdescs = info.subdescs;
495                        print.subdescs.resize(size);
496                        break;
497                    }
498                }
499                break;
500            }
501        }
502    }
503
504    print(*stream);
505}
506
507void
508Text::visit(const Vector2dInfo &info)
509{
510    if (noOutput(info))
511        return;
512
513    bool havesub = false;
514    VectorPrint print;
515
516    print.subnames = info.y_subnames;
517    print.flags = info.flags;
518    print.separatorString = info.separatorString;
519    print.descriptions = descriptions;
520    print.precision = info.precision;
521
522    if (!info.subnames.empty()) {
523        for (off_type i = 0; i < info.x; ++i)
524            if (!info.subnames[i].empty())
525                havesub = true;
526    }
527
528    VResult tot_vec(info.y);
529    Result super_total = 0.0;
530    for (off_type i = 0; i < info.x; ++i) {
531        if (havesub && (i >= info.subnames.size() || info.subnames[i].empty()))
532            continue;
533
534        off_type iy = i * info.y;
535        VResult yvec(info.y);
536
537        Result total = 0.0;
538        for (off_type j = 0; j < info.y; ++j) {
539            yvec[j] = info.cvec[iy + j];
540            tot_vec[j] += yvec[j];
541            total += yvec[j];
542            super_total += yvec[j];
543        }
544
545        print.name = info.name + "_" +
546            (havesub ? info.subnames[i] : to_string(i));
547        print.desc = info.desc;
548        print.vec = yvec;
549        print.total = total;
550        print(*stream);
551    }
552
553    if (info.flags.isSet(::Stats::total) && (info.x > 1)) {
554        print.name = info.name;
555        print.desc = info.desc;
556        print.vec = tot_vec;
557        print.total = super_total;
558        print(*stream);
559    }
560}
561
562void
563Text::visit(const DistInfo &info)
564{
565    if (noOutput(info))
566        return;
567
568    DistPrint print(this, info);
569    print(*stream);
570}
571
572void
573Text::visit(const VectorDistInfo &info)
574{
575    if (noOutput(info))
576        return;
577
578    for (off_type i = 0; i < info.size(); ++i) {
579        DistPrint print(this, info, i);
580        print(*stream);
581    }
582}
583
584void
585Text::visit(const FormulaInfo &info)
586{
587    visit((const VectorInfo &)info);
588}
589
590/*
591  This struct implements the output methods for the sparse
592  histogram stat
593*/
594struct SparseHistPrint
595{
596    string name;
597    string separatorString;
598    string desc;
599    Flags flags;
600    bool descriptions;
601    int precision;
602
603    const SparseHistData &data;
604
605    SparseHistPrint(const Text *text, const SparseHistInfo &info);
606    void init(const Text *text, const Info &info);
607    void operator()(ostream &stream) const;
608};
609
610/* Call initialization function */
611SparseHistPrint::SparseHistPrint(const Text *text, const SparseHistInfo &info)
612    : data(info.data)
613{
614    init(text, info);
615}
616
617/* Initialization function */
618void
619SparseHistPrint::init(const Text *text, const Info &info)
620{
621    name = info.name;
622    separatorString = info.separatorString;
623    desc = info.desc;
624    flags = info.flags;
625    precision = info.precision;
626    descriptions = text->descriptions;
627}
628
629/* Grab data from map and write to output stream */
630void
631SparseHistPrint::operator()(ostream &stream) const
632{
633    string base = name + separatorString;
634
635    ScalarPrint print;
636    print.precision = precision;
637    print.flags = flags;
638    print.descriptions = descriptions;
639    print.desc = desc;
640    print.pdf = NAN;
641    print.cdf = NAN;
642
643    print.name = base + "samples";
644    print.value = data.samples;
645    print(stream);
646
647    MCounter::const_iterator it;
648    for (it = data.cmap.begin(); it != data.cmap.end(); it++) {
649        stringstream namestr;
650        namestr << base;
651
652        namestr <<(*it).first;
653        print.name = namestr.str();
654        print.value = (*it).second;
655        print(stream);
656    }
657
658    print.pdf = NAN;
659    print.cdf = NAN;
660
661    print.name = base + "total";
662    print.value = total;
663    print(stream);
664}
665
666void
667Text::visit(const SparseHistInfo &info)
668{
669    if (noOutput(info))
670        return;
671
672    SparseHistPrint print(this, info);
673    print(*stream);
674}
675
676Output *
677initText(const string &filename, bool desc)
678{
679    static Text text;
680    static bool connected = false;
681
682    if (!connected) {
683        ostream *os = simout.find(filename);
684        if (!os)
685            os = simout.create(filename);
686
687        text.open(*os);
688        text.descriptions = desc;
689        connected = true;
690    }
691
692    return &text;
693}
694
695} // namespace Stats
696