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