text.cc (8982:06ce6d08caaa) text.cc (9420:965d857ac791)
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) 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) const
212{
213 if ((flags.isSet(nozero) && 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 ccprintf(stream, "%-40s %12s %10s %10s", name,
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) 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) const
212{
213 if ((flags.isSet(nozero) && 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 ccprintf(stream, "%-40s %12s %10s %10s", name,
226 ValueToString(value, precision), pdfstr, cdfstr);
226 ValueToString(value, precision), pdfstr.str(), cdfstr.str());
227
228 if (descriptions) {
229 if (!desc.empty())
230 ccprintf(stream, " # %s", desc);
231 }
232 stream << endl;
233}
234
235struct VectorPrint
236{
237 string name;
238 string separatorString;
239 string desc;
240 vector<string> subnames;
241 vector<string> subdescs;
242 Flags flags;
243 bool descriptions;
244 int precision;
245 VResult vec;
246 Result total;
247
248 void operator()(ostream &stream) const;
249};
250
251void
252VectorPrint::operator()(std::ostream &stream) const
253{
254 size_type _size = vec.size();
255 Result _total = 0.0;
256
257 if (flags.isSet(pdf | cdf)) {
258 for (off_type i = 0; i < _size; ++i) {
259 _total += vec[i];
260 }
261 }
262
263 string base = name + separatorString;
264
265 ScalarPrint print;
266 print.name = name;
267 print.desc = desc;
268 print.precision = precision;
269 print.descriptions = descriptions;
270 print.flags = flags;
271 print.pdf = _total ? 0.0 : NAN;
272 print.cdf = _total ? 0.0 : NAN;
273
274 bool havesub = !subnames.empty();
275
276 if (_size == 1) {
277 print.value = vec[0];
278 print(stream);
279 return;
280 }
281
282 for (off_type i = 0; i < _size; ++i) {
283 if (havesub && (i >= subnames.size() || subnames[i].empty()))
284 continue;
285
286 print.name = base + (havesub ? subnames[i] : to_string(i));
287 print.desc = subdescs.empty() ? desc : subdescs[i];
288
289 print.update(vec[i], _total);
290 print(stream);
291 }
292
293 if (flags.isSet(::Stats::total)) {
294 print.pdf = NAN;
295 print.cdf = NAN;
296 print.name = base + "total";
297 print.desc = desc;
298 print.value = total;
299 print(stream);
300 }
301}
302
303struct DistPrint
304{
305 string name;
306 string separatorString;
307 string desc;
308 Flags flags;
309 bool descriptions;
310 int precision;
311
312 const DistData &data;
313
314 DistPrint(const Text *text, const DistInfo &info);
315 DistPrint(const Text *text, const VectorDistInfo &info, int i);
316 void init(const Text *text, const Info &info);
317 void operator()(ostream &stream) const;
318};
319
320DistPrint::DistPrint(const Text *text, const DistInfo &info)
321 : data(info.data)
322{
323 init(text, info);
324}
325
326DistPrint::DistPrint(const Text *text, const VectorDistInfo &info, int i)
327 : data(info.data[i])
328{
329 init(text, info);
330
331 name = info.name + "_" +
332 (info.subnames[i].empty() ? (to_string(i)) : info.subnames[i]);
333
334 if (!info.subdescs[i].empty())
335 desc = info.subdescs[i];
336}
337
338void
339DistPrint::init(const Text *text, const Info &info)
340{
341 name = info.name;
342 separatorString = info.separatorString;
343 desc = info.desc;
344 flags = info.flags;
345 precision = info.precision;
346 descriptions = text->descriptions;
347}
348
349void
350DistPrint::operator()(ostream &stream) const
351{
352 string base = name + separatorString;
353
354 ScalarPrint print;
355 print.precision = precision;
356 print.flags = flags;
357 print.descriptions = descriptions;
358 print.desc = desc;
359 print.pdf = NAN;
360 print.cdf = NAN;
361
362 print.name = base + "samples";
363 print.value = data.samples;
364 print(stream);
365
366 print.name = base + "mean";
367 print.value = data.samples ? data.sum / data.samples : NAN;
368 print(stream);
369
370 if (data.type == Hist) {
371 print.name = base + "gmean";
372 print.value = data.samples ? exp(data.logs / data.samples) : NAN;
373 print(stream);
374 }
375
376 Result stdev = NAN;
377 if (data.samples)
378 stdev = sqrt((data.samples * data.squares - data.sum * data.sum) /
379 (data.samples * (data.samples - 1.0)));
380 print.name = base + "stdev";
381 print.value = stdev;
382 print(stream);
383
384 if (data.type == Deviation)
385 return;
386
387 size_t size = data.cvec.size();
388
389 Result total = 0.0;
390 if (data.type == Dist && data.underflow != NAN)
391 total += data.underflow;
392 for (off_type i = 0; i < size; ++i)
393 total += data.cvec[i];
394 if (data.type == Dist && data.overflow != NAN)
395 total += data.overflow;
396
397 if (total) {
398 print.pdf = 0.0;
399 print.cdf = 0.0;
400 }
401
402 if (data.type == Dist && data.underflow != NAN) {
403 print.name = base + "underflows";
404 print.update(data.underflow, total);
405 print(stream);
406 }
407
408 for (off_type i = 0; i < size; ++i) {
409 stringstream namestr;
410 namestr << base;
411
412 Counter low = i * data.bucket_size + data.min;
413 Counter high = ::min(low + data.bucket_size - 1.0, data.max);
414 namestr << low;
415 if (low < high)
416 namestr << "-" << high;
417
418 print.name = namestr.str();
419 print.update(data.cvec[i], total);
420 print(stream);
421 }
422
423 if (data.type == Dist && data.overflow != NAN) {
424 print.name = base + "overflows";
425 print.update(data.overflow, total);
426 print(stream);
427 }
428
429 print.pdf = NAN;
430 print.cdf = NAN;
431
432 if (data.type == Dist && data.min_val != NAN) {
433 print.name = base + "min_value";
434 print.value = data.min_val;
435 print(stream);
436 }
437
438 if (data.type == Dist && data.max_val != NAN) {
439 print.name = base + "max_value";
440 print.value = data.max_val;
441 print(stream);
442 }
443
444 print.name = base + "total";
445 print.value = total;
446 print(stream);
447}
448
449void
450Text::visit(const ScalarInfo &info)
451{
452 if (noOutput(info))
453 return;
454
455 ScalarPrint print;
456 print.value = info.result();
457 print.name = info.name;
458 print.desc = info.desc;
459 print.flags = info.flags;
460 print.descriptions = descriptions;
461 print.precision = info.precision;
462 print.pdf = NAN;
463 print.cdf = NAN;
464
465 print(*stream);
466}
467
468void
469Text::visit(const VectorInfo &info)
470{
471 if (noOutput(info))
472 return;
473
474 size_type size = info.size();
475 VectorPrint print;
476
477 print.name = info.name;
478 print.separatorString = info.separatorString;
479 print.desc = info.desc;
480 print.flags = info.flags;
481 print.descriptions = descriptions;
482 print.precision = info.precision;
483 print.vec = info.result();
484 print.total = info.total();
485
486 if (!info.subnames.empty()) {
487 for (off_type i = 0; i < size; ++i) {
488 if (!info.subnames[i].empty()) {
489 print.subnames = info.subnames;
490 print.subnames.resize(size);
491 for (off_type i = 0; i < size; ++i) {
492 if (!info.subnames[i].empty() &&
493 !info.subdescs[i].empty()) {
494 print.subdescs = info.subdescs;
495 print.subdescs.resize(size);
496 break;
497 }
498 }
499 break;
500 }
501 }
502 }
503
504 print(*stream);
505}
506
507void
508Text::visit(const Vector2dInfo &info)
509{
510 if (noOutput(info))
511 return;
512
513 bool havesub = false;
514 VectorPrint print;
515
516 if (!info.y_subnames.empty()) {
517 for (off_type i = 0; i < info.y; ++i) {
518 if (!info.y_subnames[i].empty()) {
519 print.subnames = info.y_subnames;
520 }
521 break;
522 }
523 }
524 print.flags = info.flags;
525 print.separatorString = info.separatorString;
526 print.descriptions = descriptions;
527 print.precision = info.precision;
528
529 if (!info.subnames.empty()) {
530 for (off_type i = 0; i < info.x; ++i)
531 if (!info.subnames[i].empty())
532 havesub = true;
533 }
534
535 VResult tot_vec(info.y);
536 Result super_total = 0.0;
537 for (off_type i = 0; i < info.x; ++i) {
538 if (havesub && (i >= info.subnames.size() || info.subnames[i].empty()))
539 continue;
540
541 off_type iy = i * info.y;
542 VResult yvec(info.y);
543
544 Result total = 0.0;
545 for (off_type j = 0; j < info.y; ++j) {
546 yvec[j] = info.cvec[iy + j];
547 tot_vec[j] += yvec[j];
548 total += yvec[j];
549 super_total += yvec[j];
550 }
551
552 print.name = info.name + "_" +
553 (havesub ? info.subnames[i] : to_string(i));
554 print.desc = info.desc;
555 print.vec = yvec;
556 print.total = total;
557 print(*stream);
558 }
559
560 if (info.flags.isSet(::Stats::total) && (info.x > 1)) {
561 print.name = info.name;
562 print.desc = info.desc;
563 print.vec = tot_vec;
564 print.total = super_total;
565 print(*stream);
566 }
567}
568
569void
570Text::visit(const DistInfo &info)
571{
572 if (noOutput(info))
573 return;
574
575 DistPrint print(this, info);
576 print(*stream);
577}
578
579void
580Text::visit(const VectorDistInfo &info)
581{
582 if (noOutput(info))
583 return;
584
585 for (off_type i = 0; i < info.size(); ++i) {
586 DistPrint print(this, info, i);
587 print(*stream);
588 }
589}
590
591void
592Text::visit(const FormulaInfo &info)
593{
594 visit((const VectorInfo &)info);
595}
596
597/*
598 This struct implements the output methods for the sparse
599 histogram stat
600*/
601struct SparseHistPrint
602{
603 string name;
604 string separatorString;
605 string desc;
606 Flags flags;
607 bool descriptions;
608 int precision;
609
610 const SparseHistData &data;
611
612 SparseHistPrint(const Text *text, const SparseHistInfo &info);
613 void init(const Text *text, const Info &info);
614 void operator()(ostream &stream) const;
615};
616
617/* Call initialization function */
618SparseHistPrint::SparseHistPrint(const Text *text, const SparseHistInfo &info)
619 : data(info.data)
620{
621 init(text, info);
622}
623
624/* Initialization function */
625void
626SparseHistPrint::init(const Text *text, const Info &info)
627{
628 name = info.name;
629 separatorString = info.separatorString;
630 desc = info.desc;
631 flags = info.flags;
632 precision = info.precision;
633 descriptions = text->descriptions;
634}
635
636/* Grab data from map and write to output stream */
637void
638SparseHistPrint::operator()(ostream &stream) const
639{
640 string base = name + separatorString;
641
642 ScalarPrint print;
643 print.precision = precision;
644 print.flags = flags;
645 print.descriptions = descriptions;
646 print.desc = desc;
647 print.pdf = NAN;
648 print.cdf = NAN;
649
650 print.name = base + "samples";
651 print.value = data.samples;
652 print(stream);
653
654 MCounter::const_iterator it;
655 for (it = data.cmap.begin(); it != data.cmap.end(); it++) {
656 stringstream namestr;
657 namestr << base;
658
659 namestr <<(*it).first;
660 print.name = namestr.str();
661 print.value = (*it).second;
662 print(stream);
663 }
664
665 print.pdf = NAN;
666 print.cdf = NAN;
667
668 print.name = base + "total";
669 print.value = total;
670 print(stream);
671}
672
673void
674Text::visit(const SparseHistInfo &info)
675{
676 if (noOutput(info))
677 return;
678
679 SparseHistPrint print(this, info);
680 print(*stream);
681}
682
683Output *
684initText(const string &filename, bool desc)
685{
686 static Text text;
687 static bool connected = false;
688
689 if (!connected) {
690 ostream *os = simout.find(filename);
691 if (!os)
692 os = simout.create(filename);
693
694 text.open(*os);
695 text.descriptions = desc;
696 connected = true;
697 }
698
699 return &text;
700}
701
702} // namespace Stats
227
228 if (descriptions) {
229 if (!desc.empty())
230 ccprintf(stream, " # %s", desc);
231 }
232 stream << endl;
233}
234
235struct VectorPrint
236{
237 string name;
238 string separatorString;
239 string desc;
240 vector<string> subnames;
241 vector<string> subdescs;
242 Flags flags;
243 bool descriptions;
244 int precision;
245 VResult vec;
246 Result total;
247
248 void operator()(ostream &stream) const;
249};
250
251void
252VectorPrint::operator()(std::ostream &stream) const
253{
254 size_type _size = vec.size();
255 Result _total = 0.0;
256
257 if (flags.isSet(pdf | cdf)) {
258 for (off_type i = 0; i < _size; ++i) {
259 _total += vec[i];
260 }
261 }
262
263 string base = name + separatorString;
264
265 ScalarPrint print;
266 print.name = name;
267 print.desc = desc;
268 print.precision = precision;
269 print.descriptions = descriptions;
270 print.flags = flags;
271 print.pdf = _total ? 0.0 : NAN;
272 print.cdf = _total ? 0.0 : NAN;
273
274 bool havesub = !subnames.empty();
275
276 if (_size == 1) {
277 print.value = vec[0];
278 print(stream);
279 return;
280 }
281
282 for (off_type i = 0; i < _size; ++i) {
283 if (havesub && (i >= subnames.size() || subnames[i].empty()))
284 continue;
285
286 print.name = base + (havesub ? subnames[i] : to_string(i));
287 print.desc = subdescs.empty() ? desc : subdescs[i];
288
289 print.update(vec[i], _total);
290 print(stream);
291 }
292
293 if (flags.isSet(::Stats::total)) {
294 print.pdf = NAN;
295 print.cdf = NAN;
296 print.name = base + "total";
297 print.desc = desc;
298 print.value = total;
299 print(stream);
300 }
301}
302
303struct DistPrint
304{
305 string name;
306 string separatorString;
307 string desc;
308 Flags flags;
309 bool descriptions;
310 int precision;
311
312 const DistData &data;
313
314 DistPrint(const Text *text, const DistInfo &info);
315 DistPrint(const Text *text, const VectorDistInfo &info, int i);
316 void init(const Text *text, const Info &info);
317 void operator()(ostream &stream) const;
318};
319
320DistPrint::DistPrint(const Text *text, const DistInfo &info)
321 : data(info.data)
322{
323 init(text, info);
324}
325
326DistPrint::DistPrint(const Text *text, const VectorDistInfo &info, int i)
327 : data(info.data[i])
328{
329 init(text, info);
330
331 name = info.name + "_" +
332 (info.subnames[i].empty() ? (to_string(i)) : info.subnames[i]);
333
334 if (!info.subdescs[i].empty())
335 desc = info.subdescs[i];
336}
337
338void
339DistPrint::init(const Text *text, const Info &info)
340{
341 name = info.name;
342 separatorString = info.separatorString;
343 desc = info.desc;
344 flags = info.flags;
345 precision = info.precision;
346 descriptions = text->descriptions;
347}
348
349void
350DistPrint::operator()(ostream &stream) const
351{
352 string base = name + separatorString;
353
354 ScalarPrint print;
355 print.precision = precision;
356 print.flags = flags;
357 print.descriptions = descriptions;
358 print.desc = desc;
359 print.pdf = NAN;
360 print.cdf = NAN;
361
362 print.name = base + "samples";
363 print.value = data.samples;
364 print(stream);
365
366 print.name = base + "mean";
367 print.value = data.samples ? data.sum / data.samples : NAN;
368 print(stream);
369
370 if (data.type == Hist) {
371 print.name = base + "gmean";
372 print.value = data.samples ? exp(data.logs / data.samples) : NAN;
373 print(stream);
374 }
375
376 Result stdev = NAN;
377 if (data.samples)
378 stdev = sqrt((data.samples * data.squares - data.sum * data.sum) /
379 (data.samples * (data.samples - 1.0)));
380 print.name = base + "stdev";
381 print.value = stdev;
382 print(stream);
383
384 if (data.type == Deviation)
385 return;
386
387 size_t size = data.cvec.size();
388
389 Result total = 0.0;
390 if (data.type == Dist && data.underflow != NAN)
391 total += data.underflow;
392 for (off_type i = 0; i < size; ++i)
393 total += data.cvec[i];
394 if (data.type == Dist && data.overflow != NAN)
395 total += data.overflow;
396
397 if (total) {
398 print.pdf = 0.0;
399 print.cdf = 0.0;
400 }
401
402 if (data.type == Dist && data.underflow != NAN) {
403 print.name = base + "underflows";
404 print.update(data.underflow, total);
405 print(stream);
406 }
407
408 for (off_type i = 0; i < size; ++i) {
409 stringstream namestr;
410 namestr << base;
411
412 Counter low = i * data.bucket_size + data.min;
413 Counter high = ::min(low + data.bucket_size - 1.0, data.max);
414 namestr << low;
415 if (low < high)
416 namestr << "-" << high;
417
418 print.name = namestr.str();
419 print.update(data.cvec[i], total);
420 print(stream);
421 }
422
423 if (data.type == Dist && data.overflow != NAN) {
424 print.name = base + "overflows";
425 print.update(data.overflow, total);
426 print(stream);
427 }
428
429 print.pdf = NAN;
430 print.cdf = NAN;
431
432 if (data.type == Dist && data.min_val != NAN) {
433 print.name = base + "min_value";
434 print.value = data.min_val;
435 print(stream);
436 }
437
438 if (data.type == Dist && data.max_val != NAN) {
439 print.name = base + "max_value";
440 print.value = data.max_val;
441 print(stream);
442 }
443
444 print.name = base + "total";
445 print.value = total;
446 print(stream);
447}
448
449void
450Text::visit(const ScalarInfo &info)
451{
452 if (noOutput(info))
453 return;
454
455 ScalarPrint print;
456 print.value = info.result();
457 print.name = info.name;
458 print.desc = info.desc;
459 print.flags = info.flags;
460 print.descriptions = descriptions;
461 print.precision = info.precision;
462 print.pdf = NAN;
463 print.cdf = NAN;
464
465 print(*stream);
466}
467
468void
469Text::visit(const VectorInfo &info)
470{
471 if (noOutput(info))
472 return;
473
474 size_type size = info.size();
475 VectorPrint print;
476
477 print.name = info.name;
478 print.separatorString = info.separatorString;
479 print.desc = info.desc;
480 print.flags = info.flags;
481 print.descriptions = descriptions;
482 print.precision = info.precision;
483 print.vec = info.result();
484 print.total = info.total();
485
486 if (!info.subnames.empty()) {
487 for (off_type i = 0; i < size; ++i) {
488 if (!info.subnames[i].empty()) {
489 print.subnames = info.subnames;
490 print.subnames.resize(size);
491 for (off_type i = 0; i < size; ++i) {
492 if (!info.subnames[i].empty() &&
493 !info.subdescs[i].empty()) {
494 print.subdescs = info.subdescs;
495 print.subdescs.resize(size);
496 break;
497 }
498 }
499 break;
500 }
501 }
502 }
503
504 print(*stream);
505}
506
507void
508Text::visit(const Vector2dInfo &info)
509{
510 if (noOutput(info))
511 return;
512
513 bool havesub = false;
514 VectorPrint print;
515
516 if (!info.y_subnames.empty()) {
517 for (off_type i = 0; i < info.y; ++i) {
518 if (!info.y_subnames[i].empty()) {
519 print.subnames = info.y_subnames;
520 }
521 break;
522 }
523 }
524 print.flags = info.flags;
525 print.separatorString = info.separatorString;
526 print.descriptions = descriptions;
527 print.precision = info.precision;
528
529 if (!info.subnames.empty()) {
530 for (off_type i = 0; i < info.x; ++i)
531 if (!info.subnames[i].empty())
532 havesub = true;
533 }
534
535 VResult tot_vec(info.y);
536 Result super_total = 0.0;
537 for (off_type i = 0; i < info.x; ++i) {
538 if (havesub && (i >= info.subnames.size() || info.subnames[i].empty()))
539 continue;
540
541 off_type iy = i * info.y;
542 VResult yvec(info.y);
543
544 Result total = 0.0;
545 for (off_type j = 0; j < info.y; ++j) {
546 yvec[j] = info.cvec[iy + j];
547 tot_vec[j] += yvec[j];
548 total += yvec[j];
549 super_total += yvec[j];
550 }
551
552 print.name = info.name + "_" +
553 (havesub ? info.subnames[i] : to_string(i));
554 print.desc = info.desc;
555 print.vec = yvec;
556 print.total = total;
557 print(*stream);
558 }
559
560 if (info.flags.isSet(::Stats::total) && (info.x > 1)) {
561 print.name = info.name;
562 print.desc = info.desc;
563 print.vec = tot_vec;
564 print.total = super_total;
565 print(*stream);
566 }
567}
568
569void
570Text::visit(const DistInfo &info)
571{
572 if (noOutput(info))
573 return;
574
575 DistPrint print(this, info);
576 print(*stream);
577}
578
579void
580Text::visit(const VectorDistInfo &info)
581{
582 if (noOutput(info))
583 return;
584
585 for (off_type i = 0; i < info.size(); ++i) {
586 DistPrint print(this, info, i);
587 print(*stream);
588 }
589}
590
591void
592Text::visit(const FormulaInfo &info)
593{
594 visit((const VectorInfo &)info);
595}
596
597/*
598 This struct implements the output methods for the sparse
599 histogram stat
600*/
601struct SparseHistPrint
602{
603 string name;
604 string separatorString;
605 string desc;
606 Flags flags;
607 bool descriptions;
608 int precision;
609
610 const SparseHistData &data;
611
612 SparseHistPrint(const Text *text, const SparseHistInfo &info);
613 void init(const Text *text, const Info &info);
614 void operator()(ostream &stream) const;
615};
616
617/* Call initialization function */
618SparseHistPrint::SparseHistPrint(const Text *text, const SparseHistInfo &info)
619 : data(info.data)
620{
621 init(text, info);
622}
623
624/* Initialization function */
625void
626SparseHistPrint::init(const Text *text, const Info &info)
627{
628 name = info.name;
629 separatorString = info.separatorString;
630 desc = info.desc;
631 flags = info.flags;
632 precision = info.precision;
633 descriptions = text->descriptions;
634}
635
636/* Grab data from map and write to output stream */
637void
638SparseHistPrint::operator()(ostream &stream) const
639{
640 string base = name + separatorString;
641
642 ScalarPrint print;
643 print.precision = precision;
644 print.flags = flags;
645 print.descriptions = descriptions;
646 print.desc = desc;
647 print.pdf = NAN;
648 print.cdf = NAN;
649
650 print.name = base + "samples";
651 print.value = data.samples;
652 print(stream);
653
654 MCounter::const_iterator it;
655 for (it = data.cmap.begin(); it != data.cmap.end(); it++) {
656 stringstream namestr;
657 namestr << base;
658
659 namestr <<(*it).first;
660 print.name = namestr.str();
661 print.value = (*it).second;
662 print(stream);
663 }
664
665 print.pdf = NAN;
666 print.cdf = NAN;
667
668 print.name = base + "total";
669 print.value = total;
670 print(stream);
671}
672
673void
674Text::visit(const SparseHistInfo &info)
675{
676 if (noOutput(info))
677 return;
678
679 SparseHistPrint print(this, info);
680 print(*stream);
681}
682
683Output *
684initText(const string &filename, bool desc)
685{
686 static Text text;
687 static bool connected = false;
688
689 if (!connected) {
690 ostream *os = simout.find(filename);
691 if (!os)
692 os = simout.create(filename);
693
694 text.open(*os);
695 text.descriptions = desc;
696 connected = true;
697 }
698
699 return &text;
700}
701
702} // namespace Stats