text.cc revision 9743:436a74146cbc
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 <cassert>
40#ifdef __SUNPRO_CC
41#include <math.h>
42#endif
43#include <cmath>
44#include <fstream>
45#include <iostream>
46#include <sstream>
47#include <string>
48
49#include "base/stats/info.hh"
50#include "base/stats/text.hh"
51#include "base/cast.hh"
52#include "base/misc.hh"
53#include "base/str.hh"
54
55using namespace std;
56
57#ifndef NAN
58float __nan();
59/** Define Not a number. */
60#define NAN (__nan())
61/** Need to define __nan() */
62#define __M5_NAN
63#endif
64
65#ifdef __M5_NAN
66float
67__nan()
68{
69    union {
70        uint32_t ui;
71        float f;
72    } nan;
73
74    nan.ui = 0x7fc00000;
75    return nan.f;
76}
77#endif
78
79namespace Stats {
80
81std::list<Info *> &statsList();
82
83Text::Text()
84    : mystream(false), stream(NULL), descriptions(false)
85{
86}
87
88Text::Text(std::ostream &stream)
89    : mystream(false), stream(NULL), descriptions(false)
90{
91    open(stream);
92}
93
94Text::Text(const std::string &file)
95    : mystream(false), stream(NULL), descriptions(false)
96{
97    open(file);
98}
99
100
101Text::~Text()
102{
103    if (mystream) {
104        assert(stream);
105        delete stream;
106    }
107}
108
109void
110Text::open(std::ostream &_stream)
111{
112    if (stream)
113        panic("stream already set!");
114
115    mystream = false;
116    stream = &_stream;
117    if (!valid())
118        fatal("Unable to open output stream for writing\n");
119}
120
121void
122Text::open(const std::string &file)
123{
124    if (stream)
125        panic("stream already set!");
126
127    mystream = true;
128    stream = new ofstream(file.c_str(), ios::trunc);
129    if (!valid())
130        fatal("Unable to open statistics file for writing\n");
131}
132
133bool
134Text::valid() const
135{
136    return stream != NULL && stream->good();
137}
138
139void
140Text::begin()
141{
142    ccprintf(*stream, "\n---------- Begin Simulation Statistics ----------\n");
143}
144
145void
146Text::end()
147{
148    ccprintf(*stream, "\n---------- End Simulation Statistics   ----------\n");
149    stream->flush();
150}
151
152bool
153Text::noOutput(const Info &info)
154{
155    if (!info.flags.isSet(display))
156        return true;
157
158    if (info.prereq && info.prereq->zero())
159        return true;
160
161    return false;
162}
163
164string
165ValueToString(Result value, int precision)
166{
167    stringstream val;
168
169    if (!std::isnan(value)) {
170        if (precision != -1)
171            val.precision(precision);
172        else if (value == rint(value))
173            val.precision(0);
174
175        val.unsetf(ios::showpoint);
176        val.setf(ios::fixed);
177        val << value;
178    } else {
179        val << "nan";
180    }
181
182    return val.str();
183}
184
185struct ScalarPrint
186{
187    Result value;
188    string name;
189    string desc;
190    Flags flags;
191    bool descriptions;
192    int precision;
193    Result pdf;
194    Result cdf;
195
196    void update(Result val, Result total);
197    void operator()(ostream &stream, bool oneLine = false) const;
198};
199
200void
201ScalarPrint::update(Result val, Result total)
202{
203    value = val;
204    if (total) {
205        pdf = val / total;
206        cdf += pdf;
207    }
208}
209
210void
211ScalarPrint::operator()(ostream &stream, bool oneLine) const
212{
213    if ((flags.isSet(nozero) && value == 0.0) ||
214        (flags.isSet(nonan) && std::isnan(value)))
215        return;
216
217    stringstream pdfstr, cdfstr;
218
219    if (!std::isnan(pdf))
220        ccprintf(pdfstr, "%.2f%%", pdf * 100.0);
221
222    if (!std::isnan(cdf))
223        ccprintf(cdfstr, "%.2f%%", cdf * 100.0);
224
225    if (oneLine) {
226        ccprintf(stream, " |%12s %10s %10s",
227                 ValueToString(value, precision), pdfstr.str(), cdfstr.str());
228    } else {
229        ccprintf(stream, "%-40s %12s %10s %10s", name,
230                 ValueToString(value, precision), pdfstr.str(), cdfstr.str());
231
232        if (descriptions) {
233            if (!desc.empty())
234                ccprintf(stream, " # %s", desc);
235        }
236        stream << endl;
237    }
238}
239
240struct VectorPrint
241{
242    string name;
243    string separatorString;
244    string desc;
245    vector<string> subnames;
246    vector<string> subdescs;
247    Flags flags;
248    bool descriptions;
249    int precision;
250    VResult vec;
251    Result total;
252
253    void operator()(ostream &stream) const;
254};
255
256void
257VectorPrint::operator()(std::ostream &stream) const
258{
259    size_type _size = vec.size();
260    Result _total = 0.0;
261
262    if (flags.isSet(pdf | cdf)) {
263        for (off_type i = 0; i < _size; ++i) {
264            _total += vec[i];
265        }
266    }
267
268    string base = name + separatorString;
269
270    ScalarPrint print;
271    print.name = name;
272    print.desc = desc;
273    print.precision = precision;
274    print.descriptions = descriptions;
275    print.flags = flags;
276    print.pdf = _total ? 0.0 : NAN;
277    print.cdf = _total ? 0.0 : NAN;
278
279    bool havesub = !subnames.empty();
280
281    if (_size == 1) {
282        print.value = vec[0];
283        print(stream);
284        return;
285    }
286
287    if ((!flags.isSet(nozero)) || (total != 0)) {
288        if (flags.isSet(oneline)) {
289            ccprintf(stream, "%-40s", name);
290            print.flags = print.flags & (~nozero);
291        }
292
293        for (off_type i = 0; i < _size; ++i) {
294            if (havesub && (i >= subnames.size() || subnames[i].empty()))
295                continue;
296
297            print.name = base + (havesub ? subnames[i] : to_string(i));
298            print.desc = subdescs.empty() ? desc : subdescs[i];
299
300            print.update(vec[i], _total);
301            print(stream, flags.isSet(oneline));
302        }
303
304        if (flags.isSet(oneline)) {
305            if (descriptions) {
306                if (!desc.empty())
307                    ccprintf(stream, " # %s", desc);
308            }
309
310            stream << endl;
311        }
312    }
313
314    if (flags.isSet(::Stats::total)) {
315        print.pdf = NAN;
316        print.cdf = NAN;
317        print.name = base + "total";
318        print.desc = desc;
319        print.value = total;
320        print(stream);
321    }
322
323    if (flags.isSet(oneline) && ((!flags.isSet(nozero)) || (total != 0))) {
324        stream << endl;
325    }
326}
327
328struct DistPrint
329{
330    string name;
331    string separatorString;
332    string desc;
333    Flags flags;
334    bool descriptions;
335    int precision;
336
337    const DistData &data;
338
339    DistPrint(const Text *text, const DistInfo &info);
340    DistPrint(const Text *text, const VectorDistInfo &info, int i);
341    void init(const Text *text, const Info &info);
342    void operator()(ostream &stream) const;
343};
344
345DistPrint::DistPrint(const Text *text, const DistInfo &info)
346    : data(info.data)
347{
348    init(text, info);
349}
350
351DistPrint::DistPrint(const Text *text, const VectorDistInfo &info, int i)
352    : data(info.data[i])
353{
354    init(text, info);
355
356    name = info.name + "_" +
357        (info.subnames[i].empty() ? (to_string(i)) : info.subnames[i]);
358
359    if (!info.subdescs[i].empty())
360        desc = info.subdescs[i];
361}
362
363void
364DistPrint::init(const Text *text, const Info &info)
365{
366    name = info.name;
367    separatorString = info.separatorString;
368    desc = info.desc;
369    flags = info.flags;
370    precision = info.precision;
371    descriptions = text->descriptions;
372}
373
374void
375DistPrint::operator()(ostream &stream) const
376{
377    string base = name + separatorString;
378
379    ScalarPrint print;
380    print.precision = precision;
381    print.flags = flags;
382    print.descriptions = descriptions;
383    print.desc = desc;
384    print.pdf = NAN;
385    print.cdf = NAN;
386
387    print.name = base + "samples";
388    print.value = data.samples;
389    print(stream);
390
391    print.name = base + "mean";
392    print.value = data.samples ? data.sum / data.samples : NAN;
393    print(stream);
394
395    if (data.type == Hist) {
396        print.name = base + "gmean";
397        print.value = data.samples ? exp(data.logs / data.samples) : NAN;
398        print(stream);
399    }
400
401    Result stdev = NAN;
402    if (data.samples)
403        stdev = sqrt((data.samples * data.squares - data.sum * data.sum) /
404                     (data.samples * (data.samples - 1.0)));
405    print.name = base + "stdev";
406    print.value = stdev;
407    print(stream);
408
409    if (data.type == Deviation)
410        return;
411
412    size_t size = data.cvec.size();
413
414    Result total = 0.0;
415    if (data.type == Dist && data.underflow != NAN)
416        total += data.underflow;
417    for (off_type i = 0; i < size; ++i)
418        total += data.cvec[i];
419    if (data.type == Dist && data.overflow != NAN)
420        total += data.overflow;
421
422    if (total) {
423        print.pdf = 0.0;
424        print.cdf = 0.0;
425    }
426
427    if (data.type == Dist && data.underflow != NAN) {
428        print.name = base + "underflows";
429        print.update(data.underflow, total);
430        print(stream);
431    }
432
433    for (off_type i = 0; i < size; ++i) {
434        stringstream namestr;
435        namestr << base;
436
437        Counter low = i * data.bucket_size + data.min;
438        Counter high = ::min(low + data.bucket_size - 1.0, data.max);
439        namestr << low;
440        if (low < high)
441            namestr << "-" << high;
442
443        print.name = namestr.str();
444        print.update(data.cvec[i], total);
445        print(stream);
446    }
447
448    if (data.type == Dist && data.overflow != NAN) {
449        print.name = base + "overflows";
450        print.update(data.overflow, total);
451        print(stream);
452    }
453
454    print.pdf = NAN;
455    print.cdf = NAN;
456
457    if (data.type == Dist && data.min_val != NAN) {
458        print.name = base + "min_value";
459        print.value = data.min_val;
460        print(stream);
461    }
462
463    if (data.type == Dist && data.max_val != NAN) {
464        print.name = base + "max_value";
465        print.value = data.max_val;
466        print(stream);
467    }
468
469    print.name = base + "total";
470    print.value = total;
471    print(stream);
472}
473
474void
475Text::visit(const ScalarInfo &info)
476{
477    if (noOutput(info))
478        return;
479
480    ScalarPrint print;
481    print.value = info.result();
482    print.name = info.name;
483    print.desc = info.desc;
484    print.flags = info.flags;
485    print.descriptions = descriptions;
486    print.precision = info.precision;
487    print.pdf = NAN;
488    print.cdf = NAN;
489
490    print(*stream);
491}
492
493void
494Text::visit(const VectorInfo &info)
495{
496    if (noOutput(info))
497        return;
498
499    size_type size = info.size();
500    VectorPrint print;
501
502    print.name = info.name;
503    print.separatorString = info.separatorString;
504    print.desc = info.desc;
505    print.flags = info.flags;
506    print.descriptions = descriptions;
507    print.precision = info.precision;
508    print.vec = info.result();
509    print.total = info.total();
510
511    if (!info.subnames.empty()) {
512        for (off_type i = 0; i < size; ++i) {
513            if (!info.subnames[i].empty()) {
514                print.subnames = info.subnames;
515                print.subnames.resize(size);
516                for (off_type i = 0; i < size; ++i) {
517                    if (!info.subnames[i].empty() &&
518                        !info.subdescs[i].empty()) {
519                        print.subdescs = info.subdescs;
520                        print.subdescs.resize(size);
521                        break;
522                    }
523                }
524                break;
525            }
526        }
527    }
528
529    print(*stream);
530}
531
532void
533Text::visit(const Vector2dInfo &info)
534{
535    if (noOutput(info))
536        return;
537
538    bool havesub = false;
539    VectorPrint print;
540
541    if (!info.y_subnames.empty()) {
542        for (off_type i = 0; i < info.y; ++i) {
543            if (!info.y_subnames[i].empty()) {
544                print.subnames = info.y_subnames;
545            }
546            break;
547        }
548    }
549    print.flags = info.flags;
550    print.separatorString = info.separatorString;
551    print.descriptions = descriptions;
552    print.precision = info.precision;
553
554    if (!info.subnames.empty()) {
555        for (off_type i = 0; i < info.x; ++i)
556            if (!info.subnames[i].empty())
557                havesub = true;
558    }
559
560    VResult tot_vec(info.y);
561    Result super_total = 0.0;
562    for (off_type i = 0; i < info.x; ++i) {
563        if (havesub && (i >= info.subnames.size() || info.subnames[i].empty()))
564            continue;
565
566        off_type iy = i * info.y;
567        VResult yvec(info.y);
568
569        Result total = 0.0;
570        for (off_type j = 0; j < info.y; ++j) {
571            yvec[j] = info.cvec[iy + j];
572            tot_vec[j] += yvec[j];
573            total += yvec[j];
574            super_total += yvec[j];
575        }
576
577        print.name = info.name + "_" +
578            (havesub ? info.subnames[i] : to_string(i));
579        print.desc = info.desc;
580        print.vec = yvec;
581        print.total = total;
582        print(*stream);
583    }
584
585    if (info.flags.isSet(::Stats::total) && (info.x > 1)) {
586        print.name = info.name;
587        print.desc = info.desc;
588        print.vec = tot_vec;
589        print.total = super_total;
590        print(*stream);
591    }
592}
593
594void
595Text::visit(const DistInfo &info)
596{
597    if (noOutput(info))
598        return;
599
600    DistPrint print(this, info);
601    print(*stream);
602}
603
604void
605Text::visit(const VectorDistInfo &info)
606{
607    if (noOutput(info))
608        return;
609
610    for (off_type i = 0; i < info.size(); ++i) {
611        DistPrint print(this, info, i);
612        print(*stream);
613    }
614}
615
616void
617Text::visit(const FormulaInfo &info)
618{
619    visit((const VectorInfo &)info);
620}
621
622/*
623  This struct implements the output methods for the sparse
624  histogram stat
625*/
626struct SparseHistPrint
627{
628    string name;
629    string separatorString;
630    string desc;
631    Flags flags;
632    bool descriptions;
633    int precision;
634
635    const SparseHistData &data;
636
637    SparseHistPrint(const Text *text, const SparseHistInfo &info);
638    void init(const Text *text, const Info &info);
639    void operator()(ostream &stream) const;
640};
641
642/* Call initialization function */
643SparseHistPrint::SparseHistPrint(const Text *text, const SparseHistInfo &info)
644    : data(info.data)
645{
646    init(text, info);
647}
648
649/* Initialization function */
650void
651SparseHistPrint::init(const Text *text, const Info &info)
652{
653    name = info.name;
654    separatorString = info.separatorString;
655    desc = info.desc;
656    flags = info.flags;
657    precision = info.precision;
658    descriptions = text->descriptions;
659}
660
661/* Grab data from map and write to output stream */
662void
663SparseHistPrint::operator()(ostream &stream) const
664{
665    string base = name + separatorString;
666
667    ScalarPrint print;
668    print.precision = precision;
669    print.flags = flags;
670    print.descriptions = descriptions;
671    print.desc = desc;
672    print.pdf = NAN;
673    print.cdf = NAN;
674
675    print.name = base + "samples";
676    print.value = data.samples;
677    print(stream);
678
679    MCounter::const_iterator it;
680    for (it = data.cmap.begin(); it != data.cmap.end(); it++) {
681        stringstream namestr;
682        namestr << base;
683
684        namestr <<(*it).first;
685        print.name = namestr.str();
686        print.value = (*it).second;
687        print(stream);
688    }
689
690    print.pdf = NAN;
691    print.cdf = NAN;
692
693    print.name = base + "total";
694    print.value = total;
695    print(stream);
696}
697
698void
699Text::visit(const SparseHistInfo &info)
700{
701    if (noOutput(info))
702        return;
703
704    SparseHistPrint print(this, info);
705    print(*stream);
706}
707
708Output *
709initText(const string &filename, bool desc)
710{
711    static Text text;
712    static bool connected = false;
713
714    if (!connected) {
715        ostream *os = simout.find(filename);
716        if (!os)
717            os = simout.create(filename);
718
719        text.open(*os);
720        text.descriptions = desc;
721        connected = true;
722    }
723
724    return &text;
725}
726
727} // namespace Stats
728