text.cc revision 6125:3bbbdd324a60
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    Counter min;
355    Counter max;
356    Counter bucket_size;
357    size_type size;
358    bool fancy;
359
360    const DistData &data;
361
362    DistPrint(const Text *text, const DistInfoBase &info);
363    DistPrint(const Text *text, const VectorDistInfoBase &info, int i);
364    void init(const Text *text, const Info &info, const DistParams *params);
365    void operator()(ostream &stream) const;
366};
367
368DistPrint::DistPrint(const Text *text, const DistInfoBase &info)
369    : data(info.data)
370{
371    init(text, info, safe_cast<const DistParams *>(info.storageParams));
372}
373
374DistPrint::DistPrint(const Text *text, const VectorDistInfoBase &info, int i)
375    : data(info.data[i])
376{
377    init(text, info, safe_cast<const DistParams *>(info.storageParams));
378
379    name = info.name + "_" +
380        (info.subnames[i].empty() ? (to_string(i)) : info.subnames[i]);
381
382    if (!info.subdescs[i].empty())
383        desc = info.subdescs[i];
384}
385
386void
387DistPrint::init(const Text *text, const Info &info, const DistParams *params)
388{
389    name = info.name;
390    desc = info.desc;
391    flags = info.flags;
392    precision = info.precision;
393    compat = text->compat;
394    descriptions = text->descriptions;
395
396    fancy = params->fancy;
397    min = params->min;
398    max = params->max;
399    bucket_size = params->bucket_size;
400    size = params->buckets;
401}
402
403void
404DistPrint::operator()(ostream &stream) const
405{
406    Result stdev = NAN;
407    if (data.samples)
408        stdev = sqrt((data.samples * data.squares - data.sum * data.sum) /
409                     (data.samples * (data.samples - 1.0)));
410
411    if (fancy) {
412        ScalarPrint print;
413        string base = name + (compat ? "_" : "::");
414
415        print.precision = precision;
416        print.flags = flags;
417        print.compat = compat;
418        print.descriptions = descriptions;
419        print.desc = desc;
420        print.pdf = NAN;
421        print.cdf = NAN;
422
423        print.name = base + "mean";
424        print.value = data.samples ? data.sum / data.samples : NAN;
425        print(stream);
426
427        print.name = base + "stdev";
428        print.value = stdev;
429        print(stream);
430
431        print.name = "**Ignore: " + base + "TOT";
432        print.value = data.samples;
433        print(stream);
434        return;
435    }
436
437    assert(size == data.cvec.size());
438
439    Result total = 0.0;
440
441    total += data.underflow;
442    for (off_type i = 0; i < size; ++i)
443        total += data.cvec[i];
444    total += data.overflow;
445
446    string base = name + (compat ? "." : "::");
447
448    ScalarPrint print;
449    print.desc = compat ? "" : desc;
450    print.flags = flags;
451    print.compat = compat;
452    print.descriptions = descriptions;
453    print.precision = precision;
454    print.pdf = NAN;
455    print.cdf = NAN;
456
457    if (compat) {
458        ccprintf(stream, "%-42s", base + "start_dist");
459        if (descriptions && !desc.empty())
460            ccprintf(stream, "                     # %s", desc);
461        stream << endl;
462    }
463
464    print.name = base + "samples";
465    print.value = data.samples;
466    print(stream);
467
468    print.name = base + "min_value";
469    print.value = data.min_val;
470    print(stream);
471
472    if (!compat || data.underflow > 0.0) {
473        print.name = base + "underflows";
474        print.value = data.underflow;
475        if (!compat && total) {
476            print.pdf = data.underflow / total;
477            print.cdf += print.pdf;
478        }
479        print(stream);
480    }
481
482    if (!compat) {
483        for (off_type i = 0; i < size; ++i) {
484            stringstream namestr;
485            namestr << base;
486
487            Counter low = i * bucket_size + min;
488            Counter high = ::min(low + bucket_size, max);
489            namestr << low;
490            if (low < high)
491                namestr << "-" << high;
492
493            print.name = namestr.str();
494            print.value = data.cvec[i];
495            if (total) {
496                print.pdf = data.cvec[i] / total;
497                print.cdf += print.pdf;
498            }
499            print(stream);
500        }
501    } else {
502        Counter _min;
503        Result _pdf;
504        Result _cdf = 0.0;
505
506        print.flags = flags | __substat;
507
508        for (off_type i = 0; i < size; ++i) {
509            if ((flags & nozero && data.cvec[i] == 0.0) ||
510                (flags & nonan && isnan(data.cvec[i])))
511                continue;
512
513            _min = i * bucket_size + min;
514            _pdf = data.cvec[i] / total * 100.0;
515            _cdf += _pdf;
516
517
518            print.name = ValueToString(_min, 0, compat);
519            print.value = data.cvec[i];
520            print.pdf = (flags & pdf) ? _pdf : NAN;
521            print.cdf = (flags & cdf) ? _cdf : NAN;
522            print(stream);
523        }
524
525        print.flags = flags;
526    }
527
528    if (!compat || data.overflow > 0.0) {
529        print.name = base + "overflows";
530        print.value = data.overflow;
531        if (!compat && total) {
532            print.pdf = data.overflow / total;
533            print.cdf += print.pdf;
534        } else {
535            print.pdf = NAN;
536            print.cdf = NAN;
537        }
538        print(stream);
539    }
540
541    print.pdf = NAN;
542    print.cdf = NAN;
543
544    if (!compat) {
545        print.name = base + "total";
546        print.value = total;
547        print(stream);
548    }
549
550    print.name = base + "max_value";
551    print.value = data.max_val;
552    print(stream);
553
554    if (!compat && data.samples != 0) {
555        print.name = base + "mean";
556        print.value = data.sum / data.samples;
557        print(stream);
558
559        print.name = base + "stdev";
560        print.value = stdev;
561        print(stream);
562    }
563
564    if (compat)
565        ccprintf(stream, "%send_dist\n\n", base);
566}
567
568void
569Text::visit(const ScalarInfoBase &info)
570{
571    if (noOutput(info))
572        return;
573
574    ScalarPrint print;
575    print.value = info.result();
576    print.name = info.name;
577    print.desc = info.desc;
578    print.flags = info.flags;
579    print.compat = compat;
580    print.descriptions = descriptions;
581    print.precision = info.precision;
582    print.pdf = NAN;
583    print.cdf = NAN;
584
585    print(*stream);
586}
587
588void
589Text::visit(const VectorInfoBase &info)
590{
591    if (noOutput(info))
592        return;
593
594    size_type size = info.size();
595    VectorPrint print;
596
597    print.name = info.name;
598    print.desc = info.desc;
599    print.flags = info.flags;
600    print.compat = compat;
601    print.descriptions = descriptions;
602    print.precision = info.precision;
603    print.vec = info.result();
604    print.total = info.total();
605
606    if (!info.subnames.empty()) {
607        for (off_type i = 0; i < size; ++i) {
608            if (!info.subnames[i].empty()) {
609                print.subnames = info.subnames;
610                print.subnames.resize(size);
611                for (off_type i = 0; i < size; ++i) {
612                    if (!info.subnames[i].empty() &&
613                        !info.subdescs[i].empty()) {
614                        print.subdescs = info.subdescs;
615                        print.subdescs.resize(size);
616                        break;
617                    }
618                }
619                break;
620            }
621        }
622    }
623
624    print(*stream);
625}
626
627void
628Text::visit(const Vector2dInfoBase &info)
629{
630    if (noOutput(info))
631        return;
632
633    bool havesub = false;
634    VectorPrint print;
635
636    print.subnames = info.y_subnames;
637    print.flags = info.flags;
638    print.compat = compat;
639    print.descriptions = descriptions;
640    print.precision = info.precision;
641
642    if (!info.subnames.empty()) {
643        for (off_type i = 0; i < info.x; ++i)
644            if (!info.subnames[i].empty())
645                havesub = true;
646    }
647
648    VResult tot_vec(info.y);
649    Result super_total = 0.0;
650    for (off_type i = 0; i < info.x; ++i) {
651        if (havesub && (i >= info.subnames.size() || info.subnames[i].empty()))
652            continue;
653
654        off_type iy = i * info.y;
655        VResult yvec(info.y);
656
657        Result total = 0.0;
658        for (off_type j = 0; j < info.y; ++j) {
659            yvec[j] = info.cvec[iy + j];
660            tot_vec[j] += yvec[j];
661            total += yvec[j];
662            super_total += yvec[j];
663        }
664
665        print.name = info.name + "_" +
666            (havesub ? info.subnames[i] : to_string(i));
667        print.desc = info.desc;
668        print.vec = yvec;
669        print.total = total;
670        print(*stream);
671    }
672
673    if ((info.flags & ::Stats::total) && (info.x > 1)) {
674        print.name = info.name;
675        print.desc = info.desc;
676        print.vec = tot_vec;
677        print.total = super_total;
678        print(*stream);
679    }
680}
681
682void
683Text::visit(const DistInfoBase &info)
684{
685    if (noOutput(info))
686        return;
687
688    DistPrint print(this, info);
689    print(*stream);
690}
691
692void
693Text::visit(const VectorDistInfoBase &info)
694{
695    if (noOutput(info))
696        return;
697
698    for (off_type i = 0; i < info.size(); ++i) {
699        DistPrint print(this, info, i);
700        print(*stream);
701    }
702}
703
704void
705Text::visit(const FormulaInfoBase &info)
706{
707    visit((const VectorInfoBase &)info);
708}
709
710bool
711initText(const string &filename, bool desc, bool compat)
712{
713    static Text text;
714    static bool connected = false;
715
716    if (connected)
717        return false;
718
719    extern list<Output *> OutputList;
720
721    text.open(*simout.find(filename));
722    text.descriptions = desc;
723    text.compat = compat;
724    OutputList.push_back(&text);
725    connected = true;
726
727    return true;
728}
729
730/* namespace Stats */ }
731