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