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