text.cc revision 7504:ad631c296c9b
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(display)) 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 update(Result val, Result total); 196 void operator()(ostream &stream) const; 197}; 198 199void 200ScalarPrint::update(Result val, Result total) 201{ 202 value = val; 203 if (total) { 204 pdf = val / total; 205 cdf += pdf; 206 } 207} 208 209void 210ScalarPrint::operator()(ostream &stream) const 211{ 212 if ((flags.isSet(nozero) && value == 0.0) || 213 (flags.isSet(nonan) && isnan(value))) 214 return; 215 216 stringstream pdfstr, cdfstr; 217 218 if (!isnan(pdf)) 219 ccprintf(pdfstr, "%.2f%%", pdf * 100.0); 220 221 if (!isnan(cdf)) 222 ccprintf(cdfstr, "%.2f%%", cdf * 100.0); 223 224 ccprintf(stream, "%-40s %12s %10s %10s", name, 225 ValueToString(value, precision), pdfstr, cdfstr); 226 227 if (descriptions) { 228 if (!desc.empty()) 229 ccprintf(stream, " # %s", desc); 230 } 231 stream << endl; 232} 233 234struct VectorPrint 235{ 236 string name; 237 string desc; 238 vector<string> subnames; 239 vector<string> subdescs; 240 Flags flags; 241 bool descriptions; 242 int precision; 243 VResult vec; 244 Result total; 245 246 void operator()(ostream &stream) const; 247}; 248 249void 250VectorPrint::operator()(std::ostream &stream) const 251{ 252 size_type _size = vec.size(); 253 Result _total = 0.0; 254 255 if (flags.isSet(pdf | cdf)) { 256 for (off_type i = 0; i < _size; ++i) { 257 _total += vec[i]; 258 } 259 } 260 261 string base = name + "::"; 262 263 ScalarPrint print; 264 print.name = name; 265 print.desc = desc; 266 print.precision = precision; 267 print.descriptions = descriptions; 268 print.flags = flags; 269 print.pdf = _total ? 0.0 : NAN; 270 print.cdf = _total ? 0.0 : NAN; 271 272 bool havesub = !subnames.empty(); 273 274 if (_size == 1) { 275 print.value = vec[0]; 276 print(stream); 277 return; 278 } 279 280 for (off_type i = 0; i < _size; ++i) { 281 if (havesub && (i >= subnames.size() || subnames[i].empty())) 282 continue; 283 284 print.name = base + (havesub ? subnames[i] : to_string(i)); 285 print.desc = subdescs.empty() ? desc : subdescs[i]; 286 287 print.update(vec[i], _total); 288 print(stream); 289 } 290 291 if (flags.isSet(::Stats::total)) { 292 print.pdf = NAN; 293 print.cdf = NAN; 294 print.name = base + "total"; 295 print.desc = desc; 296 print.value = total; 297 print(stream); 298 } 299} 300 301struct DistPrint 302{ 303 string name; 304 string desc; 305 Flags flags; 306 bool descriptions; 307 int precision; 308 309 Counter min; 310 Counter max; 311 Counter bucket_size; 312 size_type size; 313 DistType type; 314 315 const DistData &data; 316 317 DistPrint(const Text *text, const DistInfo &info); 318 DistPrint(const Text *text, const VectorDistInfo &info, int i); 319 void init(const Text *text, const Info &info, const DistParams *params); 320 void operator()(ostream &stream) const; 321}; 322 323DistPrint::DistPrint(const Text *text, const DistInfo &info) 324 : data(info.data) 325{ 326 init(text, info, safe_cast<const DistParams *>(info.storageParams)); 327} 328 329DistPrint::DistPrint(const Text *text, const VectorDistInfo &info, int i) 330 : data(info.data[i]) 331{ 332 init(text, info, safe_cast<const DistParams *>(info.storageParams)); 333 334 name = info.name + "_" + 335 (info.subnames[i].empty() ? (to_string(i)) : info.subnames[i]); 336 337 if (!info.subdescs[i].empty()) 338 desc = info.subdescs[i]; 339} 340 341void 342DistPrint::init(const Text *text, const Info &info, const DistParams *params) 343{ 344 name = info.name; 345 desc = info.desc; 346 flags = info.flags; 347 precision = info.precision; 348 descriptions = text->descriptions; 349 350 type = params->type; 351 switch (type) { 352 case Dist: 353 min = params->min; 354 max = params->max; 355 bucket_size = params->bucket_size; 356 size = params->buckets; 357 break; 358 case Deviation: 359 break; 360 default: 361 panic("unknown distribution type"); 362 } 363} 364 365void 366DistPrint::operator()(ostream &stream) const 367{ 368 string base = name + "::"; 369 370 ScalarPrint print; 371 print.precision = precision; 372 print.flags = flags; 373 print.descriptions = descriptions; 374 print.desc = desc; 375 print.pdf = NAN; 376 print.cdf = NAN; 377 378 print.name = base + "samples"; 379 print.value = data.samples; 380 print(stream); 381 382 print.name = base + "mean"; 383 print.value = data.samples ? data.sum / data.samples : NAN; 384 print(stream); 385 386 Result stdev = NAN; 387 if (data.samples) 388 stdev = sqrt((data.samples * data.squares - data.sum * data.sum) / 389 (data.samples * (data.samples - 1.0))); 390 print.name = base + "stdev"; 391 print.value = stdev; 392 print(stream); 393 394 if (type == Deviation) 395 return; 396 397 assert(size == data.cvec.size()); 398 399 Result total = 0.0; 400 if (data.underflow != NAN) 401 total += data.underflow; 402 for (off_type i = 0; i < size; ++i) 403 total += data.cvec[i]; 404 if (data.overflow != NAN) 405 total += data.overflow; 406 407 if (total) { 408 print.pdf = 0.0; 409 print.cdf = 0.0; 410 } 411 412 if (data.underflow != NAN) { 413 print.name = base + "underflows"; 414 print.update(data.underflow, total); 415 print(stream); 416 } 417 418 for (off_type i = 0; i < size; ++i) { 419 stringstream namestr; 420 namestr << base; 421 422 Counter low = i * bucket_size + min; 423 Counter high = ::min(low + bucket_size - 1.0, max); 424 namestr << low; 425 if (low < high) 426 namestr << "-" << high; 427 428 print.name = namestr.str(); 429 print.update(data.cvec[i], total); 430 print(stream); 431 } 432 433 if (data.overflow != NAN) { 434 print.name = base + "overflows"; 435 print.update(data.overflow, total); 436 print(stream); 437 } 438 439 print.pdf = NAN; 440 print.cdf = NAN; 441 442 if (data.min_val != NAN) { 443 print.name = base + "min_value"; 444 print.value = data.min_val; 445 print(stream); 446 } 447 448 if (data.max_val != NAN) { 449 print.name = base + "max_value"; 450 print.value = data.max_val; 451 print(stream); 452 } 453 454 print.name = base + "total"; 455 print.value = total; 456 print(stream); 457} 458 459void 460Text::visit(const ScalarInfo &info) 461{ 462 if (noOutput(info)) 463 return; 464 465 ScalarPrint print; 466 print.value = info.result(); 467 print.name = info.name; 468 print.desc = info.desc; 469 print.flags = info.flags; 470 print.descriptions = descriptions; 471 print.precision = info.precision; 472 print.pdf = NAN; 473 print.cdf = NAN; 474 475 print(*stream); 476} 477 478void 479Text::visit(const VectorInfo &info) 480{ 481 if (noOutput(info)) 482 return; 483 484 size_type size = info.size(); 485 VectorPrint print; 486 487 print.name = info.name; 488 print.desc = info.desc; 489 print.flags = info.flags; 490 print.descriptions = descriptions; 491 print.precision = info.precision; 492 print.vec = info.result(); 493 print.total = info.total(); 494 495 if (!info.subnames.empty()) { 496 for (off_type i = 0; i < size; ++i) { 497 if (!info.subnames[i].empty()) { 498 print.subnames = info.subnames; 499 print.subnames.resize(size); 500 for (off_type i = 0; i < size; ++i) { 501 if (!info.subnames[i].empty() && 502 !info.subdescs[i].empty()) { 503 print.subdescs = info.subdescs; 504 print.subdescs.resize(size); 505 break; 506 } 507 } 508 break; 509 } 510 } 511 } 512 513 print(*stream); 514} 515 516void 517Text::visit(const Vector2dInfo &info) 518{ 519 if (noOutput(info)) 520 return; 521 522 bool havesub = false; 523 VectorPrint print; 524 525 print.subnames = info.y_subnames; 526 print.flags = info.flags; 527 print.descriptions = descriptions; 528 print.precision = info.precision; 529 530 if (!info.subnames.empty()) { 531 for (off_type i = 0; i < info.x; ++i) 532 if (!info.subnames[i].empty()) 533 havesub = true; 534 } 535 536 VResult tot_vec(info.y); 537 Result super_total = 0.0; 538 for (off_type i = 0; i < info.x; ++i) { 539 if (havesub && (i >= info.subnames.size() || info.subnames[i].empty())) 540 continue; 541 542 off_type iy = i * info.y; 543 VResult yvec(info.y); 544 545 Result total = 0.0; 546 for (off_type j = 0; j < info.y; ++j) { 547 yvec[j] = info.cvec[iy + j]; 548 tot_vec[j] += yvec[j]; 549 total += yvec[j]; 550 super_total += yvec[j]; 551 } 552 553 print.name = info.name + "_" + 554 (havesub ? info.subnames[i] : to_string(i)); 555 print.desc = info.desc; 556 print.vec = yvec; 557 print.total = total; 558 print(*stream); 559 } 560 561 if (info.flags.isSet(::Stats::total) && (info.x > 1)) { 562 print.name = info.name; 563 print.desc = info.desc; 564 print.vec = tot_vec; 565 print.total = super_total; 566 print(*stream); 567 } 568} 569 570void 571Text::visit(const DistInfo &info) 572{ 573 if (noOutput(info)) 574 return; 575 576 DistPrint print(this, info); 577 print(*stream); 578} 579 580void 581Text::visit(const VectorDistInfo &info) 582{ 583 if (noOutput(info)) 584 return; 585 586 for (off_type i = 0; i < info.size(); ++i) { 587 DistPrint print(this, info, i); 588 print(*stream); 589 } 590} 591 592void 593Text::visit(const FormulaInfo &info) 594{ 595 visit((const VectorInfo &)info); 596} 597 598bool 599initText(const string &filename, bool desc) 600{ 601 static Text text; 602 static bool connected = false; 603 604 if (connected) 605 return false; 606 607 extern list<Output *> OutputList; 608 609 text.open(*simout.find(filename)); 610 text.descriptions = desc; 611 OutputList.push_back(&text); 612 connected = true; 613 614 return true; 615} 616 617/* namespace Stats */ } 618