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