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