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