text.cc revision 10374:1813597a92ec
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) && (!oneLine) && 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    bool forceSubnames;
253
254    void operator()(ostream &stream) const;
255};
256
257void
258VectorPrint::operator()(std::ostream &stream) const
259{
260    size_type _size = vec.size();
261    Result _total = 0.0;
262
263    if (flags.isSet(pdf | cdf)) {
264        for (off_type i = 0; i < _size; ++i) {
265            _total += vec[i];
266        }
267    }
268
269    string base = name + separatorString;
270
271    ScalarPrint print;
272    print.name = name;
273    print.desc = desc;
274    print.precision = precision;
275    print.descriptions = descriptions;
276    print.flags = flags;
277    print.pdf = _total ? 0.0 : NAN;
278    print.cdf = _total ? 0.0 : NAN;
279
280    bool havesub = !subnames.empty();
281
282    if (_size == 1) {
283        // If forceSubnames is set, get the first subname (or index in
284        // the case where there are no subnames) and append it to the
285        // base name.
286        if (forceSubnames)
287            print.name = base + (havesub ? subnames[0] : to_string(0));
288        print.value = vec[0];
289        print(stream);
290        return;
291    }
292
293    if ((!flags.isSet(nozero)) || (total != 0)) {
294        if (flags.isSet(oneline)) {
295            ccprintf(stream, "%-40s", name);
296            print.flags = print.flags & (~nozero);
297        }
298
299        for (off_type i = 0; i < _size; ++i) {
300            if (havesub && (i >= subnames.size() || subnames[i].empty()))
301                continue;
302
303            print.name = base + (havesub ? subnames[i] : to_string(i));
304            print.desc = subdescs.empty() ? desc : subdescs[i];
305
306            print.update(vec[i], _total);
307            print(stream, flags.isSet(oneline));
308        }
309
310        if (flags.isSet(oneline)) {
311            if (descriptions) {
312                if (!desc.empty())
313                    ccprintf(stream, " # %s", desc);
314            }
315            stream << endl;
316        }
317    }
318
319    if (flags.isSet(::Stats::total)) {
320        print.pdf = NAN;
321        print.cdf = NAN;
322        print.name = base + "total";
323        print.desc = desc;
324        print.value = total;
325        print(stream);
326    }
327}
328
329struct DistPrint
330{
331    string name;
332    string separatorString;
333    string desc;
334    Flags flags;
335    bool descriptions;
336    int precision;
337
338    const DistData &data;
339
340    DistPrint(const Text *text, const DistInfo &info);
341    DistPrint(const Text *text, const VectorDistInfo &info, int i);
342    void init(const Text *text, const Info &info);
343    void operator()(ostream &stream) const;
344};
345
346DistPrint::DistPrint(const Text *text, const DistInfo &info)
347    : data(info.data)
348{
349    init(text, info);
350}
351
352DistPrint::DistPrint(const Text *text, const VectorDistInfo &info, int i)
353    : data(info.data[i])
354{
355    init(text, info);
356
357    name = info.name + "_" +
358        (info.subnames[i].empty() ? (to_string(i)) : info.subnames[i]);
359
360    if (!info.subdescs[i].empty())
361        desc = info.subdescs[i];
362}
363
364void
365DistPrint::init(const Text *text, const Info &info)
366{
367    name = info.name;
368    separatorString = info.separatorString;
369    desc = info.desc;
370    flags = info.flags;
371    precision = info.precision;
372    descriptions = text->descriptions;
373}
374
375void
376DistPrint::operator()(ostream &stream) const
377{
378    if (flags.isSet(nozero) && data.samples == 0) return;
379    string base = name + separatorString;
380
381    ScalarPrint print;
382    print.precision = precision;
383    print.flags = flags;
384    print.descriptions = descriptions;
385    print.desc = desc;
386    print.pdf = NAN;
387    print.cdf = NAN;
388
389    if (flags.isSet(oneline)) {
390        print.name = base + "bucket_size";
391        print.value = data.bucket_size;
392        print(stream);
393
394        print.name = base + "min_bucket";
395        print.value = data.min;
396        print(stream);
397
398        print.name = base + "max_bucket";
399        print.value = data.max;
400        print(stream);
401    }
402
403    print.name = base + "samples";
404    print.value = data.samples;
405    print(stream);
406
407    print.name = base + "mean";
408    print.value = data.samples ? data.sum / data.samples : NAN;
409    print(stream);
410
411    if (data.type == Hist) {
412        print.name = base + "gmean";
413        print.value = data.samples ? exp(data.logs / data.samples) : NAN;
414        print(stream);
415    }
416
417    Result stdev = NAN;
418    if (data.samples)
419        stdev = sqrt((data.samples * data.squares - data.sum * data.sum) /
420                     (data.samples * (data.samples - 1.0)));
421    print.name = base + "stdev";
422    print.value = stdev;
423    print(stream);
424
425    if (data.type == Deviation)
426        return;
427
428    size_t size = data.cvec.size();
429
430    Result total = 0.0;
431    if (data.type == Dist && data.underflow != NAN)
432        total += data.underflow;
433    for (off_type i = 0; i < size; ++i)
434        total += data.cvec[i];
435    if (data.type == Dist && data.overflow != NAN)
436        total += data.overflow;
437
438    if (total) {
439        print.pdf = 0.0;
440        print.cdf = 0.0;
441    }
442
443    if (data.type == Dist && data.underflow != NAN) {
444        print.name = base + "underflows";
445        print.update(data.underflow, total);
446        print(stream);
447    }
448
449    if (flags.isSet(oneline)) {
450        ccprintf(stream, "%-40s", name);
451    }
452
453    for (off_type i = 0; i < size; ++i) {
454        stringstream namestr;
455        namestr << base;
456
457        Counter low = i * data.bucket_size + data.min;
458        Counter high = ::min(low + data.bucket_size - 1.0, data.max);
459        namestr << low;
460        if (low < high)
461            namestr << "-" << high;
462
463        print.name = namestr.str();
464        print.update(data.cvec[i], total);
465        print(stream, flags.isSet(oneline));
466    }
467
468    if (flags.isSet(oneline)) {
469        if (descriptions) {
470            if (!desc.empty())
471                ccprintf(stream, " # %s", desc);
472        }
473        stream << endl;
474    }
475
476    if (data.type == Dist && data.overflow != NAN) {
477        print.name = base + "overflows";
478        print.update(data.overflow, total);
479        print(stream);
480    }
481
482    print.pdf = NAN;
483    print.cdf = NAN;
484
485    if (data.type == Dist && data.min_val != NAN) {
486        print.name = base + "min_value";
487        print.value = data.min_val;
488        print(stream);
489    }
490
491    if (data.type == Dist && data.max_val != NAN) {
492        print.name = base + "max_value";
493        print.value = data.max_val;
494        print(stream);
495    }
496
497    print.name = base + "total";
498    print.value = total;
499    print(stream);
500}
501
502void
503Text::visit(const ScalarInfo &info)
504{
505    if (noOutput(info))
506        return;
507
508    ScalarPrint print;
509    print.value = info.result();
510    print.name = info.name;
511    print.desc = info.desc;
512    print.flags = info.flags;
513    print.descriptions = descriptions;
514    print.precision = info.precision;
515    print.pdf = NAN;
516    print.cdf = NAN;
517
518    print(*stream);
519}
520
521void
522Text::visit(const VectorInfo &info)
523{
524    if (noOutput(info))
525        return;
526
527    size_type size = info.size();
528    VectorPrint print;
529
530    print.name = info.name;
531    print.separatorString = info.separatorString;
532    print.desc = info.desc;
533    print.flags = info.flags;
534    print.descriptions = descriptions;
535    print.precision = info.precision;
536    print.vec = info.result();
537    print.total = info.total();
538    print.forceSubnames = false;
539
540    if (!info.subnames.empty()) {
541        for (off_type i = 0; i < size; ++i) {
542            if (!info.subnames[i].empty()) {
543                print.subnames = info.subnames;
544                print.subnames.resize(size);
545                for (off_type i = 0; i < size; ++i) {
546                    if (!info.subnames[i].empty() &&
547                        !info.subdescs[i].empty()) {
548                        print.subdescs = info.subdescs;
549                        print.subdescs.resize(size);
550                        break;
551                    }
552                }
553                break;
554            }
555        }
556    }
557
558    print(*stream);
559}
560
561void
562Text::visit(const Vector2dInfo &info)
563{
564    if (noOutput(info))
565        return;
566
567    bool havesub = false;
568    VectorPrint print;
569
570    if (!info.y_subnames.empty()) {
571        for (off_type i = 0; i < info.y; ++i) {
572            if (!info.y_subnames[i].empty()) {
573                print.subnames = info.y_subnames;
574                break;
575            }
576        }
577    }
578    print.flags = info.flags;
579    print.separatorString = info.separatorString;
580    print.descriptions = descriptions;
581    print.precision = info.precision;
582    print.forceSubnames = true;
583
584    if (!info.subnames.empty()) {
585        for (off_type i = 0; i < info.x; ++i)
586            if (!info.subnames[i].empty())
587                havesub = true;
588    }
589
590    VResult tot_vec(info.y);
591    VResult super_total(1, 0.0);
592    for (off_type i = 0; i < info.x; ++i) {
593        if (havesub && (i >= info.subnames.size() || info.subnames[i].empty()))
594            continue;
595
596        off_type iy = i * info.y;
597        VResult yvec(info.y);
598
599        Result total = 0.0;
600        for (off_type j = 0; j < info.y; ++j) {
601            yvec[j] = info.cvec[iy + j];
602            tot_vec[j] += yvec[j];
603            total += yvec[j];
604            super_total[0] += yvec[j];
605        }
606
607        print.name = info.name + "_" +
608            (havesub ? info.subnames[i] : to_string(i));
609        print.desc = info.desc;
610        print.vec = yvec;
611        print.total = total;
612        print(*stream);
613    }
614
615    // Create a subname for printing the total
616    vector<string> total_subname;
617    total_subname.push_back("total");
618
619    if (info.flags.isSet(::Stats::total) && (info.x > 1)) {
620        print.name = info.name;
621        print.subnames = total_subname;
622        print.desc = info.desc;
623        print.vec = super_total;
624        print.flags = print.flags & ~total;
625        print(*stream);
626    }
627}
628
629void
630Text::visit(const DistInfo &info)
631{
632    if (noOutput(info))
633        return;
634
635    DistPrint print(this, info);
636    print(*stream);
637}
638
639void
640Text::visit(const VectorDistInfo &info)
641{
642    if (noOutput(info))
643        return;
644
645    for (off_type i = 0; i < info.size(); ++i) {
646        DistPrint print(this, info, i);
647        print(*stream);
648    }
649}
650
651void
652Text::visit(const FormulaInfo &info)
653{
654    visit((const VectorInfo &)info);
655}
656
657/*
658  This struct implements the output methods for the sparse
659  histogram stat
660*/
661struct SparseHistPrint
662{
663    string name;
664    string separatorString;
665    string desc;
666    Flags flags;
667    bool descriptions;
668    int precision;
669
670    const SparseHistData &data;
671
672    SparseHistPrint(const Text *text, const SparseHistInfo &info);
673    void init(const Text *text, const Info &info);
674    void operator()(ostream &stream) const;
675};
676
677/* Call initialization function */
678SparseHistPrint::SparseHistPrint(const Text *text, const SparseHistInfo &info)
679    : data(info.data)
680{
681    init(text, info);
682}
683
684/* Initialization function */
685void
686SparseHistPrint::init(const Text *text, const Info &info)
687{
688    name = info.name;
689    separatorString = info.separatorString;
690    desc = info.desc;
691    flags = info.flags;
692    precision = info.precision;
693    descriptions = text->descriptions;
694}
695
696/* Grab data from map and write to output stream */
697void
698SparseHistPrint::operator()(ostream &stream) const
699{
700    string base = name + separatorString;
701
702    ScalarPrint print;
703    print.precision = precision;
704    print.flags = flags;
705    print.descriptions = descriptions;
706    print.desc = desc;
707    print.pdf = NAN;
708    print.cdf = NAN;
709
710    print.name = base + "samples";
711    print.value = data.samples;
712    print(stream);
713
714    MCounter::const_iterator it;
715    for (it = data.cmap.begin(); it != data.cmap.end(); it++) {
716        stringstream namestr;
717        namestr << base;
718
719        namestr <<(*it).first;
720        print.name = namestr.str();
721        print.value = (*it).second;
722        print(stream);
723    }
724}
725
726void
727Text::visit(const SparseHistInfo &info)
728{
729    if (noOutput(info))
730        return;
731
732    SparseHistPrint print(this, info);
733    print(*stream);
734}
735
736Output *
737initText(const string &filename, bool desc)
738{
739    static Text text;
740    static bool connected = false;
741
742    if (!connected) {
743        ostream *os = simout.find(filename);
744        if (!os)
745            os = simout.create(filename);
746
747        text.open(*os);
748        text.descriptions = desc;
749        connected = true;
750    }
751
752    return &text;
753}
754
755} // namespace Stats
756