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