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