text.cc revision 4209:57ff8c2ae0cf
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.compat = compat;
255    print.precision = precision;
256    print.descriptions = descriptions;
257    print.flags = flags;
258    print.pdf = NAN;
259    print.cdf = NAN;
260
261    bool havesub = !subnames.empty();
262
263    if (_size == 1) {
264        print.value = vec[0];
265        print(stream);
266    } else if (!compat) {
267        for (int i = 0; i < _size; ++i) {
268            if (havesub && (i >= subnames.size() || subnames[i].empty()))
269                continue;
270
271            print.name = base + (havesub ? subnames[i] : to_string(i));
272            print.desc = subdescs.empty() ? desc : subdescs[i];
273            print.value = vec[i];
274
275            if (_total && (flags & pdf)) {
276                print.pdf = vec[i] / _total;
277                print.cdf += print.pdf;
278            }
279
280            print(stream);
281        }
282
283        if (flags & ::Stats::total) {
284            print.name = base + "total";
285            print.desc = desc;
286            print.value = total;
287            print(stream);
288        }
289    } else {
290        if (flags & ::Stats::total) {
291            print.value = total;
292            print(stream);
293        }
294
295        Result _pdf = 0.0;
296        Result _cdf = 0.0;
297        if (flags & dist) {
298            ccprintf(stream, "%s.start_dist\n", name);
299            for (int i = 0; i < _size; ++i) {
300                print.name = havesub ? subnames[i] : to_string(i);
301                print.desc = subdescs.empty() ? desc : subdescs[i];
302                print.flags |= __substat;
303                print.value = vec[i];
304
305                if (_total) {
306                    _pdf = vec[i] / _total;
307                    _cdf += _pdf;
308                }
309
310                if (flags & pdf)
311                    print.pdf = _pdf;
312                if (flags & cdf)
313                    print.cdf = _cdf;
314
315                print(stream);
316            }
317            ccprintf(stream, "%s.end_dist\n", name);
318        } else {
319            for (int i = 0; i < _size; ++i) {
320                if (havesub && subnames[i].empty())
321                    continue;
322
323                print.name = base;
324                print.name += havesub ? subnames[i] : to_string(i);
325                print.desc = subdescs.empty() ? desc : subdescs[i];
326                print.value = vec[i];
327
328                if (_total) {
329                    _pdf = vec[i] / _total;
330                    _cdf += _pdf;
331                } else {
332                    _pdf = _cdf = NAN;
333                }
334
335                if (flags & pdf) {
336                    print.pdf = _pdf;
337                    print.cdf = _cdf;
338                }
339
340                print(stream);
341            }
342        }
343    }
344}
345
346struct DistPrint
347{
348    string name;
349    string desc;
350    StatFlags flags;
351    bool compat;
352    bool descriptions;
353    int precision;
354
355    Result min_val;
356    Result max_val;
357    Result underflow;
358    Result overflow;
359    VResult vec;
360    Result sum;
361    Result squares;
362    Result samples;
363
364    Counter min;
365    Counter max;
366    Counter bucket_size;
367    int size;
368    bool fancy;
369
370    void operator()(ostream &stream) const;
371};
372
373void
374DistPrint::operator()(ostream &stream) const
375{
376    if (fancy) {
377        ScalarPrint print;
378        string base = name + (compat ? "_" : "::");
379
380        print.precision = precision;
381        print.flags = flags;
382        print.compat = compat;
383        print.descriptions = descriptions;
384        print.desc = desc;
385        print.pdf = NAN;
386        print.cdf = NAN;
387
388        print.name = base + "mean";
389        print.value = samples ? sum / samples : NAN;
390        print(stream);
391
392        print.name = base + "stdev";
393        print.value = samples ? sqrt((samples * squares - sum * sum) /
394                                     (samples * (samples - 1.0))) : NAN;
395        print(stream);
396
397        print.name = "**Ignore: " + base + "TOT";
398        print.value = samples;
399        print(stream);
400        return;
401    }
402
403    assert(size == vec.size());
404
405    Result total = 0.0;
406
407    total += underflow;
408    for (int i = 0; i < size; ++i)
409        total += vec[i];
410    total += overflow;
411
412    string base = name + (compat ? "." : "::");
413
414    ScalarPrint print;
415    print.desc = compat ? "" : desc;
416    print.flags = flags;
417    print.compat = compat;
418    print.descriptions = descriptions;
419    print.precision = precision;
420    print.pdf = NAN;
421    print.cdf = NAN;
422
423    if (compat) {
424        ccprintf(stream, "%-42s", base + "start_dist");
425        if (descriptions && !desc.empty())
426            ccprintf(stream, "                     # %s", desc);
427        stream << endl;
428    }
429
430    print.name = base + "samples";
431    print.value = samples;
432    print(stream);
433
434    print.name = base + "min_value";
435    print.value = min_val;
436    print(stream);
437
438    if (!compat || underflow > 0.0) {
439        print.name = base + "underflows";
440        print.value = underflow;
441        if (!compat && total) {
442            print.pdf = underflow / total;
443            print.cdf += print.pdf;
444        }
445        print(stream);
446    }
447
448
449    if (!compat) {
450        for (int i = 0; i < size; ++i) {
451            stringstream namestr;
452            namestr << name;
453
454            Counter low = i * bucket_size + min;
455            Counter high = ::min(low + bucket_size, max);
456            namestr << low;
457            if (low < high)
458                namestr << "-" << high;
459
460            print.name = namestr.str();
461            print.value = vec[i];
462            if (total) {
463                print.pdf = vec[i] / total;
464                print.cdf += print.pdf;
465            }
466            print(stream);
467        }
468
469    } else {
470        Counter _min;
471        Result _pdf;
472        Result _cdf = 0.0;
473
474        print.flags = flags | __substat;
475
476        for (int 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 ScalarData &data)
539{
540    if (noOutput(data))
541        return;
542
543    ScalarPrint print;
544    print.value = data.result();
545    print.name = data.name;
546    print.desc = data.desc;
547    print.flags = data.flags;
548    print.compat = compat;
549    print.descriptions = descriptions;
550    print.precision = data.precision;
551    print.pdf = NAN;
552    print.cdf = NAN;
553
554    print(*stream);
555}
556
557void
558Text::visit(const VectorData &data)
559{
560    if (noOutput(data))
561        return;
562
563    int size = data.size();
564    VectorPrint print;
565
566    print.name = data.name;
567    print.desc = data.desc;
568    print.flags = data.flags;
569    print.compat = compat;
570    print.descriptions = descriptions;
571    print.precision = data.precision;
572    print.vec = data.result();
573    print.total = data.total();
574
575    if (!data.subnames.empty()) {
576        for (int i = 0; i < size; ++i) {
577            if (!data.subnames[i].empty()) {
578                print.subnames = data.subnames;
579                print.subnames.resize(size);
580                for (int i = 0; i < size; ++i) {
581                    if (!data.subnames[i].empty() &&
582                        !data.subdescs[i].empty()) {
583                        print.subdescs = data.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 Vector2dData &data)
598{
599    if (noOutput(data))
600        return;
601
602    bool havesub = false;
603    VectorPrint print;
604
605    print.subnames = data.y_subnames;
606    print.flags = data.flags;
607    print.compat = compat;
608    print.descriptions = descriptions;
609    print.precision = data.precision;
610
611    if (!data.subnames.empty()) {
612        for (int i = 0; i < data.x; ++i)
613            if (!data.subnames[i].empty())
614                havesub = true;
615    }
616
617    VResult tot_vec(data.y);
618    Result super_total = 0.0;
619    for (int i = 0; i < data.x; ++i) {
620        if (havesub && (i >= data.subnames.size() || data.subnames[i].empty()))
621            continue;
622
623        int iy = i * data.y;
624        VResult yvec(data.y);
625
626        Result total = 0.0;
627        for (int j = 0; j < data.y; ++j) {
628            yvec[j] = data.cvec[iy + j];
629            tot_vec[j] += yvec[j];
630            total += yvec[j];
631            super_total += yvec[j];
632        }
633
634        print.name = data.name + "_" + (havesub ? data.subnames[i] : to_string(i));
635        print.desc = data.desc;
636        print.vec = yvec;
637        print.total = total;
638        print(*stream);
639    }
640
641    if ((data.flags & ::Stats::total) && (data.x > 1)) {
642        print.name = data.name;
643        print.desc = data.desc;
644        print.vec = tot_vec;
645        print.total = super_total;
646        print(*stream);
647    }
648}
649
650void
651Text::visit(const DistData &data)
652{
653    if (noOutput(data))
654        return;
655
656    DistPrint print;
657
658    print.name = data.name;
659    print.desc = data.desc;
660    print.flags = data.flags;
661    print.compat = compat;
662    print.descriptions = descriptions;
663    print.precision = data.precision;
664
665    print.min_val = data.data.min_val;
666    print.max_val = data.data.max_val;
667    print.underflow = data.data.underflow;
668    print.overflow = data.data.overflow;
669    print.vec.resize(data.data.cvec.size());
670    for (int i = 0; i < print.vec.size(); ++i)
671        print.vec[i] = (Result)data.data.cvec[i];
672    print.sum = data.data.sum;
673    print.squares = data.data.squares;
674    print.samples = data.data.samples;
675
676    print.min = data.data.min;
677    print.max = data.data.max;
678    print.bucket_size = data.data.bucket_size;
679    print.size = data.data.size;
680    print.fancy = data.data.fancy;
681
682    print(*stream);
683}
684
685void
686Text::visit(const VectorDistData &data)
687{
688    if (noOutput(data))
689        return;
690
691    for (int i = 0; i < data.size(); ++i) {
692        DistPrint print;
693
694        print.name = data.name +
695            (data.subnames[i].empty() ? ("_" + to_string(i)) : data.subnames[i]);
696        print.desc = data.subdescs[i].empty() ? data.desc : data.subdescs[i];
697        print.flags = data.flags;
698        print.compat = compat;
699        print.descriptions = descriptions;
700        print.precision = data.precision;
701
702        print.min_val = data.data[i].min_val;
703        print.max_val = data.data[i].max_val;
704        print.underflow = data.data[i].underflow;
705        print.overflow = data.data[i].overflow;
706        print.vec.resize(data.data[i].cvec.size());
707        for (int j = 0; j < print.vec.size(); ++j)
708            print.vec[j] = (Result)data.data[i].cvec[j];
709        print.sum = data.data[i].sum;
710        print.squares = data.data[i].squares;
711        print.samples = data.data[i].samples;
712
713        print.min = data.data[i].min;
714        print.max = data.data[i].max;
715        print.bucket_size = data.data[i].bucket_size;
716        print.size = data.data[i].size;
717        print.fancy = data.data[i].fancy;
718
719        print(*stream);
720    }
721}
722
723void
724Text::visit(const FormulaData &data)
725{
726    visit((const VectorData &)data);
727}
728
729bool
730initText(const string &filename, bool desc, bool compat)
731{
732    static Text text;
733    static bool connected = false;
734
735    if (connected)
736        return false;
737
738    extern list<Output *> OutputList;
739
740    text.open(*simout.find(filename));
741    text.descriptions = desc;
742    text.compat = compat;
743    OutputList.push_back(&text);
744    connected = true;
745
746    return true;
747}
748
749
750/* namespace Stats */ }
751