text.cc revision 5889:02e5bc7ca9ba
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) 77{ 78} 79 80Text::Text(std::ostream &stream) 81 : mystream(false), stream(NULL), compat(false), descriptions(false) 82{ 83 open(stream); 84} 85 86Text::Text(const std::string &file) 87 : mystream(false), stream(NULL), compat(false), 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) 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"); 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; 182 bool descriptions; 183 int precision; 184 Result pdf; 185 Result cdf; 186 187 void operator()(ostream &stream) const; 188}; 189 190void 191ScalarPrint::operator()(ostream &stream) const 192{ 193 if ((flags & nozero && value == 0.0) || 194 (flags & nonan && isnan(value))) 195 return; 196 197 stringstream pdfstr, cdfstr; 198 199 if (!isnan(pdf)) 200 ccprintf(pdfstr, "%.2f%%", pdf * 100.0); 201 202 if (!isnan(cdf)) 203 ccprintf(cdfstr, "%.2f%%", cdf * 100.0); 204 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 } 212 213 if (descriptions) { 214 if (!desc.empty()) 215 ccprintf(stream, " # %s", desc); 216 } 217 stream << endl; 218} 219 220struct VectorPrint 221{ 222 string name; 223 string desc; 224 vector<string> subnames; 225 vector<string> subdescs; 226 StatFlags flags; 227 bool compat; 228 bool descriptions; 229 int precision; 230 VResult vec; 231 Result total; 232 233 void operator()(ostream &stream) const; 234}; 235 236void 237VectorPrint::operator()(std::ostream &stream) const 238{ 239 size_type _size = vec.size(); 240 Result _total = 0.0; 241 242 if (flags & (pdf | cdf)) { 243 for (off_type i = 0; i < _size; ++i) { 244 _total += vec[i]; 245 } 246 } 247 248 string base = name + (compat ? "_" : "::"); 249 250 ScalarPrint print; 251 print.name = name; 252 print.desc = desc; 253 print.compat = compat; 254 print.precision = precision; 255 print.descriptions = descriptions; 256 print.flags = flags; 257 print.pdf = NAN; 258 print.cdf = NAN; 259 260 bool havesub = !subnames.empty(); 261 262 if (_size == 1) { 263 print.value = vec[0]; 264 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; 269 270 print.name = base + (havesub ? subnames[i] : to_string(i)); 271 print.desc = subdescs.empty() ? desc : subdescs[i]; 272 print.value = vec[i]; 273 274 if (_total && (flags & pdf)) { 275 print.pdf = vec[i] / _total; 276 print.cdf += print.pdf; 277 } 278 279 print(stream); 280 } 281 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 } 293 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 } 342 } 343} 344 345struct DistPrint 346{ 347 string name; 348 string desc; 349 StatFlags flags; 350 bool compat; 351 bool descriptions; 352 int precision; 353 354 Result min_val; 355 Result max_val; 356 Result underflow; 357 Result overflow; 358 VResult vec; 359 Result sum; 360 Result squares; 361 Result samples; 362 363 Counter min; 364 Counter max; 365 Counter bucket_size; 366 size_type size; 367 bool fancy; 368 369 void operator()(ostream &stream) const; 370}; 371 372void 373DistPrint::operator()(ostream &stream) const 374{ 375 if (fancy) { 376 ScalarPrint print; 377 string base = name + (compat ? "_" : "::"); 378 379 print.precision = precision; 380 print.flags = flags; 381 print.compat = compat; 382 print.descriptions = descriptions; 383 print.desc = desc; 384 print.pdf = NAN; 385 print.cdf = NAN; 386 387 print.name = base + "mean"; 388 print.value = samples ? sum / samples : NAN; 389 print(stream); 390 391 print.name = base + "stdev"; 392 print.value = samples ? sqrt((samples * squares - sum * sum) / 393 (samples * (samples - 1.0))) : NAN; 394 print(stream); 395 396 print.name = "**Ignore: " + base + "TOT"; 397 print.value = samples; 398 print(stream); 399 return; 400 } 401 402 assert(size == vec.size()); 403 404 Result total = 0.0; 405 406 total += underflow; 407 for (off_type i = 0; i < size; ++i) 408 total += vec[i]; 409 total += overflow; 410 411 string base = name + (compat ? "." : "::"); 412 413 ScalarPrint print; 414 print.desc = compat ? "" : desc; 415 print.flags = flags; 416 print.compat = compat; 417 print.descriptions = descriptions; 418 print.precision = precision; 419 print.pdf = NAN; 420 print.cdf = NAN; 421 422 if (compat) { 423 ccprintf(stream, "%-42s", base + "start_dist"); 424 if (descriptions && !desc.empty()) 425 ccprintf(stream, " # %s", desc); 426 stream << endl; 427 } 428 429 print.name = base + "samples"; 430 print.value = samples; 431 print(stream); 432 433 print.name = base + "min_value"; 434 print.value = min_val; 435 print(stream); 436 437 if (!compat || underflow > 0.0) { 438 print.name = base + "underflows"; 439 print.value = underflow; 440 if (!compat && total) { 441 print.pdf = underflow / total; 442 print.cdf += print.pdf; 443 } 444 print(stream); 445 } 446 447 if (!compat) { 448 for (off_type i = 0; i < size; ++i) { 449 stringstream namestr; 450 namestr << base; 451 452 Counter low = i * bucket_size + min; 453 Counter high = ::min(low + bucket_size, max); 454 namestr << low; 455 if (low < high) 456 namestr << "-" << high; 457 458 print.name = namestr.str(); 459 print.value = vec[i]; 460 if (total) { 461 print.pdf = vec[i] / total; 462 print.cdf += print.pdf; 463 } 464 print(stream); 465 } 466 } else { 467 Counter _min; 468 Result _pdf; 469 Result _cdf = 0.0; 470 471 print.flags = flags | __substat; 472 473 for (off_type i = 0; i < size; ++i) { 474 if ((flags & nozero && vec[i] == 0.0) || 475 (flags & nonan && isnan(vec[i]))) 476 continue; 477 478 _min = i * bucket_size + min; 479 _pdf = vec[i] / total * 100.0; 480 _cdf += _pdf; 481 482 483 print.name = ValueToString(_min, 0, compat); 484 print.value = vec[i]; 485 print.pdf = (flags & pdf) ? _pdf : NAN; 486 print.cdf = (flags & cdf) ? _cdf : NAN; 487 print(stream); 488 } 489 490 print.flags = flags; 491 } 492 493 if (!compat || overflow > 0.0) { 494 print.name = base + "overflows"; 495 print.value = overflow; 496 if (!compat && total) { 497 print.pdf = overflow / total; 498 print.cdf += print.pdf; 499 } else { 500 print.pdf = NAN; 501 print.cdf = NAN; 502 } 503 print(stream); 504 } 505 506 print.pdf = NAN; 507 print.cdf = NAN; 508 509 if (!compat) { 510 print.name = base + "total"; 511 print.value = total; 512 print(stream); 513 } 514 515 print.name = base + "max_value"; 516 print.value = max_val; 517 print(stream); 518 519 if (!compat && samples != 0) { 520 print.name = base + "mean"; 521 print.value = sum / samples; 522 print(stream); 523 524 print.name = base + "stdev"; 525 print.value = sqrt((samples * squares - sum * sum) / 526 (samples * (samples - 1.0))); 527 print(stream); 528 } 529 530 if (compat) 531 ccprintf(stream, "%send_dist\n\n", base); 532} 533 534void 535Text::visit(const ScalarInfoBase &info) 536{ 537 if (noOutput(info)) 538 return; 539 540 ScalarPrint print; 541 print.value = info.result(); 542 print.name = info.name; 543 print.desc = info.desc; 544 print.flags = info.flags; 545 print.compat = compat; 546 print.descriptions = descriptions; 547 print.precision = info.precision; 548 print.pdf = NAN; 549 print.cdf = NAN; 550 551 print(*stream); 552} 553 554void 555Text::visit(const VectorInfoBase &info) 556{ 557 if (noOutput(info)) 558 return; 559 560 size_type size = info.size(); 561 VectorPrint print; 562 563 print.name = info.name; 564 print.desc = info.desc; 565 print.flags = info.flags; 566 print.compat = compat; 567 print.descriptions = descriptions; 568 print.precision = info.precision; 569 print.vec = info.result(); 570 print.total = info.total(); 571 572 if (!info.subnames.empty()) { 573 for (off_type i = 0; i < size; ++i) { 574 if (!info.subnames[i].empty()) { 575 print.subnames = info.subnames; 576 print.subnames.resize(size); 577 for (off_type i = 0; i < size; ++i) { 578 if (!info.subnames[i].empty() && 579 !info.subdescs[i].empty()) { 580 print.subdescs = info.subdescs; 581 print.subdescs.resize(size); 582 break; 583 } 584 } 585 break; 586 } 587 } 588 } 589 590 print(*stream); 591} 592 593void 594Text::visit(const Vector2dInfoBase &info) 595{ 596 if (noOutput(info)) 597 return; 598 599 bool havesub = false; 600 VectorPrint print; 601 602 print.subnames = info.y_subnames; 603 print.flags = info.flags; 604 print.compat = compat; 605 print.descriptions = descriptions; 606 print.precision = info.precision; 607 608 if (!info.subnames.empty()) { 609 for (off_type i = 0; i < info.x; ++i) 610 if (!info.subnames[i].empty()) 611 havesub = true; 612 } 613 614 VResult tot_vec(info.y); 615 Result super_total = 0.0; 616 for (off_type i = 0; i < info.x; ++i) { 617 if (havesub && (i >= info.subnames.size() || info.subnames[i].empty())) 618 continue; 619 620 off_type iy = i * info.y; 621 VResult yvec(info.y); 622 623 Result total = 0.0; 624 for (off_type j = 0; j < info.y; ++j) { 625 yvec[j] = info.cvec[iy + j]; 626 tot_vec[j] += yvec[j]; 627 total += yvec[j]; 628 super_total += yvec[j]; 629 } 630 631 print.name = info.name + "_" + 632 (havesub ? info.subnames[i] : to_string(i)); 633 print.desc = info.desc; 634 print.vec = yvec; 635 print.total = total; 636 print(*stream); 637 } 638 639 if ((info.flags & ::Stats::total) && (info.x > 1)) { 640 print.name = info.name; 641 print.desc = info.desc; 642 print.vec = tot_vec; 643 print.total = super_total; 644 print(*stream); 645 } 646} 647 648void 649Text::visit(const DistInfoBase &info) 650{ 651 if (noOutput(info)) 652 return; 653 654 DistPrint print; 655 656 print.name = info.name; 657 print.desc = info.desc; 658 print.flags = info.flags; 659 print.compat = compat; 660 print.descriptions = descriptions; 661 print.precision = info.precision; 662 663 const DistData &data = info.data; 664 665 print.min_val = data.min_val; 666 print.max_val = data.max_val; 667 print.underflow = data.underflow; 668 print.overflow = data.overflow; 669 print.vec.resize(data.cvec.size()); 670 for (off_type i = 0; i < print.vec.size(); ++i) 671 print.vec[i] = (Result)data.cvec[i]; 672 print.sum = data.sum; 673 print.squares = data.squares; 674 print.samples = data.samples; 675 676 print.fancy = data.fancy; 677 678 if (!data.fancy) { 679 const DistStor::Params *params = 680 safe_cast<const DistStor::Params *>(info.storageParams); 681 682 print.min = params->min; 683 print.max = params->max; 684 print.bucket_size = params->bucket_size; 685 print.size = params->buckets; 686 } 687 688 print(*stream); 689} 690 691void 692Text::visit(const VectorDistInfoBase &info) 693{ 694 if (noOutput(info)) 695 return; 696 697 for (off_type i = 0; i < info.size(); ++i) { 698 DistPrint print; 699 700 print.name = info.name + "_" + 701 (info.subnames[i].empty() ? (to_string(i)) : info.subnames[i]); 702 print.desc = info.subdescs[i].empty() ? info.desc : info.subdescs[i]; 703 print.flags = info.flags; 704 print.compat = compat; 705 print.descriptions = descriptions; 706 print.precision = info.precision; 707 708 print.min_val = info.data[i].min_val; 709 print.max_val = info.data[i].max_val; 710 print.underflow = info.data[i].underflow; 711 print.overflow = info.data[i].overflow; 712 print.vec.resize(info.data[i].cvec.size()); 713 for (off_type j = 0; j < print.vec.size(); ++j) 714 print.vec[j] = (Result)info.data[i].cvec[j]; 715 print.sum = info.data[i].sum; 716 print.squares = info.data[i].squares; 717 print.samples = info.data[i].samples; 718 719 print.fancy = info.data[i].fancy; 720 if (!print.fancy) { 721 const DistStor::Params *params = 722 safe_cast<const DistStor::Params *>(info.storageParams); 723 724 print.min = params->min; 725 print.max = params->max; 726 print.bucket_size = params->bucket_size; 727 print.size = params->buckets; 728 } 729 730 print(*stream); 731 } 732} 733 734void 735Text::visit(const FormulaInfoBase &info) 736{ 737 visit((const VectorInfoBase &)info); 738} 739 740bool 741initText(const string &filename, bool desc, bool compat) 742{ 743 static Text text; 744 static bool connected = false; 745 746 if (connected) 747 return false; 748 749 extern list<Output *> OutputList; 750 751 text.open(*simout.find(filename)); 752 text.descriptions = desc; 753 text.compat = compat; 754 OutputList.push_back(&text); 755 connected = true; 756 757 return true; 758} 759 760/* namespace Stats */ } 761