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