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