text.cc revision 5581
16019SN/A/*
26019SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
310037SARM gem5 Developers * All rights reserved.
47102SN/A *
57102SN/A * Redistribution and use in source and binary forms, with or without
67102SN/A * modification, are permitted provided that the following conditions are
77102SN/A * met: redistributions of source code must retain the above copyright
87102SN/A * notice, this list of conditions and the following disclaimer;
97102SN/A * redistributions in binary form must reproduce the above copyright
107102SN/A * notice, this list of conditions and the following disclaimer in the
117102SN/A * documentation and/or other materials provided with the distribution;
127102SN/A * neither the name of the copyright holders nor the names of its
137102SN/A * contributors may be used to endorse or promote products derived from
147102SN/A * this software without specific prior written permission.
157102SN/A *
166019SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176019SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186019SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196019SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206019SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216019SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226019SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236019SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246019SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256019SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266019SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276019SN/A *
286019SN/A * Authors: Nathan Binkert
296019SN/A */
306019SN/A
316019SN/A#if defined(__APPLE__)
326019SN/A#define _GLIBCPP_USE_C99 1
336019SN/A#endif
346019SN/A
356019SN/A#if defined(__sun)
366019SN/A#include <math.h>
376019SN/A#endif
386019SN/A
396019SN/A#include <iostream>
406019SN/A#include <sstream>
417102SN/A#include <fstream>
426019SN/A#include <string>
4310611SAndreas.Sandberg@ARM.com
4410611SAndreas.Sandberg@ARM.com#include "base/misc.hh"
4510611SAndreas.Sandberg@ARM.com#include "base/statistics.hh"
4610611SAndreas.Sandberg@ARM.com#include "base/stats/statdb.hh"
4710611SAndreas.Sandberg@ARM.com#include "base/stats/text.hh"
4810611SAndreas.Sandberg@ARM.com#include "base/stats/visit.hh"
4910611SAndreas.Sandberg@ARM.com
5010611SAndreas.Sandberg@ARM.comusing namespace std;
5110611SAndreas.Sandberg@ARM.com
5210611SAndreas.Sandberg@ARM.com#ifndef NAN
5310611SAndreas.Sandberg@ARM.comfloat __nan();
5410037SARM gem5 Developers/** 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 StatData &data)
147{
148    if (!(data.flags & print))
149        return true;
150
151    if (data.prereq && data.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    int _size = vec.size();
243    Result _total = 0.0;
244
245    if (flags & (pdf | cdf)) {
246        for (int 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 (int 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 (int 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 (int 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    int 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 (int 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
451    if (!compat) {
452        for (int i = 0; i < size; ++i) {
453            stringstream namestr;
454            namestr << name;
455
456            Counter low = i * bucket_size + min;
457            Counter high = ::min(low + bucket_size, max);
458            namestr << low;
459            if (low < high)
460                namestr << "-" << high;
461
462            print.name = namestr.str();
463            print.value = vec[i];
464            if (total) {
465                print.pdf = vec[i] / total;
466                print.cdf += print.pdf;
467            }
468            print(stream);
469        }
470
471    } else {
472        Counter _min;
473        Result _pdf;
474        Result _cdf = 0.0;
475
476        print.flags = flags | __substat;
477
478        for (int i = 0; i < size; ++i) {
479            if ((flags & nozero && vec[i] == 0.0) ||
480                (flags & nonan && isnan(vec[i])))
481                continue;
482
483            _min = i * bucket_size + min;
484            _pdf = vec[i] / total * 100.0;
485            _cdf += _pdf;
486
487
488            print.name = ValueToString(_min, 0, compat);
489            print.value = vec[i];
490            print.pdf = (flags & pdf) ? _pdf : NAN;
491            print.cdf = (flags & cdf) ? _cdf : NAN;
492            print(stream);
493        }
494
495        print.flags = flags;
496    }
497
498    if (!compat || overflow > 0.0) {
499        print.name = base + "overflows";
500        print.value = overflow;
501        if (!compat && total) {
502            print.pdf = overflow / total;
503            print.cdf += print.pdf;
504        } else {
505            print.pdf = NAN;
506            print.cdf = NAN;
507        }
508        print(stream);
509    }
510
511    print.pdf = NAN;
512    print.cdf = NAN;
513
514    if (!compat) {
515        print.name = base + "total";
516        print.value = total;
517        print(stream);
518    }
519
520    print.name = base + "max_value";
521    print.value = max_val;
522    print(stream);
523
524    if (!compat && samples != 0) {
525        print.name = base + "mean";
526        print.value = sum / samples;
527        print(stream);
528
529        print.name = base + "stdev";
530        print.value = sqrt((samples * squares - sum * sum) /
531                           (samples * (samples - 1.0)));
532        print(stream);
533    }
534
535    if (compat)
536        ccprintf(stream, "%send_dist\n\n", base);
537}
538
539void
540Text::visit(const ScalarData &data)
541{
542    if (noOutput(data))
543        return;
544
545    ScalarPrint print;
546    print.value = data.result();
547    print.name = data.name;
548    print.desc = data.desc;
549    print.flags = data.flags;
550    print.compat = compat;
551    print.descriptions = descriptions;
552    print.precision = data.precision;
553    print.pdf = NAN;
554    print.cdf = NAN;
555
556    print(*stream);
557}
558
559void
560Text::visit(const VectorData &data)
561{
562    if (noOutput(data))
563        return;
564
565    int size = data.size();
566    VectorPrint print;
567
568    print.name = data.name;
569    print.desc = data.desc;
570    print.flags = data.flags;
571    print.compat = compat;
572    print.descriptions = descriptions;
573    print.precision = data.precision;
574    print.vec = data.result();
575    print.total = data.total();
576
577    if (!data.subnames.empty()) {
578        for (int i = 0; i < size; ++i) {
579            if (!data.subnames[i].empty()) {
580                print.subnames = data.subnames;
581                print.subnames.resize(size);
582                for (int i = 0; i < size; ++i) {
583                    if (!data.subnames[i].empty() &&
584                        !data.subdescs[i].empty()) {
585                        print.subdescs = data.subdescs;
586                        print.subdescs.resize(size);
587                        break;
588                    }
589                }
590                break;
591            }
592        }
593    }
594
595    print(*stream);
596}
597
598void
599Text::visit(const Vector2dData &data)
600{
601    if (noOutput(data))
602        return;
603
604    bool havesub = false;
605    VectorPrint print;
606
607    print.subnames = data.y_subnames;
608    print.flags = data.flags;
609    print.compat = compat;
610    print.descriptions = descriptions;
611    print.precision = data.precision;
612
613    if (!data.subnames.empty()) {
614        for (int i = 0; i < data.x; ++i)
615            if (!data.subnames[i].empty())
616                havesub = true;
617    }
618
619    VResult tot_vec(data.y);
620    Result super_total = 0.0;
621    for (int i = 0; i < data.x; ++i) {
622        if (havesub && (i >= data.subnames.size() || data.subnames[i].empty()))
623            continue;
624
625        int iy = i * data.y;
626        VResult yvec(data.y);
627
628        Result total = 0.0;
629        for (int j = 0; j < data.y; ++j) {
630            yvec[j] = data.cvec[iy + j];
631            tot_vec[j] += yvec[j];
632            total += yvec[j];
633            super_total += yvec[j];
634        }
635
636        print.name = data.name + "_" + (havesub ? data.subnames[i] : to_string(i));
637        print.desc = data.desc;
638        print.vec = yvec;
639        print.total = total;
640        print(*stream);
641    }
642
643    if ((data.flags & ::Stats::total) && (data.x > 1)) {
644        print.name = data.name;
645        print.desc = data.desc;
646        print.vec = tot_vec;
647        print.total = super_total;
648        print(*stream);
649    }
650}
651
652void
653Text::visit(const DistData &data)
654{
655    if (noOutput(data))
656        return;
657
658    DistPrint print;
659
660    print.name = data.name;
661    print.desc = data.desc;
662    print.flags = data.flags;
663    print.compat = compat;
664    print.descriptions = descriptions;
665    print.precision = data.precision;
666
667    print.min_val = data.data.min_val;
668    print.max_val = data.data.max_val;
669    print.underflow = data.data.underflow;
670    print.overflow = data.data.overflow;
671    print.vec.resize(data.data.cvec.size());
672    for (int i = 0; i < print.vec.size(); ++i)
673        print.vec[i] = (Result)data.data.cvec[i];
674    print.sum = data.data.sum;
675    print.squares = data.data.squares;
676    print.samples = data.data.samples;
677
678    print.min = data.data.min;
679    print.max = data.data.max;
680    print.bucket_size = data.data.bucket_size;
681    print.size = data.data.size;
682    print.fancy = data.data.fancy;
683
684    print(*stream);
685}
686
687void
688Text::visit(const VectorDistData &data)
689{
690    if (noOutput(data))
691        return;
692
693    for (int i = 0; i < data.size(); ++i) {
694        DistPrint print;
695
696        print.name = data.name +
697            (data.subnames[i].empty() ? ("_" + to_string(i)) : data.subnames[i]);
698        print.desc = data.subdescs[i].empty() ? data.desc : data.subdescs[i];
699        print.flags = data.flags;
700        print.compat = compat;
701        print.descriptions = descriptions;
702        print.precision = data.precision;
703
704        print.min_val = data.data[i].min_val;
705        print.max_val = data.data[i].max_val;
706        print.underflow = data.data[i].underflow;
707        print.overflow = data.data[i].overflow;
708        print.vec.resize(data.data[i].cvec.size());
709        for (int j = 0; j < print.vec.size(); ++j)
710            print.vec[j] = (Result)data.data[i].cvec[j];
711        print.sum = data.data[i].sum;
712        print.squares = data.data[i].squares;
713        print.samples = data.data[i].samples;
714
715        print.min = data.data[i].min;
716        print.max = data.data[i].max;
717        print.bucket_size = data.data[i].bucket_size;
718        print.size = data.data[i].size;
719        print.fancy = data.data[i].fancy;
720
721        print(*stream);
722    }
723}
724
725void
726Text::visit(const FormulaData &data)
727{
728    visit((const VectorData &)data);
729}
730
731bool
732initText(const string &filename, bool desc, bool compat)
733{
734    static Text text;
735    static bool connected = false;
736
737    if (connected)
738        return false;
739
740    extern list<Output *> OutputList;
741
742    text.open(*simout.find(filename));
743    text.descriptions = desc;
744    text.compat = compat;
745    OutputList.push_back(&text);
746    connected = true;
747
748    return true;
749}
750
751
752/* namespace Stats */ }
753