text.cc revision 6125:3bbbdd324a60
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 Counter min; 355 Counter max; 356 Counter bucket_size; 357 size_type size; 358 bool fancy; 359 360 const DistData &data; 361 362 DistPrint(const Text *text, const DistInfoBase &info); 363 DistPrint(const Text *text, const VectorDistInfoBase &info, int i); 364 void init(const Text *text, const Info &info, const DistParams *params); 365 void operator()(ostream &stream) const; 366}; 367 368DistPrint::DistPrint(const Text *text, const DistInfoBase &info) 369 : data(info.data) 370{ 371 init(text, info, safe_cast<const DistParams *>(info.storageParams)); 372} 373 374DistPrint::DistPrint(const Text *text, const VectorDistInfoBase &info, int i) 375 : data(info.data[i]) 376{ 377 init(text, info, safe_cast<const DistParams *>(info.storageParams)); 378 379 name = info.name + "_" + 380 (info.subnames[i].empty() ? (to_string(i)) : info.subnames[i]); 381 382 if (!info.subdescs[i].empty()) 383 desc = info.subdescs[i]; 384} 385 386void 387DistPrint::init(const Text *text, const Info &info, const DistParams *params) 388{ 389 name = info.name; 390 desc = info.desc; 391 flags = info.flags; 392 precision = info.precision; 393 compat = text->compat; 394 descriptions = text->descriptions; 395 396 fancy = params->fancy; 397 min = params->min; 398 max = params->max; 399 bucket_size = params->bucket_size; 400 size = params->buckets; 401} 402 403void 404DistPrint::operator()(ostream &stream) const 405{ 406 Result stdev = NAN; 407 if (data.samples) 408 stdev = sqrt((data.samples * data.squares - data.sum * data.sum) / 409 (data.samples * (data.samples - 1.0))); 410 411 if (fancy) { 412 ScalarPrint print; 413 string base = name + (compat ? "_" : "::"); 414 415 print.precision = precision; 416 print.flags = flags; 417 print.compat = compat; 418 print.descriptions = descriptions; 419 print.desc = desc; 420 print.pdf = NAN; 421 print.cdf = NAN; 422 423 print.name = base + "mean"; 424 print.value = data.samples ? data.sum / data.samples : NAN; 425 print(stream); 426 427 print.name = base + "stdev"; 428 print.value = stdev; 429 print(stream); 430 431 print.name = "**Ignore: " + base + "TOT"; 432 print.value = data.samples; 433 print(stream); 434 return; 435 } 436 437 assert(size == data.cvec.size()); 438 439 Result total = 0.0; 440 441 total += data.underflow; 442 for (off_type i = 0; i < size; ++i) 443 total += data.cvec[i]; 444 total += data.overflow; 445 446 string base = name + (compat ? "." : "::"); 447 448 ScalarPrint print; 449 print.desc = compat ? "" : desc; 450 print.flags = flags; 451 print.compat = compat; 452 print.descriptions = descriptions; 453 print.precision = precision; 454 print.pdf = NAN; 455 print.cdf = NAN; 456 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 464 print.name = base + "samples"; 465 print.value = data.samples; 466 print(stream); 467 468 print.name = base + "min_value"; 469 print.value = data.min_val; 470 print(stream); 471 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); 480 } 481 482 if (!compat) { 483 for (off_type i = 0; i < size; ++i) { 484 stringstream namestr; 485 namestr << base; 486 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; 492 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; 533 print.cdf += print.pdf; 534 } else { 535 print.pdf = NAN; 536 print.cdf = NAN; 537 } 538 print(stream); 539 } 540 541 print.pdf = NAN; 542 print.cdf = NAN; 543 544 if (!compat) { 545 print.name = base + "total"; 546 print.value = total; 547 print(stream); 548 } 549 550 print.name = base + "max_value"; 551 print.value = data.max_val; 552 print(stream); 553 554 if (!compat && data.samples != 0) { 555 print.name = base + "mean"; 556 print.value = data.sum / data.samples; 557 print(stream); 558 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); 566} 567 568void 569Text::visit(const ScalarInfoBase &info) 570{ 571 if (noOutput(info)) 572 return; 573 574 ScalarPrint print; 575 print.value = info.result(); 576 print.name = info.name; 577 print.desc = info.desc; 578 print.flags = info.flags; 579 print.compat = compat; 580 print.descriptions = descriptions; 581 print.precision = info.precision; 582 print.pdf = NAN; 583 print.cdf = NAN; 584 585 print(*stream); 586} 587 588void 589Text::visit(const VectorInfoBase &info) 590{ 591 if (noOutput(info)) 592 return; 593 594 size_type size = info.size(); 595 VectorPrint print; 596 597 print.name = info.name; 598 print.desc = info.desc; 599 print.flags = info.flags; 600 print.compat = compat; 601 print.descriptions = descriptions; 602 print.precision = info.precision; 603 print.vec = info.result(); 604 print.total = info.total(); 605 606 if (!info.subnames.empty()) { 607 for (off_type i = 0; i < size; ++i) { 608 if (!info.subnames[i].empty()) { 609 print.subnames = info.subnames; 610 print.subnames.resize(size); 611 for (off_type i = 0; i < size; ++i) { 612 if (!info.subnames[i].empty() && 613 !info.subdescs[i].empty()) { 614 print.subdescs = info.subdescs; 615 print.subdescs.resize(size); 616 break; 617 } 618 } 619 break; 620 } 621 } 622 } 623 624 print(*stream); 625} 626 627void 628Text::visit(const Vector2dInfoBase &info) 629{ 630 if (noOutput(info)) 631 return; 632 633 bool havesub = false; 634 VectorPrint print; 635 636 print.subnames = info.y_subnames; 637 print.flags = info.flags; 638 print.compat = compat; 639 print.descriptions = descriptions; 640 print.precision = info.precision; 641 642 if (!info.subnames.empty()) { 643 for (off_type i = 0; i < info.x; ++i) 644 if (!info.subnames[i].empty()) 645 havesub = true; 646 } 647 648 VResult tot_vec(info.y); 649 Result super_total = 0.0; 650 for (off_type i = 0; i < info.x; ++i) { 651 if (havesub && (i >= info.subnames.size() || info.subnames[i].empty())) 652 continue; 653 654 off_type iy = i * info.y; 655 VResult yvec(info.y); 656 657 Result total = 0.0; 658 for (off_type j = 0; j < info.y; ++j) { 659 yvec[j] = info.cvec[iy + j]; 660 tot_vec[j] += yvec[j]; 661 total += yvec[j]; 662 super_total += yvec[j]; 663 } 664 665 print.name = info.name + "_" + 666 (havesub ? info.subnames[i] : to_string(i)); 667 print.desc = info.desc; 668 print.vec = yvec; 669 print.total = total; 670 print(*stream); 671 } 672 673 if ((info.flags & ::Stats::total) && (info.x > 1)) { 674 print.name = info.name; 675 print.desc = info.desc; 676 print.vec = tot_vec; 677 print.total = super_total; 678 print(*stream); 679 } 680} 681 682void 683Text::visit(const DistInfoBase &info) 684{ 685 if (noOutput(info)) 686 return; 687 688 DistPrint print(this, info); 689 print(*stream); 690} 691 692void 693Text::visit(const VectorDistInfoBase &info) 694{ 695 if (noOutput(info)) 696 return; 697 698 for (off_type i = 0; i < info.size(); ++i) { 699 DistPrint print(this, info, i); 700 print(*stream); 701 } 702} 703 704void 705Text::visit(const FormulaInfoBase &info) 706{ 707 visit((const VectorInfoBase &)info); 708} 709 710bool 711initText(const string &filename, bool desc, bool compat) 712{ 713 static Text text; 714 static bool connected = false; 715 716 if (connected) 717 return false; 718 719 extern list<Output *> OutputList; 720 721 text.open(*simout.find(filename)); 722 text.descriptions = desc; 723 text.compat = compat; 724 OutputList.push_back(&text); 725 connected = true; 726 727 return true; 728} 729 730/* namespace Stats */ } 731