text.cc revision 2343
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 29#if defined(__APPLE__) 30#define _GLIBCPP_USE_C99 1 31#endif 32 33#include <iostream> 34#include <fstream> 35#include <string> 36 37#include "base/misc.hh" 38#include "base/statistics.hh" 39#include "base/stats/statdb.hh" 40#include "base/stats/text.hh" 41#include "base/stats/visit.hh" 42 43using namespace std; 44 45#ifndef NAN 46float __nan(); 47/** Define Not a number. */ 48#define NAN (__nan()) 49/** Need to define __nan() */ 50#define __M5_NAN 51#endif 52 53#ifdef __M5_NAN 54float 55__nan() 56{ 57 union { 58 uint32_t ui; 59 float f; 60 } nan; 61 62 nan.ui = 0x7fc00000; 63 return nan.f; 64} 65#endif 66 67namespace Stats { 68 69Text::Text() 70 : mystream(false), stream(NULL), compat(false), descriptions(false) 71{ 72} 73 74Text::Text(std::ostream &stream) 75 : mystream(false), stream(NULL), compat(false), descriptions(false) 76{ 77 open(stream); 78} 79 80Text::Text(const std::string &file) 81 : mystream(false), stream(NULL), compat(false), descriptions(false) 82{ 83 open(file); 84} 85 86 87Text::~Text() 88{ 89 if (mystream) { 90 assert(stream); 91 delete stream; 92 } 93} 94 95void 96Text::open(std::ostream &_stream) 97{ 98 if (stream) 99 panic("stream already set!"); 100 101 mystream = false; 102 stream = &_stream; 103 assert(valid()); 104} 105 106void 107Text::open(const std::string &file) 108{ 109 if (stream) 110 panic("stream already set!"); 111 112 mystream = true; 113 stream = new ofstream(file.c_str(), ios::trunc); 114 assert(valid()); 115} 116 117bool 118Text::valid() const 119{ 120 return stream != NULL; 121} 122 123void 124Text::output() 125{ 126 using namespace Database; 127 128 ccprintf(*stream, "\n---------- Begin Simulation Statistics ----------\n"); 129 stat_list_t::const_iterator i, end = stats().end(); 130 for (i = stats().begin(); i != end; ++i) 131 (*i)->visit(*this); 132 ccprintf(*stream, "\n---------- End Simulation Statistics ----------\n"); 133 stream->flush(); 134} 135 136bool 137Text::noOutput(const StatData &data) 138{ 139 if (!(data.flags & print)) 140 return true; 141 142 if (data.prereq && data.prereq->zero()) 143 return true; 144 145 return false; 146} 147 148string 149ValueToString(Result value, int precision, bool compat) 150{ 151 stringstream val; 152 153 if (!isnan(value)) { 154 if (precision != -1) 155 val.precision(precision); 156 else if (value == rint(value)) 157 val.precision(0); 158 159 val.unsetf(ios::showpoint); 160 val.setf(ios::fixed); 161 val << value; 162 } else { 163 val << (compat ? "<err: div-0>" : "no value"); 164 } 165 166 return val.str(); 167} 168 169struct ScalarPrint 170{ 171 Result value; 172 string name; 173 string desc; 174 StatFlags flags; 175 bool compat; 176 bool descriptions; 177 int precision; 178 Result pdf; 179 Result cdf; 180 181 void operator()(ostream &stream) const; 182}; 183 184void 185ScalarPrint::operator()(ostream &stream) const 186{ 187 if (flags & nozero && value == 0.0 || 188 flags & nonan && isnan(value)) 189 return; 190 191 stringstream pdfstr, cdfstr; 192 193 if (!isnan(pdf)) 194 ccprintf(pdfstr, "%.2f%%", pdf * 100.0); 195 196 if (!isnan(cdf)) 197 ccprintf(cdfstr, "%.2f%%", cdf * 100.0); 198 199 if (compat && flags & __substat) { 200 ccprintf(stream, "%32s %12s %10s %10s", name, 201 ValueToString(value, precision, compat), pdfstr, cdfstr); 202 } else { 203 ccprintf(stream, "%-40s %12s %10s %10s", name, 204 ValueToString(value, precision, compat), pdfstr, cdfstr); 205 } 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; 221 bool compat; 222 bool descriptions; 223 int precision; 224 VResult vec; 225 Result total; 226 227 void operator()(ostream &stream) const; 228}; 229 230void 231VectorPrint::operator()(std::ostream &stream) const 232{ 233 int _size = vec.size(); 234 Result _total = 0.0; 235 236 if (flags & (pdf | cdf)) { 237 for (int i = 0; i < _size; ++i) { 238 _total += vec[i]; 239 } 240 } 241 242 string base = name + (compat ? "_" : "::"); 243 244 ScalarPrint print; 245 print.name = name; 246 print.desc = desc; 247 print.precision = precision; 248 print.descriptions = descriptions; 249 print.flags = flags; 250 print.pdf = NAN; 251 print.cdf = NAN; 252 253 bool havesub = !subnames.empty(); 254 255 if (_size == 1) { 256 print.value = vec[0]; 257 print(stream); 258 } else if (!compat) { 259 for (int i = 0; i < _size; ++i) { 260 if (havesub && (i >= subnames.size() || subnames[i].empty())) 261 continue; 262 263 print.name = base + (havesub ? subnames[i] : to_string(i)); 264 print.desc = subdescs.empty() ? desc : subdescs[i]; 265 print.value = vec[i]; 266 267 if (_total && (flags & pdf)) { 268 print.pdf = vec[i] / _total; 269 print.cdf += print.pdf; 270 } 271 272 print(stream); 273 } 274 275 if (flags & ::Stats::total) { 276 print.name = base + "total"; 277 print.desc = desc; 278 print.value = total; 279 print(stream); 280 } 281 } else { 282 if (flags & ::Stats::total) { 283 print.value = total; 284 print(stream); 285 } 286 287 Result _pdf = 0.0; 288 Result _cdf = 0.0; 289 if (flags & dist) { 290 ccprintf(stream, "%s.start_dist\n", name); 291 for (int i = 0; i < _size; ++i) { 292 print.name = havesub ? subnames[i] : to_string(i); 293 print.desc = subdescs.empty() ? desc : subdescs[i]; 294 print.flags |= __substat; 295 print.value = vec[i]; 296 297 if (_total) { 298 _pdf = vec[i] / _total; 299 _cdf += _pdf; 300 } 301 302 if (flags & pdf) 303 print.pdf = _pdf; 304 if (flags & cdf) 305 print.cdf = _cdf; 306 307 print(stream); 308 } 309 ccprintf(stream, "%s.end_dist\n", name); 310 } else { 311 for (int i = 0; i < _size; ++i) { 312 if (havesub && subnames[i].empty()) 313 continue; 314 315 print.name = base; 316 print.name += havesub ? subnames[i] : to_string(i); 317 print.desc = subdescs.empty() ? desc : subdescs[i]; 318 print.value = vec[i]; 319 320 if (_total) { 321 _pdf = vec[i] / _total; 322 _cdf += _pdf; 323 } else { 324 _pdf = _cdf = NAN; 325 } 326 327 if (flags & pdf) { 328 print.pdf = _pdf; 329 print.cdf = _cdf; 330 } 331 332 print(stream); 333 } 334 } 335 } 336} 337 338struct DistPrint 339{ 340 string name; 341 string desc; 342 StatFlags flags; 343 bool compat; 344 bool descriptions; 345 int precision; 346 347 Result min_val; 348 Result max_val; 349 Result underflow; 350 Result overflow; 351 VResult vec; 352 Result sum; 353 Result squares; 354 Result samples; 355 356 Counter min; 357 Counter max; 358 Counter bucket_size; 359 int size; 360 bool fancy; 361 362 void operator()(ostream &stream) const; 363}; 364 365void 366DistPrint::operator()(ostream &stream) const 367{ 368 if (fancy) { 369 ScalarPrint print; 370 string base = name + (compat ? "_" : "::"); 371 372 print.precision = precision; 373 print.flags = flags; 374 print.compat = compat; 375 print.descriptions = descriptions; 376 print.desc = desc; 377 print.pdf = NAN; 378 print.cdf = NAN; 379 380 print.name = base + "mean"; 381 print.value = samples ? sum / samples : NAN; 382 print(stream); 383 384 print.name = base + "stdev"; 385 print.value = samples ? sqrt((samples * squares - sum * sum) / 386 (samples * (samples - 1.0))) : NAN; 387 print(stream); 388 389 print.name = "**Ignore: " + base + "TOT"; 390 print.value = samples; 391 print(stream); 392 return; 393 } 394 395 assert(size == vec.size()); 396 397 Result total = 0.0; 398 399 total += underflow; 400 for (int i = 0; i < size; ++i) 401 total += vec[i]; 402 total += overflow; 403 404 string base = name + (compat ? "." : "::"); 405 406 ScalarPrint print; 407 print.desc = compat ? "" : desc; 408 print.flags = flags; 409 print.compat = compat; 410 print.descriptions = descriptions; 411 print.precision = precision; 412 print.pdf = NAN; 413 print.cdf = NAN; 414 415 if (compat) { 416 ccprintf(stream, "%-42s", base + "start_dist"); 417 if (descriptions && !desc.empty()) 418 ccprintf(stream, " # %s", desc); 419 stream << endl; 420 } 421 422 print.name = base + "samples"; 423 print.value = samples; 424 print(stream); 425 426 print.name = base + "min_value"; 427 print.value = min_val; 428 print(stream); 429 430 if (!compat || underflow > 0.0) { 431 print.name = base + "underflows"; 432 print.value = underflow; 433 if (!compat && total) { 434 print.pdf = underflow / total; 435 print.cdf += print.pdf; 436 } 437 print(stream); 438 } 439 440 441 if (!compat) { 442 for (int i = 0; i < size; ++i) { 443 stringstream namestr; 444 namestr << name; 445 446 Counter low = i * bucket_size + min; 447 Counter high = ::min(low + bucket_size, max); 448 namestr << low; 449 if (low < high) 450 namestr << "-" << high; 451 452 print.name = namestr.str(); 453 print.value = vec[i]; 454 if (total) { 455 print.pdf = vec[i] / total; 456 print.cdf += print.pdf; 457 } 458 print(stream); 459 } 460 461 } else { 462 Counter _min; 463 Result _pdf; 464 Result _cdf = 0.0; 465 466 print.flags = flags | __substat; 467 468 for (int i = 0; i < size; ++i) { 469 if (flags & nozero && vec[i] == 0.0 || 470 flags & nonan && isnan(vec[i])) 471 continue; 472 473 _min = i * bucket_size + min; 474 _pdf = vec[i] / total * 100.0; 475 _cdf += _pdf; 476 477 478 print.name = ValueToString(_min, 0, compat); 479 print.value = vec[i]; 480 print.pdf = (flags & pdf) ? _pdf : NAN; 481 print.cdf = (flags & cdf) ? _cdf : NAN; 482 print(stream); 483 } 484 485 print.flags = flags; 486 } 487 488 if (!compat || overflow > 0.0) { 489 print.name = base + "overflows"; 490 print.value = overflow; 491 if (!compat && total) { 492 print.pdf = overflow / total; 493 print.cdf += print.pdf; 494 } else { 495 print.pdf = NAN; 496 print.cdf = NAN; 497 } 498 print(stream); 499 } 500 501 print.pdf = NAN; 502 print.cdf = NAN; 503 504 if (!compat) { 505 print.name = base + "total"; 506 print.value = total; 507 print(stream); 508 } 509 510 print.name = base + "max_value"; 511 print.value = max_val; 512 print(stream); 513 514 if (!compat && samples != 0) { 515 print.name = base + "mean"; 516 print.value = sum / samples; 517 print(stream); 518 519 print.name = base + "stdev"; 520 print.value = sqrt((samples * squares - sum * sum) / 521 (samples * (samples - 1.0))); 522 print(stream); 523 } 524 525 if (compat) 526 ccprintf(stream, "%send_dist\n\n", base); 527} 528 529void 530Text::visit(const ScalarData &data) 531{ 532 if (noOutput(data)) 533 return; 534 535 ScalarPrint print; 536 print.value = data.result(); 537 print.name = data.name; 538 print.desc = data.desc; 539 print.flags = data.flags; 540 print.compat = compat; 541 print.descriptions = descriptions; 542 print.precision = data.precision; 543 print.pdf = NAN; 544 print.cdf = NAN; 545 546 print(*stream); 547} 548 549void 550Text::visit(const VectorData &data) 551{ 552 if (noOutput(data)) 553 return; 554 555 int size = data.size(); 556 VectorPrint print; 557 558 print.name = data.name; 559 print.desc = data.desc; 560 print.flags = data.flags; 561 print.compat = compat; 562 print.descriptions = descriptions; 563 print.precision = data.precision; 564 print.vec = data.result(); 565 print.total = data.total(); 566 567 if (!data.subnames.empty()) { 568 for (int i = 0; i < size; ++i) { 569 if (!data.subnames[i].empty()) { 570 print.subnames = data.subnames; 571 print.subnames.resize(size); 572 for (int i = 0; i < size; ++i) { 573 if (!data.subnames[i].empty() && 574 !data.subdescs[i].empty()) { 575 print.subdescs = data.subdescs; 576 print.subdescs.resize(size); 577 break; 578 } 579 } 580 break; 581 } 582 } 583 } 584 585 print(*stream); 586} 587 588void 589Text::visit(const Vector2dData &data) 590{ 591 if (noOutput(data)) 592 return; 593 594 bool havesub = false; 595 VectorPrint print; 596 597 print.subnames = data.y_subnames; 598 print.flags = data.flags; 599 print.compat = compat; 600 print.descriptions = descriptions; 601 print.precision = data.precision; 602 603 if (!data.subnames.empty()) { 604 for (int i = 0; i < data.x; ++i) 605 if (!data.subnames[i].empty()) 606 havesub = true; 607 } 608 609 VResult tot_vec(data.y); 610 Result super_total = 0.0; 611 for (int i = 0; i < data.x; ++i) { 612 if (havesub && (i >= data.subnames.size() || data.subnames[i].empty())) 613 continue; 614 615 int iy = i * data.y; 616 VResult yvec(data.y); 617 618 Result total = 0.0; 619 for (int j = 0; j < data.y; ++j) { 620 yvec[j] = data.cvec[iy + j]; 621 tot_vec[j] += yvec[j]; 622 total += yvec[j]; 623 super_total += yvec[j]; 624 } 625 626 print.name = data.name + "_" + (havesub ? data.subnames[i] : to_string(i)); 627 print.desc = data.desc; 628 print.vec = yvec; 629 print.total = total; 630 print(*stream); 631 } 632 633 if ((data.flags & ::Stats::total) && (data.x > 1)) { 634 print.name = data.name; 635 print.desc = data.desc; 636 print.vec = tot_vec; 637 print.total = super_total; 638 print(*stream); 639 } 640} 641 642void 643Text::visit(const DistData &data) 644{ 645 if (noOutput(data)) 646 return; 647 648 DistPrint print; 649 650 print.name = data.name; 651 print.desc = data.desc; 652 print.flags = data.flags; 653 print.compat = compat; 654 print.descriptions = descriptions; 655 print.precision = data.precision; 656 657 print.min_val = data.data.min_val; 658 print.max_val = data.data.max_val; 659 print.underflow = data.data.underflow; 660 print.overflow = data.data.overflow; 661 print.vec.resize(data.data.cvec.size()); 662 for (int i = 0; i < print.vec.size(); ++i) 663 print.vec[i] = (Result)data.data.cvec[i]; 664 print.sum = data.data.sum; 665 print.squares = data.data.squares; 666 print.samples = data.data.samples; 667 668 print.min = data.data.min; 669 print.max = data.data.max; 670 print.bucket_size = data.data.bucket_size; 671 print.size = data.data.size; 672 print.fancy = data.data.fancy; 673 674 print(*stream); 675} 676 677void 678Text::visit(const VectorDistData &data) 679{ 680 if (noOutput(data)) 681 return; 682 683 for (int i = 0; i < data.size(); ++i) { 684 DistPrint print; 685 686 print.name = data.name + 687 (data.subnames[i].empty() ? ("_" + to_string(i)) : data.subnames[i]); 688 print.desc = data.subdescs[i].empty() ? data.desc : data.subdescs[i]; 689 print.flags = data.flags; 690 print.compat = compat; 691 print.descriptions = descriptions; 692 print.precision = data.precision; 693 694 print.min_val = data.data[i].min_val; 695 print.max_val = data.data[i].max_val; 696 print.underflow = data.data[i].underflow; 697 print.overflow = data.data[i].overflow; 698 print.vec.resize(data.data[i].cvec.size()); 699 for (int j = 0; j < print.vec.size(); ++j) 700 print.vec[j] = (Result)data.data[i].cvec[j]; 701 print.sum = data.data[i].sum; 702 print.squares = data.data[i].squares; 703 print.samples = data.data[i].samples; 704 705 print.min = data.data[i].min; 706 print.max = data.data[i].max; 707 print.bucket_size = data.data[i].bucket_size; 708 print.size = data.data[i].size; 709 print.fancy = data.data[i].fancy; 710 711 print(*stream); 712 } 713} 714 715void 716Text::visit(const FormulaData &data) 717{ 718 visit((const VectorData &)data); 719} 720 721/* namespace Stats */ } 722