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