statistics.cc revision 8243
1/* 2 * Copyright (c) 2003-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#include <fstream> 32#include <iomanip> 33#include <list> 34#include <map> 35#include <string> 36 37#include "base/callback.hh" 38#include "base/cprintf.hh" 39#include "base/debug.hh" 40#include "base/hostinfo.hh" 41#include "base/misc.hh" 42#include "base/statistics.hh" 43#include "base/str.hh" 44#include "base/time.hh" 45#include "base/trace.hh" 46 47using namespace std; 48 49namespace Stats { 50 51std::string Info::separatorString = "::"; 52typedef map<const void *, Info *> MapType; 53 54// We wrap these in a function to make sure they're built in time. 55list<Info *> & 56statsList() 57{ 58 static list<Info *> the_list; 59 return the_list; 60} 61 62MapType & 63statsMap() 64{ 65 static MapType the_map; 66 return the_map; 67} 68 69void 70InfoAccess::setInfo(Info *info) 71{ 72 if (statsMap().find(this) != statsMap().end()) 73 panic("shouldn't register stat twice!"); 74 75 statsList().push_back(info); 76 77#ifndef NDEBUG 78 pair<MapType::iterator, bool> result = 79#endif 80 statsMap().insert(make_pair(this, info)); 81 assert(result.second && "this should never fail"); 82 assert(statsMap().find(this) != statsMap().end()); 83} 84 85void 86InfoAccess::setParams(const StorageParams *params) 87{ 88 info()->storageParams = params; 89} 90 91void 92InfoAccess::setInit() 93{ 94 info()->flags.set(init); 95} 96 97Info * 98InfoAccess::info() 99{ 100 MapType::const_iterator i = statsMap().find(this); 101 assert(i != statsMap().end()); 102 return (*i).second; 103} 104 105const Info * 106InfoAccess::info() const 107{ 108 MapType::const_iterator i = statsMap().find(this); 109 assert(i != statsMap().end()); 110 return (*i).second; 111} 112 113StorageParams::~StorageParams() 114{ 115} 116 117typedef map<std::string, Info *> NameMapType; 118NameMapType & 119nameMap() 120{ 121 static NameMapType the_map; 122 return the_map; 123} 124 125int Info::id_count = 0; 126 127int debug_break_id = -1; 128 129Info::Info() 130 : flags(none), precision(-1), prereq(0), storageParams(NULL) 131{ 132 id = id_count++; 133 if (debug_break_id >= 0 and debug_break_id == id) 134 Debug::breakpoint(); 135} 136 137Info::~Info() 138{ 139} 140 141void 142Info::setName(const string &name) 143{ 144 pair<NameMapType::iterator, bool> p = 145 nameMap().insert(make_pair(name, this)); 146 147 Info *other = p.first->second; 148 bool result = p.second; 149 150 if (!result) { 151 // using other->name instead of just name to avoid a compiler 152 // warning. They should be the same. 153 panic("same statistic name used twice! name=%s\n", other->name); 154 } 155 156 this->name = name; 157} 158 159bool 160Info::less(Info *stat1, Info *stat2) 161{ 162 const string &name1 = stat1->name; 163 const string &name2 = stat2->name; 164 165 vector<string> v1; 166 vector<string> v2; 167 168 tokenize(v1, name1, '.'); 169 tokenize(v2, name2, '.'); 170 171 size_type last = min(v1.size(), v2.size()) - 1; 172 for (off_type i = 0; i < last; ++i) 173 if (v1[i] != v2[i]) 174 return v1[i] < v2[i]; 175 176 // Special compare for last element. 177 if (v1[last] == v2[last]) 178 return v1.size() < v2.size(); 179 else 180 return v1[last] < v2[last]; 181 182 return false; 183} 184 185bool 186Info::baseCheck() const 187{ 188 if (!(flags & Stats::init)) { 189#ifdef DEBUG 190 cprintf("this is stat number %d\n", id); 191#endif 192 panic("Not all stats have been initialized"); 193 return false; 194 } 195 196 if ((flags & display) && name.empty()) { 197 panic("all printable stats must be named"); 198 return false; 199 } 200 201 return true; 202} 203 204void 205Info::enable() 206{ 207} 208 209void 210VectorInfo::enable() 211{ 212 size_type s = size(); 213 if (subnames.size() < s) 214 subnames.resize(s); 215 if (subdescs.size() < s) 216 subdescs.resize(s); 217} 218 219void 220VectorDistInfo::enable() 221{ 222 size_type s = size(); 223 if (subnames.size() < s) 224 subnames.resize(s); 225 if (subdescs.size() < s) 226 subdescs.resize(s); 227} 228 229void 230Vector2dInfo::enable() 231{ 232 if (subnames.size() < x) 233 subnames.resize(x); 234 if (subdescs.size() < x) 235 subdescs.resize(x); 236 if (y_subnames.size() < y) 237 y_subnames.resize(y); 238} 239 240void 241HistStor::grow_out() 242{ 243 int size = cvec.size(); 244 int zero = size / 2; // round down! 245 int top_half = zero + (size - zero + 1) / 2; // round up! 246 int bottom_half = (size - zero) / 2; // round down! 247 248 // grow down 249 int low_pair = zero - 1; 250 for (int i = zero - 1; i >= bottom_half; i--) { 251 cvec[i] = cvec[low_pair]; 252 if (low_pair - 1 >= 0) 253 cvec[i] += cvec[low_pair - 1]; 254 low_pair -= 2; 255 } 256 assert(low_pair == 0 || low_pair == -1 || low_pair == -2); 257 258 for (int i = bottom_half - 1; i >= 0; i--) 259 cvec[i] = Counter(); 260 261 // grow up 262 int high_pair = zero; 263 for (int i = zero; i < top_half; i++) { 264 cvec[i] = cvec[high_pair]; 265 if (high_pair + 1 < size) 266 cvec[i] += cvec[high_pair + 1]; 267 high_pair += 2; 268 } 269 assert(high_pair == size || high_pair == size + 1); 270 271 for (int i = top_half; i < size; i++) 272 cvec[i] = Counter(); 273 274 max_bucket *= 2; 275 min_bucket *= 2; 276 bucket_size *= 2; 277} 278 279void 280HistStor::grow_convert() 281{ 282 int size = cvec.size(); 283 int half = (size + 1) / 2; // round up! 284 //bool even = (size & 1) == 0; 285 286 int pair = size - 1; 287 for (int i = size - 1; i >= half; --i) { 288 cvec[i] = cvec[pair]; 289 if (pair - 1 >= 0) 290 cvec[i] += cvec[pair - 1]; 291 pair -= 2; 292 } 293 294 for (int i = half - 1; i >= 0; i--) 295 cvec[i] = Counter(); 296 297 min_bucket = -max_bucket;// - (even ? bucket_size : 0); 298 bucket_size *= 2; 299} 300 301void 302HistStor::grow_up() 303{ 304 int size = cvec.size(); 305 int half = (size + 1) / 2; // round up! 306 307 int pair = 0; 308 for (int i = 0; i < half; i++) { 309 cvec[i] = cvec[pair]; 310 if (pair + 1 < size) 311 cvec[i] += cvec[pair + 1]; 312 pair += 2; 313 } 314 assert(pair == size || pair == size + 1); 315 316 for (int i = half; i < size; i++) 317 cvec[i] = Counter(); 318 319 max_bucket *= 2; 320 bucket_size *= 2; 321} 322 323Formula::Formula() 324{ 325} 326 327Formula::Formula(Temp r) 328{ 329 root = r; 330 setInit(); 331 assert(size()); 332} 333 334const Formula & 335Formula::operator=(Temp r) 336{ 337 assert(!root && "Can't change formulas"); 338 root = r; 339 setInit(); 340 assert(size()); 341 return *this; 342} 343 344const Formula & 345Formula::operator+=(Temp r) 346{ 347 if (root) 348 root = NodePtr(new BinaryNode<std::plus<Result> >(root, r)); 349 else { 350 root = r; 351 setInit(); 352 } 353 354 assert(size()); 355 return *this; 356} 357 358void 359Formula::result(VResult &vec) const 360{ 361 if (root) 362 vec = root->result(); 363} 364 365Result 366Formula::total() const 367{ 368 return root ? root->total() : 0.0; 369} 370 371size_type 372Formula::size() const 373{ 374 if (!root) 375 return 0; 376 else 377 return root->size(); 378} 379 380void 381Formula::reset() 382{ 383} 384 385bool 386Formula::zero() const 387{ 388 VResult vec; 389 result(vec); 390 for (VResult::size_type i = 0; i < vec.size(); ++i) 391 if (vec[i] != 0.0) 392 return false; 393 return true; 394} 395 396string 397Formula::str() const 398{ 399 return root ? root->str() : ""; 400} 401 402void 403enable() 404{ 405 typedef list<Info *>::iterator iter_t; 406 407 iter_t i, end = statsList().end(); 408 for (i = statsList().begin(); i != end; ++i) { 409 Info *info = *i; 410 assert(info); 411 if (!info->check() || !info->baseCheck()) 412 panic("stat check failed for '%s' %d\n", info->name, info->id); 413 } 414 415 off_t j = 0; 416 for (i = statsList().begin(); i != end; ++i) { 417 Info *info = *i; 418 if (!(info->flags & display)) 419 info->name = "__Stat" + to_string(j++); 420 } 421 422 statsList().sort(Info::less); 423 424 for (i = statsList().begin(); i != end; ++i) { 425 Info *info = *i; 426 info->enable(); 427 } 428} 429 430void 431prepare() 432{ 433 list<Info *>::iterator i = statsList().begin(); 434 list<Info *>::iterator end = statsList().end(); 435 while (i != end) { 436 Info *info = *i; 437 info->prepare(); 438 ++i; 439 } 440} 441 442CallbackQueue resetQueue; 443 444void 445reset() 446{ 447 list<Info *>::iterator i = statsList().begin(); 448 list<Info *>::iterator end = statsList().end(); 449 while (i != end) { 450 Info *info = *i; 451 info->reset(); 452 ++i; 453 } 454 455 resetQueue.process(); 456} 457 458void 459registerResetCallback(Callback *cb) 460{ 461 resetQueue.add(cb); 462} 463 464} // namespace Stats 465