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