text.cc revision 6126:5f32f9e3c65a
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), descriptions(false)
77{
78}
79
80Text::Text(std::ostream &stream)
81    : mystream(false), stream(NULL), descriptions(false)
82{
83    open(stream);
84}
85
86Text::Text(const std::string &file)
87    : mystream(false), stream(NULL), 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)
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 << "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 descriptions;
182    int precision;
183    Result pdf;
184    Result cdf;
185
186    void operator()(ostream &stream) const;
187};
188
189void
190ScalarPrint::operator()(ostream &stream) const
191{
192    if ((flags & nozero && value == 0.0) ||
193        (flags & nonan && isnan(value)))
194        return;
195
196    stringstream pdfstr, cdfstr;
197
198    if (!isnan(pdf))
199        ccprintf(pdfstr, "%.2f%%", pdf * 100.0);
200
201    if (!isnan(cdf))
202        ccprintf(cdfstr, "%.2f%%", cdf * 100.0);
203
204    ccprintf(stream, "%-40s %12s %10s %10s", name,
205             ValueToString(value, precision), pdfstr, cdfstr);
206
207    if (descriptions) {
208        if (!desc.empty())
209            ccprintf(stream, " # %s", desc);
210    }
211    stream << endl;
212}
213
214struct VectorPrint
215{
216    string name;
217    string desc;
218    vector<string> subnames;
219    vector<string> subdescs;
220    StatFlags flags;
221    bool descriptions;
222    int precision;
223    VResult vec;
224    Result total;
225
226    void operator()(ostream &stream) const;
227};
228
229void
230VectorPrint::operator()(std::ostream &stream) const
231{
232    size_type _size = vec.size();
233    Result _total = 0.0;
234
235    if (flags & (pdf | cdf)) {
236        for (off_type i = 0; i < _size; ++i) {
237            _total += vec[i];
238        }
239    }
240
241    string base = name + "::";
242
243    ScalarPrint print;
244    print.name = name;
245    print.desc = desc;
246    print.precision = precision;
247    print.descriptions = descriptions;
248    print.flags = flags;
249    print.pdf = NAN;
250    print.cdf = NAN;
251
252    bool havesub = !subnames.empty();
253
254    if (_size == 1) {
255        print.value = vec[0];
256        print(stream);
257        return;
258    }
259
260    for (off_type i = 0; i < _size; ++i) {
261        if (havesub && (i >= subnames.size() || subnames[i].empty()))
262            continue;
263
264        print.name = base + (havesub ? subnames[i] : to_string(i));
265        print.desc = subdescs.empty() ? desc : subdescs[i];
266        print.value = vec[i];
267
268        if (_total && flags & pdf) {
269            print.pdf = vec[i] / _total;
270            print.cdf += print.pdf;
271        }
272
273        print(stream);
274    }
275
276    if (flags & ::Stats::total) {
277        print.pdf = NAN;
278        print.cdf = NAN;
279        print.name = base + "total";
280        print.desc = desc;
281        print.value = total;
282        print(stream);
283    }
284}
285
286struct DistPrint
287{
288    string name;
289    string desc;
290    StatFlags flags;
291    bool descriptions;
292    int precision;
293
294    Counter min;
295    Counter max;
296    Counter bucket_size;
297    size_type size;
298    bool fancy;
299
300    const DistData &data;
301
302    DistPrint(const Text *text, const DistInfoBase &info);
303    DistPrint(const Text *text, const VectorDistInfoBase &info, int i);
304    void init(const Text *text, const Info &info, const DistParams *params);
305    void operator()(ostream &stream) const;
306};
307
308DistPrint::DistPrint(const Text *text, const DistInfoBase &info)
309    : data(info.data)
310{
311    init(text, info, safe_cast<const DistParams *>(info.storageParams));
312}
313
314DistPrint::DistPrint(const Text *text, const VectorDistInfoBase &info, int i)
315    : data(info.data[i])
316{
317    init(text, info, safe_cast<const DistParams *>(info.storageParams));
318
319    name = info.name + "_" +
320        (info.subnames[i].empty() ? (to_string(i)) : info.subnames[i]);
321
322    if (!info.subdescs[i].empty())
323        desc = info.subdescs[i];
324}
325
326void
327DistPrint::init(const Text *text, const Info &info, const DistParams *params)
328{
329    name = info.name;
330    desc = info.desc;
331    flags = info.flags;
332    precision = info.precision;
333    descriptions = text->descriptions;
334
335    fancy = params->fancy;
336    min = params->min;
337    max = params->max;
338    bucket_size = params->bucket_size;
339    size = params->buckets;
340}
341
342void
343DistPrint::operator()(ostream &stream) const
344{
345    Result stdev = NAN;
346    if (data.samples)
347        stdev = sqrt((data.samples * data.squares - data.sum * data.sum) /
348                     (data.samples * (data.samples - 1.0)));
349
350    if (fancy) {
351        ScalarPrint print;
352        string base = name + "::";
353
354        print.precision = precision;
355        print.flags = flags;
356        print.descriptions = descriptions;
357        print.desc = desc;
358        print.pdf = NAN;
359        print.cdf = NAN;
360
361        print.name = base + "mean";
362        print.value = data.samples ? data.sum / data.samples : NAN;
363        print(stream);
364
365        print.name = base + "stdev";
366        print.value = stdev;
367        print(stream);
368
369        print.name = "**Ignore: " + base + "TOT";
370        print.value = data.samples;
371        print(stream);
372        return;
373    }
374
375    assert(size == data.cvec.size());
376
377    Result total = 0.0;
378
379    total += data.underflow;
380    for (off_type i = 0; i < size; ++i)
381        total += data.cvec[i];
382    total += data.overflow;
383
384    string base = name + "::";
385
386    ScalarPrint print;
387    print.desc = desc;
388    print.flags = flags;
389    print.descriptions = descriptions;
390    print.precision = precision;
391    print.pdf = NAN;
392    print.cdf = NAN;
393
394    print.name = base + "samples";
395    print.value = data.samples;
396    print(stream);
397
398    print.name = base + "min_value";
399    print.value = data.min_val;
400    print(stream);
401
402    print.name = base + "underflows";
403    print.value = data.underflow;
404    if (total) {
405        print.pdf = data.underflow / total;
406        print.cdf += print.pdf;
407    }
408    print(stream);
409
410    for (off_type i = 0; i < size; ++i) {
411        stringstream namestr;
412        namestr << base;
413
414        Counter low = i * bucket_size + min;
415        Counter high = ::min(low + bucket_size, max);
416        namestr << low;
417        if (low < high)
418            namestr << "-" << high;
419
420        print.name = namestr.str();
421        print.value = data.cvec[i];
422        if (total) {
423            print.pdf = data.cvec[i] / total;
424            print.cdf += print.pdf;
425        }
426        print(stream);
427    }
428
429    print.name = base + "overflows";
430    print.value = data.overflow;
431    if (total) {
432        print.pdf = data.overflow / total;
433        print.cdf += print.pdf;
434    } else {
435        print.pdf = NAN;
436        print.cdf = NAN;
437    }
438    print(stream);
439
440    print.pdf = NAN;
441    print.cdf = NAN;
442
443    print.name = base + "total";
444    print.value = total;
445    print(stream);
446
447    print.name = base + "max_value";
448    print.value = data.max_val;
449    print(stream);
450
451    print.name = base + "mean";
452    print.value = data.sum / data.samples;
453    print(stream);
454
455    print.name = base + "stdev";
456    print.value = stdev;
457    print(stream);
458}
459
460void
461Text::visit(const ScalarInfoBase &info)
462{
463    if (noOutput(info))
464        return;
465
466    ScalarPrint print;
467    print.value = info.result();
468    print.name = info.name;
469    print.desc = info.desc;
470    print.flags = info.flags;
471    print.descriptions = descriptions;
472    print.precision = info.precision;
473    print.pdf = NAN;
474    print.cdf = NAN;
475
476    print(*stream);
477}
478
479void
480Text::visit(const VectorInfoBase &info)
481{
482    if (noOutput(info))
483        return;
484
485    size_type size = info.size();
486    VectorPrint print;
487
488    print.name = info.name;
489    print.desc = info.desc;
490    print.flags = info.flags;
491    print.descriptions = descriptions;
492    print.precision = info.precision;
493    print.vec = info.result();
494    print.total = info.total();
495
496    if (!info.subnames.empty()) {
497        for (off_type i = 0; i < size; ++i) {
498            if (!info.subnames[i].empty()) {
499                print.subnames = info.subnames;
500                print.subnames.resize(size);
501                for (off_type i = 0; i < size; ++i) {
502                    if (!info.subnames[i].empty() &&
503                        !info.subdescs[i].empty()) {
504                        print.subdescs = info.subdescs;
505                        print.subdescs.resize(size);
506                        break;
507                    }
508                }
509                break;
510            }
511        }
512    }
513
514    print(*stream);
515}
516
517void
518Text::visit(const Vector2dInfoBase &info)
519{
520    if (noOutput(info))
521        return;
522
523    bool havesub = false;
524    VectorPrint print;
525
526    print.subnames = info.y_subnames;
527    print.flags = info.flags;
528    print.descriptions = descriptions;
529    print.precision = info.precision;
530
531    if (!info.subnames.empty()) {
532        for (off_type i = 0; i < info.x; ++i)
533            if (!info.subnames[i].empty())
534                havesub = true;
535    }
536
537    VResult tot_vec(info.y);
538    Result super_total = 0.0;
539    for (off_type i = 0; i < info.x; ++i) {
540        if (havesub && (i >= info.subnames.size() || info.subnames[i].empty()))
541            continue;
542
543        off_type iy = i * info.y;
544        VResult yvec(info.y);
545
546        Result total = 0.0;
547        for (off_type j = 0; j < info.y; ++j) {
548            yvec[j] = info.cvec[iy + j];
549            tot_vec[j] += yvec[j];
550            total += yvec[j];
551            super_total += yvec[j];
552        }
553
554        print.name = info.name + "_" +
555            (havesub ? info.subnames[i] : to_string(i));
556        print.desc = info.desc;
557        print.vec = yvec;
558        print.total = total;
559        print(*stream);
560    }
561
562    if ((info.flags & ::Stats::total) && (info.x > 1)) {
563        print.name = info.name;
564        print.desc = info.desc;
565        print.vec = tot_vec;
566        print.total = super_total;
567        print(*stream);
568    }
569}
570
571void
572Text::visit(const DistInfoBase &info)
573{
574    if (noOutput(info))
575        return;
576
577    DistPrint print(this, info);
578    print(*stream);
579}
580
581void
582Text::visit(const VectorDistInfoBase &info)
583{
584    if (noOutput(info))
585        return;
586
587    for (off_type i = 0; i < info.size(); ++i) {
588        DistPrint print(this, info, i);
589        print(*stream);
590    }
591}
592
593void
594Text::visit(const FormulaInfoBase &info)
595{
596    visit((const VectorInfoBase &)info);
597}
598
599bool
600initText(const string &filename, bool desc)
601{
602    static Text text;
603    static bool connected = false;
604
605    if (connected)
606        return false;
607
608    extern list<Output *> OutputList;
609
610    text.open(*simout.find(filename));
611    text.descriptions = desc;
612    OutputList.push_back(&text);
613    connected = true;
614
615    return true;
616}
617
618/* namespace Stats */ }
619