text.cc revision 5886:12431dc9a30a
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#if defined(__sun)
36#include <math.h>
37#endif
38
39#include <iostream>
40#include <sstream>
41#include <fstream>
42#include <string>
43
44#include "base/misc.hh"
45#include "base/statistics.hh"
46#include "base/stats/statdb.hh"
47#include "base/stats/text.hh"
48#include "base/stats/visit.hh"
49
50using namespace std;
51
52#ifndef NAN
53float __nan();
54/** Define Not a number. */
55#define NAN (__nan())
56/** Need to define __nan() */
57#define __M5_NAN
58#endif
59
60#ifdef __M5_NAN
61float
62__nan()
63{
64    union {
65        uint32_t ui;
66        float f;
67    } nan;
68
69    nan.ui = 0x7fc00000;
70    return nan.f;
71}
72#endif
73
74namespace Stats {
75
76Text::Text()
77    : mystream(false), stream(NULL), compat(false), descriptions(false)
78{
79}
80
81Text::Text(std::ostream &stream)
82    : mystream(false), stream(NULL), compat(false), descriptions(false)
83{
84    open(stream);
85}
86
87Text::Text(const std::string &file)
88    : mystream(false), stream(NULL), compat(false), descriptions(false)
89{
90    open(file);
91}
92
93
94Text::~Text()
95{
96    if (mystream) {
97        assert(stream);
98        delete stream;
99    }
100}
101
102void
103Text::open(std::ostream &_stream)
104{
105    if (stream)
106        panic("stream already set!");
107
108    mystream = false;
109    stream = &_stream;
110    if (!valid())
111        fatal("Unable to open output stream for writing\n");
112}
113
114void
115Text::open(const std::string &file)
116{
117    if (stream)
118        panic("stream already set!");
119
120    mystream = true;
121    stream = new ofstream(file.c_str(), ios::trunc);
122    if (!valid())
123        fatal("Unable to open statistics file for writing\n");
124}
125
126bool
127Text::valid() const
128{
129    return stream != NULL && stream->good();
130}
131
132void
133Text::output()
134{
135    using namespace Database;
136
137    ccprintf(*stream, "\n---------- Begin Simulation Statistics ----------\n");
138    stat_list_t::const_iterator i, end = stats().end();
139    for (i = stats().begin(); i != end; ++i)
140        (*i)->visit(*this);
141    ccprintf(*stream, "\n---------- End Simulation Statistics   ----------\n");
142    stream->flush();
143}
144
145bool
146Text::noOutput(const Info &info)
147{
148    if (!(info.flags & print))
149        return true;
150
151    if (info.prereq && info.prereq->zero())
152        return true;
153
154    return false;
155}
156
157string
158ValueToString(Result value, int precision, bool compat)
159{
160    stringstream val;
161
162    if (!isnan(value)) {
163        if (precision != -1)
164            val.precision(precision);
165        else if (value == rint(value))
166            val.precision(0);
167
168        val.unsetf(ios::showpoint);
169        val.setf(ios::fixed);
170        val << value;
171    } else {
172        val << (compat ? "<err: div-0>" : "no value");
173    }
174
175    return val.str();
176}
177
178struct ScalarPrint
179{
180    Result value;
181    string name;
182    string desc;
183    StatFlags flags;
184    bool compat;
185    bool descriptions;
186    int precision;
187    Result pdf;
188    Result cdf;
189
190    void operator()(ostream &stream) const;
191};
192
193void
194ScalarPrint::operator()(ostream &stream) const
195{
196    if ((flags & nozero && value == 0.0) ||
197        (flags & nonan && isnan(value)))
198        return;
199
200    stringstream pdfstr, cdfstr;
201
202    if (!isnan(pdf))
203        ccprintf(pdfstr, "%.2f%%", pdf * 100.0);
204
205    if (!isnan(cdf))
206        ccprintf(cdfstr, "%.2f%%", cdf * 100.0);
207
208    if (compat && flags & __substat) {
209        ccprintf(stream, "%32s %12s %10s %10s", name,
210                 ValueToString(value, precision, compat), pdfstr, cdfstr);
211    } else {
212        ccprintf(stream, "%-40s %12s %10s %10s", name,
213                 ValueToString(value, precision, compat), pdfstr, cdfstr);
214    }
215
216    if (descriptions) {
217        if (!desc.empty())
218            ccprintf(stream, " # %s", desc);
219    }
220    stream << endl;
221}
222
223struct VectorPrint
224{
225    string name;
226    string desc;
227    vector<string> subnames;
228    vector<string> subdescs;
229    StatFlags flags;
230    bool compat;
231    bool descriptions;
232    int precision;
233    VResult vec;
234    Result total;
235
236    void operator()(ostream &stream) const;
237};
238
239void
240VectorPrint::operator()(std::ostream &stream) const
241{
242    size_type _size = vec.size();
243    Result _total = 0.0;
244
245    if (flags & (pdf | cdf)) {
246        for (off_type i = 0; i < _size; ++i) {
247            _total += vec[i];
248        }
249    }
250
251    string base = name + (compat ? "_" : "::");
252
253    ScalarPrint print;
254    print.name = name;
255    print.desc = desc;
256    print.compat = compat;
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 (off_type 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 & ::Stats::total) {
286            print.name = base + "total";
287            print.desc = desc;
288            print.value = total;
289            print(stream);
290        }
291    } else {
292        if (flags & ::Stats::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 (off_type 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 (off_type 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    size_type 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 (off_type 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    if (!compat) {
451        for (off_type i = 0; i < size; ++i) {
452            stringstream namestr;
453            namestr << base;
454
455            Counter low = i * bucket_size + min;
456            Counter high = ::min(low + bucket_size, max);
457            namestr << low;
458            if (low < high)
459                namestr << "-" << high;
460
461            print.name = namestr.str();
462            print.value = vec[i];
463            if (total) {
464                print.pdf = vec[i] / total;
465                print.cdf += print.pdf;
466            }
467            print(stream);
468        }
469    } else {
470        Counter _min;
471        Result _pdf;
472        Result _cdf = 0.0;
473
474        print.flags = flags | __substat;
475
476        for (off_type i = 0; i < size; ++i) {
477            if ((flags & nozero && vec[i] == 0.0) ||
478                (flags & nonan && isnan(vec[i])))
479                continue;
480
481            _min = i * bucket_size + min;
482            _pdf = vec[i] / total * 100.0;
483            _cdf += _pdf;
484
485
486            print.name = ValueToString(_min, 0, compat);
487            print.value = vec[i];
488            print.pdf = (flags & pdf) ? _pdf : NAN;
489            print.cdf = (flags & cdf) ? _cdf : NAN;
490            print(stream);
491        }
492
493        print.flags = flags;
494    }
495
496    if (!compat || overflow > 0.0) {
497        print.name = base + "overflows";
498        print.value = overflow;
499        if (!compat && total) {
500            print.pdf = overflow / total;
501            print.cdf += print.pdf;
502        } else {
503            print.pdf = NAN;
504            print.cdf = NAN;
505        }
506        print(stream);
507    }
508
509    print.pdf = NAN;
510    print.cdf = NAN;
511
512    if (!compat) {
513        print.name = base + "total";
514        print.value = total;
515        print(stream);
516    }
517
518    print.name = base + "max_value";
519    print.value = max_val;
520    print(stream);
521
522    if (!compat && samples != 0) {
523        print.name = base + "mean";
524        print.value = sum / samples;
525        print(stream);
526
527        print.name = base + "stdev";
528        print.value = sqrt((samples * squares - sum * sum) /
529                           (samples * (samples - 1.0)));
530        print(stream);
531    }
532
533    if (compat)
534        ccprintf(stream, "%send_dist\n\n", base);
535}
536
537void
538Text::visit(const ScalarInfoBase &info)
539{
540    if (noOutput(info))
541        return;
542
543    ScalarPrint print;
544    print.value = info.result();
545    print.name = info.name;
546    print.desc = info.desc;
547    print.flags = info.flags;
548    print.compat = compat;
549    print.descriptions = descriptions;
550    print.precision = info.precision;
551    print.pdf = NAN;
552    print.cdf = NAN;
553
554    print(*stream);
555}
556
557void
558Text::visit(const VectorInfoBase &info)
559{
560    if (noOutput(info))
561        return;
562
563    size_type size = info.size();
564    VectorPrint print;
565
566    print.name = info.name;
567    print.desc = info.desc;
568    print.flags = info.flags;
569    print.compat = compat;
570    print.descriptions = descriptions;
571    print.precision = info.precision;
572    print.vec = info.result();
573    print.total = info.total();
574
575    if (!info.subnames.empty()) {
576        for (off_type i = 0; i < size; ++i) {
577            if (!info.subnames[i].empty()) {
578                print.subnames = info.subnames;
579                print.subnames.resize(size);
580                for (off_type i = 0; i < size; ++i) {
581                    if (!info.subnames[i].empty() &&
582                        !info.subdescs[i].empty()) {
583                        print.subdescs = info.subdescs;
584                        print.subdescs.resize(size);
585                        break;
586                    }
587                }
588                break;
589            }
590        }
591    }
592
593    print(*stream);
594}
595
596void
597Text::visit(const Vector2dInfoBase &info)
598{
599    if (noOutput(info))
600        return;
601
602    bool havesub = false;
603    VectorPrint print;
604
605    print.subnames = info.y_subnames;
606    print.flags = info.flags;
607    print.compat = compat;
608    print.descriptions = descriptions;
609    print.precision = info.precision;
610
611    if (!info.subnames.empty()) {
612        for (off_type i = 0; i < info.x; ++i)
613            if (!info.subnames[i].empty())
614                havesub = true;
615    }
616
617    VResult tot_vec(info.y);
618    Result super_total = 0.0;
619    for (off_type i = 0; i < info.x; ++i) {
620        if (havesub && (i >= info.subnames.size() || info.subnames[i].empty()))
621            continue;
622
623        off_type iy = i * info.y;
624        VResult yvec(info.y);
625
626        Result total = 0.0;
627        for (off_type j = 0; j < info.y; ++j) {
628            yvec[j] = info.cvec[iy + j];
629            tot_vec[j] += yvec[j];
630            total += yvec[j];
631            super_total += yvec[j];
632        }
633
634        print.name = info.name + "_" +
635            (havesub ? info.subnames[i] : to_string(i));
636        print.desc = info.desc;
637        print.vec = yvec;
638        print.total = total;
639        print(*stream);
640    }
641
642    if ((info.flags & ::Stats::total) && (info.x > 1)) {
643        print.name = info.name;
644        print.desc = info.desc;
645        print.vec = tot_vec;
646        print.total = super_total;
647        print(*stream);
648    }
649}
650
651void
652Text::visit(const DistInfoBase &info)
653{
654    if (noOutput(info))
655        return;
656
657    DistPrint print;
658
659    print.name = info.name;
660    print.desc = info.desc;
661    print.flags = info.flags;
662    print.compat = compat;
663    print.descriptions = descriptions;
664    print.precision = info.precision;
665
666    const DistData &data = info.data;
667
668    print.min_val = data.min_val;
669    print.max_val = data.max_val;
670    print.underflow = data.underflow;
671    print.overflow = data.overflow;
672    print.vec.resize(data.cvec.size());
673    for (off_type i = 0; i < print.vec.size(); ++i)
674        print.vec[i] = (Result)data.cvec[i];
675    print.sum = data.sum;
676    print.squares = data.squares;
677    print.samples = data.samples;
678
679    print.min = data.min;
680    print.max = data.max;
681    print.bucket_size = data.bucket_size;
682    print.size = data.size;
683    print.fancy = data.fancy;
684
685    print(*stream);
686}
687
688void
689Text::visit(const VectorDistInfoBase &info)
690{
691    if (noOutput(info))
692        return;
693
694    for (off_type i = 0; i < info.size(); ++i) {
695        DistPrint print;
696
697        print.name = info.name + "_" +
698            (info.subnames[i].empty() ? (to_string(i)) : info.subnames[i]);
699        print.desc = info.subdescs[i].empty() ? info.desc : info.subdescs[i];
700        print.flags = info.flags;
701        print.compat = compat;
702        print.descriptions = descriptions;
703        print.precision = info.precision;
704
705        print.min_val = info.data[i].min_val;
706        print.max_val = info.data[i].max_val;
707        print.underflow = info.data[i].underflow;
708        print.overflow = info.data[i].overflow;
709        print.vec.resize(info.data[i].cvec.size());
710        for (off_type j = 0; j < print.vec.size(); ++j)
711            print.vec[j] = (Result)info.data[i].cvec[j];
712        print.sum = info.data[i].sum;
713        print.squares = info.data[i].squares;
714        print.samples = info.data[i].samples;
715
716        print.min = info.data[i].min;
717        print.max = info.data[i].max;
718        print.bucket_size = info.data[i].bucket_size;
719        print.size = info.data[i].size;
720        print.fancy = info.data[i].fancy;
721
722        print(*stream);
723    }
724}
725
726void
727Text::visit(const FormulaInfoBase &info)
728{
729    visit((const VectorInfoBase &)info);
730}
731
732bool
733initText(const string &filename, bool desc, bool compat)
734{
735    static Text text;
736    static bool connected = false;
737
738    if (connected)
739        return false;
740
741    extern list<Output *> OutputList;
742
743    text.open(*simout.find(filename));
744    text.descriptions = desc;
745    text.compat = compat;
746    OutputList.push_back(&text);
747    connected = true;
748
749    return true;
750}
751
752/* namespace Stats */ }
753