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