Deleted Added
sdiff udiff text old ( 11565:9b9116df5e88 ) new ( 11793:ef606668d247 )
full compact
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] : std::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] : std::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() ? (std::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 for (off_type i = 0; i < info.x; ++i) {
592 if (havesub && (i >= info.subnames.size() || info.subnames[i].empty()))
593 continue;
594
595 off_type iy = i * info.y;
596 VResult yvec(info.y);
597
598 Result total = 0.0;
599 for (off_type j = 0; j < info.y; ++j) {
600 yvec[j] = info.cvec[iy + j];
601 tot_vec[j] += yvec[j];
602 total += yvec[j];
603 }
604
605 print.name = info.name + "_" +
606 (havesub ? info.subnames[i] : std::to_string(i));
607 print.desc = info.desc;
608 print.vec = yvec;
609 print.total = total;
610 print(*stream);
611 }
612
613 // Create a subname for printing the total
614 vector<string> total_subname;
615 total_subname.push_back("total");
616
617 if (info.flags.isSet(::Stats::total) && (info.x > 1)) {
618 print.name = info.name;
619 print.subnames = total_subname;
620 print.desc = info.desc;
621 print.vec = VResult(1, info.total());
622 print.flags = print.flags & ~total;
623 print(*stream);
624 }
625}
626
627void
628Text::visit(const DistInfo &info)
629{
630 if (noOutput(info))
631 return;
632
633 DistPrint print(this, info);
634 print(*stream);
635}
636
637void
638Text::visit(const VectorDistInfo &info)
639{
640 if (noOutput(info))
641 return;
642
643 for (off_type i = 0; i < info.size(); ++i) {
644 DistPrint print(this, info, i);
645 print(*stream);
646 }
647}
648
649void
650Text::visit(const FormulaInfo &info)
651{
652 visit((const VectorInfo &)info);
653}
654
655/*
656 This struct implements the output methods for the sparse
657 histogram stat
658*/
659struct SparseHistPrint
660{
661 string name;
662 string separatorString;
663 string desc;
664 Flags flags;
665 bool descriptions;
666 int precision;
667
668 const SparseHistData &data;
669
670 SparseHistPrint(const Text *text, const SparseHistInfo &info);
671 void init(const Text *text, const Info &info);
672 void operator()(ostream &stream) const;
673};
674
675/* Call initialization function */
676SparseHistPrint::SparseHistPrint(const Text *text, const SparseHistInfo &info)
677 : data(info.data)
678{
679 init(text, info);
680}
681
682/* Initialization function */
683void
684SparseHistPrint::init(const Text *text, const Info &info)
685{
686 name = info.name;
687 separatorString = info.separatorString;
688 desc = info.desc;
689 flags = info.flags;
690 precision = info.precision;
691 descriptions = text->descriptions;
692}
693
694/* Grab data from map and write to output stream */
695void
696SparseHistPrint::operator()(ostream &stream) const
697{
698 string base = name + separatorString;
699
700 ScalarPrint print;
701 print.precision = precision;
702 print.flags = flags;
703 print.descriptions = descriptions;
704 print.desc = desc;
705 print.pdf = NAN;
706 print.cdf = NAN;
707
708 print.name = base + "samples";
709 print.value = data.samples;
710 print(stream);
711
712 MCounter::const_iterator it;
713 for (it = data.cmap.begin(); it != data.cmap.end(); it++) {
714 stringstream namestr;
715 namestr << base;
716
717 namestr <<(*it).first;
718 print.name = namestr.str();
719 print.value = (*it).second;
720 print(stream);
721 }
722}
723
724void
725Text::visit(const SparseHistInfo &info)
726{
727 if (noOutput(info))
728 return;
729
730 SparseHistPrint print(this, info);
731 print(*stream);
732}
733
734Output *
735initText(const string &filename, bool desc)
736{
737 static Text text;
738 static bool connected = false;
739
740 if (!connected) {
741 text.open(*simout.findOrCreate(filename)->stream());
742 text.descriptions = desc;
743 connected = true;
744 }
745
746 return &text;
747}
748
749} // namespace Stats