text.cc revision 5886:12431dc9a30a
1/* 2 * Copyright (c) 2004-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Nathan Binkert 29 */ 30 31#if defined(__APPLE__) 32#define _GLIBCPP_USE_C99 1 33#endif 34 35#if defined(__sun) 36#include <math.h> 37#endif 38 39#include <iostream> 40#include <sstream> 41#include <fstream> 42#include <string> 43 44#include "base/misc.hh" 45#include "base/statistics.hh" 46#include "base/stats/statdb.hh" 47#include "base/stats/text.hh" 48#include "base/stats/visit.hh" 49 50using namespace std; 51 52#ifndef NAN 53float __nan(); 54/** Define Not a number. */ 55#define NAN (__nan()) 56/** Need to define __nan() */ 57#define __M5_NAN 58#endif 59 60#ifdef __M5_NAN 61float 62__nan() 63{ 64 union { 65 uint32_t ui; 66 float f; 67 } nan; 68 69 nan.ui = 0x7fc00000; 70 return nan.f; 71} 72#endif 73 74namespace Stats { 75 76Text::Text() 77 : mystream(false), stream(NULL), compat(false), descriptions(false) 78{ 79} 80 81Text::Text(std::ostream &stream) 82 : mystream(false), stream(NULL), compat(false), descriptions(false) 83{ 84 open(stream); 85} 86 87Text::Text(const std::string &file) 88 : mystream(false), stream(NULL), compat(false), descriptions(false) 89{ 90 open(file); 91} 92 93 94Text::~Text() 95{ 96 if (mystream) { 97 assert(stream); 98 delete stream; 99 } 100} 101 102void 103Text::open(std::ostream &_stream) 104{ 105 if (stream) 106 panic("stream already set!"); 107 108 mystream = false; 109 stream = &_stream; 110 if (!valid()) 111 fatal("Unable to open output stream for writing\n"); 112} 113 114void 115Text::open(const std::string &file) 116{ 117 if (stream) 118 panic("stream already set!"); 119 120 mystream = true; 121 stream = new ofstream(file.c_str(), ios::trunc); 122 if (!valid()) 123 fatal("Unable to open statistics file for writing\n"); 124} 125 126bool 127Text::valid() const 128{ 129 return stream != NULL && stream->good(); 130} 131 132void 133Text::output() 134{ 135 using namespace Database; 136 137 ccprintf(*stream, "\n---------- Begin Simulation Statistics ----------\n"); 138 stat_list_t::const_iterator i, end = stats().end(); 139 for (i = stats().begin(); i != end; ++i) 140 (*i)->visit(*this); 141 ccprintf(*stream, "\n---------- End Simulation Statistics ----------\n"); 142 stream->flush(); 143} 144 145bool 146Text::noOutput(const Info &info) 147{ 148 if (!(info.flags & print)) 149 return true; 150 151 if (info.prereq && info.prereq->zero()) 152 return true; 153 154 return false; 155} 156 157string 158ValueToString(Result value, int precision, bool compat) 159{ 160 stringstream val; 161 162 if (!isnan(value)) { 163 if (precision != -1) 164 val.precision(precision); 165 else if (value == rint(value)) 166 val.precision(0); 167 168 val.unsetf(ios::showpoint); 169 val.setf(ios::fixed); 170 val << value; 171 } else { 172 val << (compat ? "<err: div-0>" : "no value"); 173 } 174 175 return val.str(); 176} 177 178struct ScalarPrint 179{ 180 Result value; 181 string name; 182 string desc; 183 StatFlags flags; 184 bool compat; 185 bool descriptions; 186 int precision; 187 Result pdf; 188 Result cdf; 189 190 void operator()(ostream &stream) const; 191}; 192 193void 194ScalarPrint::operator()(ostream &stream) const 195{ 196 if ((flags & nozero && value == 0.0) || 197 (flags & nonan && isnan(value))) 198 return; 199 200 stringstream pdfstr, cdfstr; 201 202 if (!isnan(pdf)) 203 ccprintf(pdfstr, "%.2f%%", pdf * 100.0); 204 205 if (!isnan(cdf)) 206 ccprintf(cdfstr, "%.2f%%", cdf * 100.0); 207 208 if (compat && flags & __substat) { 209 ccprintf(stream, "%32s %12s %10s %10s", name, 210 ValueToString(value, precision, compat), pdfstr, cdfstr); 211 } else { 212 ccprintf(stream, "%-40s %12s %10s %10s", name, 213 ValueToString(value, precision, compat), pdfstr, cdfstr); 214 } 215 216 if (descriptions) { 217 if (!desc.empty()) 218 ccprintf(stream, " # %s", desc); 219 } 220 stream << endl; 221} 222 223struct VectorPrint 224{ 225 string name; 226 string desc; 227 vector<string> subnames; 228 vector<string> subdescs; 229 StatFlags flags; 230 bool compat; 231 bool descriptions; 232 int precision; 233 VResult vec; 234 Result total; 235 236 void operator()(ostream &stream) const; 237}; 238 239void 240VectorPrint::operator()(std::ostream &stream) const 241{ 242 size_type _size = vec.size(); 243 Result _total = 0.0; 244 245 if (flags & (pdf | cdf)) { 246 for (off_type i = 0; i < _size; ++i) { 247 _total += vec[i]; 248 } 249 } 250 251 string base = name + (compat ? "_" : "::"); 252 253 ScalarPrint print; 254 print.name = name; 255 print.desc = desc; 256 print.compat = compat; 257 print.precision = precision; 258 print.descriptions = descriptions; 259 print.flags = flags; 260 print.pdf = NAN; 261 print.cdf = NAN; 262 263 bool havesub = !subnames.empty(); 264 265 if (_size == 1) { 266 print.value = vec[0]; 267 print(stream); 268 } else if (!compat) { 269 for (off_type i = 0; i < _size; ++i) { 270 if (havesub && (i >= subnames.size() || subnames[i].empty())) 271 continue; 272 273 print.name = base + (havesub ? subnames[i] : to_string(i)); 274 print.desc = subdescs.empty() ? desc : subdescs[i]; 275 print.value = vec[i]; 276 277 if (_total && (flags & pdf)) { 278 print.pdf = vec[i] / _total; 279 print.cdf += print.pdf; 280 } 281 282 print(stream); 283 } 284 285 if (flags & ::Stats::total) { 286 print.name = base + "total"; 287 print.desc = desc; 288 print.value = total; 289 print(stream); 290 } 291 } else { 292 if (flags & ::Stats::total) { 293 print.value = total; 294 print(stream); 295 } 296 297 Result _pdf = 0.0; 298 Result _cdf = 0.0; 299 if (flags & dist) { 300 ccprintf(stream, "%s.start_dist\n", name); 301 for (off_type i = 0; i < _size; ++i) { 302 print.name = havesub ? subnames[i] : to_string(i); 303 print.desc = subdescs.empty() ? desc : subdescs[i]; 304 print.flags |= __substat; 305 print.value = vec[i]; 306 307 if (_total) { 308 _pdf = vec[i] / _total; 309 _cdf += _pdf; 310 } 311 312 if (flags & pdf) 313 print.pdf = _pdf; 314 if (flags & cdf) 315 print.cdf = _cdf; 316 317 print(stream); 318 } 319 ccprintf(stream, "%s.end_dist\n", name); 320 } else { 321 for (off_type i = 0; i < _size; ++i) { 322 if (havesub && subnames[i].empty()) 323 continue; 324 325 print.name = base; 326 print.name += havesub ? subnames[i] : to_string(i); 327 print.desc = subdescs.empty() ? desc : subdescs[i]; 328 print.value = vec[i]; 329 330 if (_total) { 331 _pdf = vec[i] / _total; 332 _cdf += _pdf; 333 } else { 334 _pdf = _cdf = NAN; 335 } 336 337 if (flags & pdf) { 338 print.pdf = _pdf; 339 print.cdf = _cdf; 340 } 341 342 print(stream); 343 } 344 } 345 } 346} 347 348struct DistPrint 349{ 350 string name; 351 string desc; 352 StatFlags flags; 353 bool compat; 354 bool descriptions; 355 int precision; 356 357 Result min_val; 358 Result max_val; 359 Result underflow; 360 Result overflow; 361 VResult vec; 362 Result sum; 363 Result squares; 364 Result samples; 365 366 Counter min; 367 Counter max; 368 Counter bucket_size; 369 size_type size; 370 bool fancy; 371 372 void operator()(ostream &stream) const; 373}; 374 375void 376DistPrint::operator()(ostream &stream) const 377{ 378 if (fancy) { 379 ScalarPrint print; 380 string base = name + (compat ? "_" : "::"); 381 382 print.precision = precision; 383 print.flags = flags; 384 print.compat = compat; 385 print.descriptions = descriptions; 386 print.desc = desc; 387 print.pdf = NAN; 388 print.cdf = NAN; 389 390 print.name = base + "mean"; 391 print.value = samples ? sum / samples : NAN; 392 print(stream); 393 394 print.name = base + "stdev"; 395 print.value = samples ? sqrt((samples * squares - sum * sum) / 396 (samples * (samples - 1.0))) : NAN; 397 print(stream); 398 399 print.name = "**Ignore: " + base + "TOT"; 400 print.value = samples; 401 print(stream); 402 return; 403 } 404 405 assert(size == vec.size()); 406 407 Result total = 0.0; 408 409 total += underflow; 410 for (off_type i = 0; i < size; ++i) 411 total += vec[i]; 412 total += overflow; 413 414 string base = name + (compat ? "." : "::"); 415 416 ScalarPrint print; 417 print.desc = compat ? "" : desc; 418 print.flags = flags; 419 print.compat = compat; 420 print.descriptions = descriptions; 421 print.precision = precision; 422 print.pdf = NAN; 423 print.cdf = NAN; 424 425 if (compat) { 426 ccprintf(stream, "%-42s", base + "start_dist"); 427 if (descriptions && !desc.empty()) 428 ccprintf(stream, " # %s", desc); 429 stream << endl; 430 } 431 432 print.name = base + "samples"; 433 print.value = samples; 434 print(stream); 435 436 print.name = base + "min_value"; 437 print.value = min_val; 438 print(stream); 439 440 if (!compat || underflow > 0.0) { 441 print.name = base + "underflows"; 442 print.value = underflow; 443 if (!compat && total) { 444 print.pdf = underflow / total; 445 print.cdf += print.pdf; 446 } 447 print(stream); 448 } 449 450 if (!compat) { 451 for (off_type i = 0; i < size; ++i) { 452 stringstream namestr; 453 namestr << base; 454 455 Counter low = i * bucket_size + min; 456 Counter high = ::min(low + bucket_size, max); 457 namestr << low; 458 if (low < high) 459 namestr << "-" << high; 460 461 print.name = namestr.str(); 462 print.value = vec[i]; 463 if (total) { 464 print.pdf = vec[i] / total; 465 print.cdf += print.pdf; 466 } 467 print(stream); 468 } 469 } else { 470 Counter _min; 471 Result _pdf; 472 Result _cdf = 0.0; 473 474 print.flags = flags | __substat; 475 476 for (off_type i = 0; i < size; ++i) { 477 if ((flags & nozero && vec[i] == 0.0) || 478 (flags & nonan && isnan(vec[i]))) 479 continue; 480 481 _min = i * bucket_size + min; 482 _pdf = vec[i] / total * 100.0; 483 _cdf += _pdf; 484 485 486 print.name = ValueToString(_min, 0, compat); 487 print.value = vec[i]; 488 print.pdf = (flags & pdf) ? _pdf : NAN; 489 print.cdf = (flags & cdf) ? _cdf : NAN; 490 print(stream); 491 } 492 493 print.flags = flags; 494 } 495 496 if (!compat || overflow > 0.0) { 497 print.name = base + "overflows"; 498 print.value = overflow; 499 if (!compat && total) { 500 print.pdf = overflow / total; 501 print.cdf += print.pdf; 502 } else { 503 print.pdf = NAN; 504 print.cdf = NAN; 505 } 506 print(stream); 507 } 508 509 print.pdf = NAN; 510 print.cdf = NAN; 511 512 if (!compat) { 513 print.name = base + "total"; 514 print.value = total; 515 print(stream); 516 } 517 518 print.name = base + "max_value"; 519 print.value = max_val; 520 print(stream); 521 522 if (!compat && samples != 0) { 523 print.name = base + "mean"; 524 print.value = sum / samples; 525 print(stream); 526 527 print.name = base + "stdev"; 528 print.value = sqrt((samples * squares - sum * sum) / 529 (samples * (samples - 1.0))); 530 print(stream); 531 } 532 533 if (compat) 534 ccprintf(stream, "%send_dist\n\n", base); 535} 536 537void 538Text::visit(const ScalarInfoBase &info) 539{ 540 if (noOutput(info)) 541 return; 542 543 ScalarPrint print; 544 print.value = info.result(); 545 print.name = info.name; 546 print.desc = info.desc; 547 print.flags = info.flags; 548 print.compat = compat; 549 print.descriptions = descriptions; 550 print.precision = info.precision; 551 print.pdf = NAN; 552 print.cdf = NAN; 553 554 print(*stream); 555} 556 557void 558Text::visit(const VectorInfoBase &info) 559{ 560 if (noOutput(info)) 561 return; 562 563 size_type size = info.size(); 564 VectorPrint print; 565 566 print.name = info.name; 567 print.desc = info.desc; 568 print.flags = info.flags; 569 print.compat = compat; 570 print.descriptions = descriptions; 571 print.precision = info.precision; 572 print.vec = info.result(); 573 print.total = info.total(); 574 575 if (!info.subnames.empty()) { 576 for (off_type i = 0; i < size; ++i) { 577 if (!info.subnames[i].empty()) { 578 print.subnames = info.subnames; 579 print.subnames.resize(size); 580 for (off_type i = 0; i < size; ++i) { 581 if (!info.subnames[i].empty() && 582 !info.subdescs[i].empty()) { 583 print.subdescs = info.subdescs; 584 print.subdescs.resize(size); 585 break; 586 } 587 } 588 break; 589 } 590 } 591 } 592 593 print(*stream); 594} 595 596void 597Text::visit(const Vector2dInfoBase &info) 598{ 599 if (noOutput(info)) 600 return; 601 602 bool havesub = false; 603 VectorPrint print; 604 605 print.subnames = info.y_subnames; 606 print.flags = info.flags; 607 print.compat = compat; 608 print.descriptions = descriptions; 609 print.precision = info.precision; 610 611 if (!info.subnames.empty()) { 612 for (off_type i = 0; i < info.x; ++i) 613 if (!info.subnames[i].empty()) 614 havesub = true; 615 } 616 617 VResult tot_vec(info.y); 618 Result super_total = 0.0; 619 for (off_type i = 0; i < info.x; ++i) { 620 if (havesub && (i >= info.subnames.size() || info.subnames[i].empty())) 621 continue; 622 623 off_type iy = i * info.y; 624 VResult yvec(info.y); 625 626 Result total = 0.0; 627 for (off_type j = 0; j < info.y; ++j) { 628 yvec[j] = info.cvec[iy + j]; 629 tot_vec[j] += yvec[j]; 630 total += yvec[j]; 631 super_total += yvec[j]; 632 } 633 634 print.name = info.name + "_" + 635 (havesub ? info.subnames[i] : to_string(i)); 636 print.desc = info.desc; 637 print.vec = yvec; 638 print.total = total; 639 print(*stream); 640 } 641 642 if ((info.flags & ::Stats::total) && (info.x > 1)) { 643 print.name = info.name; 644 print.desc = info.desc; 645 print.vec = tot_vec; 646 print.total = super_total; 647 print(*stream); 648 } 649} 650 651void 652Text::visit(const DistInfoBase &info) 653{ 654 if (noOutput(info)) 655 return; 656 657 DistPrint print; 658 659 print.name = info.name; 660 print.desc = info.desc; 661 print.flags = info.flags; 662 print.compat = compat; 663 print.descriptions = descriptions; 664 print.precision = info.precision; 665 666 const DistData &data = info.data; 667 668 print.min_val = data.min_val; 669 print.max_val = data.max_val; 670 print.underflow = data.underflow; 671 print.overflow = data.overflow; 672 print.vec.resize(data.cvec.size()); 673 for (off_type i = 0; i < print.vec.size(); ++i) 674 print.vec[i] = (Result)data.cvec[i]; 675 print.sum = data.sum; 676 print.squares = data.squares; 677 print.samples = data.samples; 678 679 print.min = data.min; 680 print.max = data.max; 681 print.bucket_size = data.bucket_size; 682 print.size = data.size; 683 print.fancy = data.fancy; 684 685 print(*stream); 686} 687 688void 689Text::visit(const VectorDistInfoBase &info) 690{ 691 if (noOutput(info)) 692 return; 693 694 for (off_type i = 0; i < info.size(); ++i) { 695 DistPrint print; 696 697 print.name = info.name + "_" + 698 (info.subnames[i].empty() ? (to_string(i)) : info.subnames[i]); 699 print.desc = info.subdescs[i].empty() ? info.desc : info.subdescs[i]; 700 print.flags = info.flags; 701 print.compat = compat; 702 print.descriptions = descriptions; 703 print.precision = info.precision; 704 705 print.min_val = info.data[i].min_val; 706 print.max_val = info.data[i].max_val; 707 print.underflow = info.data[i].underflow; 708 print.overflow = info.data[i].overflow; 709 print.vec.resize(info.data[i].cvec.size()); 710 for (off_type j = 0; j < print.vec.size(); ++j) 711 print.vec[j] = (Result)info.data[i].cvec[j]; 712 print.sum = info.data[i].sum; 713 print.squares = info.data[i].squares; 714 print.samples = info.data[i].samples; 715 716 print.min = info.data[i].min; 717 print.max = info.data[i].max; 718 print.bucket_size = info.data[i].bucket_size; 719 print.size = info.data[i].size; 720 print.fancy = info.data[i].fancy; 721 722 print(*stream); 723 } 724} 725 726void 727Text::visit(const FormulaInfoBase &info) 728{ 729 visit((const VectorInfoBase &)info); 730} 731 732bool 733initText(const string &filename, bool desc, bool compat) 734{ 735 static Text text; 736 static bool connected = false; 737 738 if (connected) 739 return false; 740 741 extern list<Output *> OutputList; 742 743 text.open(*simout.find(filename)); 744 text.descriptions = desc; 745 text.compat = compat; 746 OutputList.push_back(&text); 747 connected = true; 748 749 return true; 750} 751 752/* namespace Stats */ } 753