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