Make commenting on close namespace brackets consistent.
[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 <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
56 using namespace std;
57
58 #ifndef NAN
59 float __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
67 float
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
80 namespace Stats {
81
82 std::list<Info *> &statsList();
83
84 Text::Text()
85 : mystream(false), stream(NULL), descriptions(false)
86 {
87 }
88
89 Text::Text(std::ostream &stream)
90 : mystream(false), stream(NULL), descriptions(false)
91 {
92 open(stream);
93 }
94
95 Text::Text(const std::string &file)
96 : mystream(false), stream(NULL), descriptions(false)
97 {
98 open(file);
99 }
100
101
102 Text::~Text()
103 {
104 if (mystream) {
105 assert(stream);
106 delete stream;
107 }
108 }
109
110 void
111 Text::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
122 void
123 Text::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
134 bool
135 Text::valid() const
136 {
137 return stream != NULL && stream->good();
138 }
139
140 void
141 Text::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
151 bool
152 Text::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
163 string
164 ValueToString(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
184 struct 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
199 void
200 ScalarPrint::update(Result val, Result total)
201 {
202 value = val;
203 if (total) {
204 pdf = val / total;
205 cdf += pdf;
206 }
207 }
208
209 void
210 ScalarPrint::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
234 struct 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
249 void
250 VectorPrint::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
301 struct DistPrint
302 {
303 string name;
304 string desc;
305 Flags flags;
306 bool descriptions;
307 int precision;
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);
314 void operator()(ostream &stream) const;
315 };
316
317 DistPrint::DistPrint(const Text *text, const DistInfo &info)
318 : data(info.data)
319 {
320 init(text, info);
321 }
322
323 DistPrint::DistPrint(const Text *text, const VectorDistInfo &info, int i)
324 : data(info.data[i])
325 {
326 init(text, info);
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
335 void
336 DistPrint::init(const Text *text, const Info &info)
337 {
338 name = info.name;
339 desc = info.desc;
340 flags = info.flags;
341 precision = info.precision;
342 descriptions = text->descriptions;
343 }
344
345 void
346 DistPrint::operator()(ostream &stream) const
347 {
348 string base = name + "::";
349
350 ScalarPrint print;
351 print.precision = precision;
352 print.flags = flags;
353 print.descriptions = descriptions;
354 print.desc = desc;
355 print.pdf = NAN;
356 print.cdf = NAN;
357
358 print.name = base + "samples";
359 print.value = data.samples;
360 print(stream);
361
362 print.name = base + "mean";
363 print.value = data.samples ? data.sum / data.samples : NAN;
364 print(stream);
365
366 Result stdev = NAN;
367 if (data.samples)
368 stdev = sqrt((data.samples * data.squares - data.sum * data.sum) /
369 (data.samples * (data.samples - 1.0)));
370 print.name = base + "stdev";
371 print.value = stdev;
372 print(stream);
373
374 if (data.type == Deviation)
375 return;
376
377 size_t size = data.cvec.size();
378
379 Result total = 0.0;
380 if (data.underflow != NAN)
381 total += data.underflow;
382 for (off_type i = 0; i < size; ++i)
383 total += data.cvec[i];
384 if (data.overflow != NAN)
385 total += data.overflow;
386
387 if (total) {
388 print.pdf = 0.0;
389 print.cdf = 0.0;
390 }
391
392 if (data.underflow != NAN) {
393 print.name = base + "underflows";
394 print.update(data.underflow, total);
395 print(stream);
396 }
397
398 for (off_type i = 0; i < size; ++i) {
399 stringstream namestr;
400 namestr << base;
401
402 Counter low = i * data.bucket_size + data.min;
403 Counter high = ::min(low + data.bucket_size - 1.0, data.max);
404 namestr << low;
405 if (low < high)
406 namestr << "-" << high;
407
408 print.name = namestr.str();
409 print.update(data.cvec[i], total);
410 print(stream);
411 }
412
413 if (data.overflow != NAN) {
414 print.name = base + "overflows";
415 print.update(data.overflow, total);
416 print(stream);
417 }
418
419 print.pdf = NAN;
420 print.cdf = NAN;
421
422 if (data.min_val != NAN) {
423 print.name = base + "min_value";
424 print.value = data.min_val;
425 print(stream);
426 }
427
428 if (data.max_val != NAN) {
429 print.name = base + "max_value";
430 print.value = data.max_val;
431 print(stream);
432 }
433
434 print.name = base + "total";
435 print.value = total;
436 print(stream);
437 }
438
439 void
440 Text::visit(const ScalarInfo &info)
441 {
442 if (noOutput(info))
443 return;
444
445 ScalarPrint print;
446 print.value = info.result();
447 print.name = info.name;
448 print.desc = info.desc;
449 print.flags = info.flags;
450 print.descriptions = descriptions;
451 print.precision = info.precision;
452 print.pdf = NAN;
453 print.cdf = NAN;
454
455 print(*stream);
456 }
457
458 void
459 Text::visit(const VectorInfo &info)
460 {
461 if (noOutput(info))
462 return;
463
464 size_type size = info.size();
465 VectorPrint print;
466
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.vec = info.result();
473 print.total = info.total();
474
475 if (!info.subnames.empty()) {
476 for (off_type i = 0; i < size; ++i) {
477 if (!info.subnames[i].empty()) {
478 print.subnames = info.subnames;
479 print.subnames.resize(size);
480 for (off_type i = 0; i < size; ++i) {
481 if (!info.subnames[i].empty() &&
482 !info.subdescs[i].empty()) {
483 print.subdescs = info.subdescs;
484 print.subdescs.resize(size);
485 break;
486 }
487 }
488 break;
489 }
490 }
491 }
492
493 print(*stream);
494 }
495
496 void
497 Text::visit(const Vector2dInfo &info)
498 {
499 if (noOutput(info))
500 return;
501
502 bool havesub = false;
503 VectorPrint print;
504
505 print.subnames = info.y_subnames;
506 print.flags = info.flags;
507 print.descriptions = descriptions;
508 print.precision = info.precision;
509
510 if (!info.subnames.empty()) {
511 for (off_type i = 0; i < info.x; ++i)
512 if (!info.subnames[i].empty())
513 havesub = true;
514 }
515
516 VResult tot_vec(info.y);
517 Result super_total = 0.0;
518 for (off_type i = 0; i < info.x; ++i) {
519 if (havesub && (i >= info.subnames.size() || info.subnames[i].empty()))
520 continue;
521
522 off_type iy = i * info.y;
523 VResult yvec(info.y);
524
525 Result total = 0.0;
526 for (off_type j = 0; j < info.y; ++j) {
527 yvec[j] = info.cvec[iy + j];
528 tot_vec[j] += yvec[j];
529 total += yvec[j];
530 super_total += yvec[j];
531 }
532
533 print.name = info.name + "_" +
534 (havesub ? info.subnames[i] : to_string(i));
535 print.desc = info.desc;
536 print.vec = yvec;
537 print.total = total;
538 print(*stream);
539 }
540
541 if (info.flags.isSet(::Stats::total) && (info.x > 1)) {
542 print.name = info.name;
543 print.desc = info.desc;
544 print.vec = tot_vec;
545 print.total = super_total;
546 print(*stream);
547 }
548 }
549
550 void
551 Text::visit(const DistInfo &info)
552 {
553 if (noOutput(info))
554 return;
555
556 DistPrint print(this, info);
557 print(*stream);
558 }
559
560 void
561 Text::visit(const VectorDistInfo &info)
562 {
563 if (noOutput(info))
564 return;
565
566 for (off_type i = 0; i < info.size(); ++i) {
567 DistPrint print(this, info, i);
568 print(*stream);
569 }
570 }
571
572 void
573 Text::visit(const FormulaInfo &info)
574 {
575 visit((const VectorInfo &)info);
576 }
577
578 bool
579 initText(const string &filename, bool desc)
580 {
581 static Text text;
582 static bool connected = false;
583
584 if (connected)
585 return false;
586
587 extern list<Output *> OutputList;
588
589 text.open(*simout.find(filename));
590 text.descriptions = desc;
591 OutputList.push_back(&text);
592 connected = true;
593
594 return true;
595 }
596
597 } // namespace Stats