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