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