statistics.cc revision 10011:69bd1011dcf3
112955Sgabeblack@google.com/* 212955Sgabeblack@google.com * Copyright (c) 2003-2005 The Regents of The University of Michigan 312955Sgabeblack@google.com * All rights reserved. 412955Sgabeblack@google.com * 512955Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 612955Sgabeblack@google.com * modification, are permitted provided that the following conditions are 712955Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 812955Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 912955Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 1012955Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 1112955Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 1212955Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 1312955Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 1412955Sgabeblack@google.com * this software without specific prior written permission. 1512955Sgabeblack@google.com * 1612955Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1712955Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1812955Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1912955Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2012955Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2112955Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2212955Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2312955Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2412955Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2512955Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2612955Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2712955Sgabeblack@google.com * 2812955Sgabeblack@google.com * Authors: Nathan Binkert 2912955Sgabeblack@google.com */ 3012955Sgabeblack@google.com 3112955Sgabeblack@google.com#include <fstream> 3212955Sgabeblack@google.com#include <iomanip> 3313193Sgabeblack@google.com#include <list> 3412955Sgabeblack@google.com#include <map> 3512955Sgabeblack@google.com#include <string> 3612955Sgabeblack@google.com 3712957Sgabeblack@google.com#include "base/callback.hh" 3812955Sgabeblack@google.com#include "base/cprintf.hh" 3912955Sgabeblack@google.com#include "base/debug.hh" 4013206Sgabeblack@google.com#include "base/hostinfo.hh" 4113063Sgabeblack@google.com#include "base/misc.hh" 4213206Sgabeblack@google.com#include "base/statistics.hh" 4312955Sgabeblack@google.com#include "base/str.hh" 4412955Sgabeblack@google.com#include "base/time.hh" 4512955Sgabeblack@google.com#include "base/trace.hh" 4612955Sgabeblack@google.com 4712955Sgabeblack@google.comusing namespace std; 4812955Sgabeblack@google.com 4912955Sgabeblack@google.comnamespace Stats { 5012955Sgabeblack@google.com 5112955Sgabeblack@google.comstd::string Info::separatorString = "::"; 5212955Sgabeblack@google.com 5312955Sgabeblack@google.com// We wrap these in a function to make sure they're built in time. 5412955Sgabeblack@google.comlist<Info *> & 5512955Sgabeblack@google.comstatsList() 5612955Sgabeblack@google.com{ 5712955Sgabeblack@google.com static list<Info *> the_list; 5812957Sgabeblack@google.com return the_list; 5912957Sgabeblack@google.com} 6012955Sgabeblack@google.com 6112955Sgabeblack@google.comMapType & 6212955Sgabeblack@google.comstatsMap() 6312955Sgabeblack@google.com{ 6412955Sgabeblack@google.com static MapType the_map; 6512955Sgabeblack@google.com return the_map; 6612955Sgabeblack@google.com} 6712955Sgabeblack@google.com 6812955Sgabeblack@google.comvoid 6912955Sgabeblack@google.comInfoAccess::setInfo(Info *info) 7012955Sgabeblack@google.com{ 7112955Sgabeblack@google.com if (statsMap().find(this) != statsMap().end()) 7212955Sgabeblack@google.com panic("shouldn't register stat twice!"); 7312955Sgabeblack@google.com 7412955Sgabeblack@google.com statsList().push_back(info); 7513208Sgabeblack@google.com 7613208Sgabeblack@google.com#ifndef NDEBUG 7713208Sgabeblack@google.com pair<MapType::iterator, bool> result = 7812955Sgabeblack@google.com#endif 7912955Sgabeblack@google.com statsMap().insert(make_pair(this, info)); 8012955Sgabeblack@google.com assert(result.second && "this should never fail"); 8112955Sgabeblack@google.com assert(statsMap().find(this) != statsMap().end()); 8212955Sgabeblack@google.com} 8312955Sgabeblack@google.com 8412955Sgabeblack@google.comvoid 8512955Sgabeblack@google.comInfoAccess::setParams(const StorageParams *params) 8612955Sgabeblack@google.com{ 8712955Sgabeblack@google.com info()->storageParams = params; 8812955Sgabeblack@google.com} 8912955Sgabeblack@google.com 9012955Sgabeblack@google.comvoid 9112955Sgabeblack@google.comInfoAccess::setInit() 9212955Sgabeblack@google.com{ 9312955Sgabeblack@google.com info()->flags.set(init); 9412955Sgabeblack@google.com} 9512955Sgabeblack@google.com 9612955Sgabeblack@google.comInfo * 9712955Sgabeblack@google.comInfoAccess::info() 9812955Sgabeblack@google.com{ 9912955Sgabeblack@google.com MapType::const_iterator i = statsMap().find(this); 10012955Sgabeblack@google.com assert(i != statsMap().end()); 10113206Sgabeblack@google.com return (*i).second; 10213206Sgabeblack@google.com} 10313206Sgabeblack@google.com 10413206Sgabeblack@google.comconst Info * 10513206Sgabeblack@google.comInfoAccess::info() const 10613208Sgabeblack@google.com{ 10713208Sgabeblack@google.com MapType::const_iterator i = statsMap().find(this); 10813206Sgabeblack@google.com assert(i != statsMap().end()); 10913206Sgabeblack@google.com return (*i).second; 11013206Sgabeblack@google.com} 11113206Sgabeblack@google.com 11213208Sgabeblack@google.comStorageParams::~StorageParams() 11313208Sgabeblack@google.com{ 11413206Sgabeblack@google.com} 11513208Sgabeblack@google.com 11613208Sgabeblack@google.comNameMapType & 11713206Sgabeblack@google.comnameMap() 11813206Sgabeblack@google.com{ 11913206Sgabeblack@google.com static NameMapType the_map; 12013206Sgabeblack@google.com return the_map; 12113206Sgabeblack@google.com} 12213206Sgabeblack@google.com 12313206Sgabeblack@google.comint Info::id_count = 0; 12413208Sgabeblack@google.com 12513208Sgabeblack@google.comint debug_break_id = -1; 12613206Sgabeblack@google.com 12713206Sgabeblack@google.comInfo::Info() 12813206Sgabeblack@google.com : flags(none), precision(-1), prereq(0), storageParams(NULL) 12913206Sgabeblack@google.com{ 13013208Sgabeblack@google.com id = id_count++; 13113208Sgabeblack@google.com if (debug_break_id >= 0 and debug_break_id == id) 13213206Sgabeblack@google.com Debug::breakpoint(); 13313208Sgabeblack@google.com} 13413208Sgabeblack@google.com 13513206Sgabeblack@google.comInfo::~Info() 13613206Sgabeblack@google.com{ 13713206Sgabeblack@google.com} 13813206Sgabeblack@google.com 13912957Sgabeblack@google.combool 14012955Sgabeblack@google.comvalidateStatName(const string &name) 14112955Sgabeblack@google.com{ 14212955Sgabeblack@google.com if (name.empty()) 14312955Sgabeblack@google.com return false; 14412955Sgabeblack@google.com 14512955Sgabeblack@google.com vector<string> vec; 14612955Sgabeblack@google.com tokenize(vec, name, '.'); 14712955Sgabeblack@google.com vector<string>::const_iterator item = vec.begin(); 14812957Sgabeblack@google.com while (item != vec.end()) { 14913063Sgabeblack@google.com if (item->empty()) 15012957Sgabeblack@google.com return false; 15113208Sgabeblack@google.com 15213208Sgabeblack@google.com string::const_iterator c = item->begin(); 15313208Sgabeblack@google.com 15413208Sgabeblack@google.com // The first character is different 15512955Sgabeblack@google.com if (!isalpha(*c) && *c != '_') 15612955Sgabeblack@google.com return false; 15712955Sgabeblack@google.com 15812955Sgabeblack@google.com // The rest of the characters have different rules. 15912955Sgabeblack@google.com while (++c != item->end()) { 16012955Sgabeblack@google.com if (!isalnum(*c) && *c != '_') 16112955Sgabeblack@google.com return false; 16212955Sgabeblack@google.com } 16312955Sgabeblack@google.com 16412955Sgabeblack@google.com ++item; 165 } 166 167 return true; 168} 169 170void 171Info::setName(const string &name) 172{ 173 if (!validateStatName(name)) 174 panic("invalid stat name '%s'", name); 175 176 pair<NameMapType::iterator, bool> p = 177 nameMap().insert(make_pair(name, this)); 178 179 Info *other = p.first->second; 180 bool result = p.second; 181 182 if (!result) { 183 // using other->name instead of just name to avoid a compiler 184 // warning. They should be the same. 185 panic("same statistic name used twice! name=%s\n", other->name); 186 } 187 188 this->name = name; 189} 190 191bool 192Info::less(Info *stat1, Info *stat2) 193{ 194 const string &name1 = stat1->name; 195 const string &name2 = stat2->name; 196 197 vector<string> v1; 198 vector<string> v2; 199 200 tokenize(v1, name1, '.'); 201 tokenize(v2, name2, '.'); 202 203 size_type last = min(v1.size(), v2.size()) - 1; 204 for (off_type i = 0; i < last; ++i) 205 if (v1[i] != v2[i]) 206 return v1[i] < v2[i]; 207 208 // Special compare for last element. 209 if (v1[last] == v2[last]) 210 return v1.size() < v2.size(); 211 else 212 return v1[last] < v2[last]; 213 214 return false; 215} 216 217bool 218Info::baseCheck() const 219{ 220 if (!(flags & Stats::init)) { 221#ifdef DEBUG 222 cprintf("this is stat number %d\n", id); 223#endif 224 panic("Not all stats have been initialized"); 225 return false; 226 } 227 228 if ((flags & display) && name.empty()) { 229 panic("all printable stats must be named"); 230 return false; 231 } 232 233 return true; 234} 235 236void 237Info::enable() 238{ 239} 240 241void 242VectorInfo::enable() 243{ 244 size_type s = size(); 245 if (subnames.size() < s) 246 subnames.resize(s); 247 if (subdescs.size() < s) 248 subdescs.resize(s); 249} 250 251void 252VectorDistInfo::enable() 253{ 254 size_type s = size(); 255 if (subnames.size() < s) 256 subnames.resize(s); 257 if (subdescs.size() < s) 258 subdescs.resize(s); 259} 260 261void 262Vector2dInfo::enable() 263{ 264 if (subnames.size() < x) 265 subnames.resize(x); 266 if (subdescs.size() < x) 267 subdescs.resize(x); 268 if (y_subnames.size() < y) 269 y_subnames.resize(y); 270} 271 272void 273HistStor::grow_out() 274{ 275 int size = cvec.size(); 276 int zero = size / 2; // round down! 277 int top_half = zero + (size - zero + 1) / 2; // round up! 278 int bottom_half = (size - zero) / 2; // round down! 279 280 // grow down 281 int low_pair = zero - 1; 282 for (int i = zero - 1; i >= bottom_half; i--) { 283 cvec[i] = cvec[low_pair]; 284 if (low_pair - 1 >= 0) 285 cvec[i] += cvec[low_pair - 1]; 286 low_pair -= 2; 287 } 288 assert(low_pair == 0 || low_pair == -1 || low_pair == -2); 289 290 for (int i = bottom_half - 1; i >= 0; i--) 291 cvec[i] = Counter(); 292 293 // grow up 294 int high_pair = zero; 295 for (int i = zero; i < top_half; i++) { 296 cvec[i] = cvec[high_pair]; 297 if (high_pair + 1 < size) 298 cvec[i] += cvec[high_pair + 1]; 299 high_pair += 2; 300 } 301 assert(high_pair == size || high_pair == size + 1); 302 303 for (int i = top_half; i < size; i++) 304 cvec[i] = Counter(); 305 306 max_bucket *= 2; 307 min_bucket *= 2; 308 bucket_size *= 2; 309} 310 311void 312HistStor::grow_convert() 313{ 314 int size = cvec.size(); 315 int half = (size + 1) / 2; // round up! 316 //bool even = (size & 1) == 0; 317 318 int pair = size - 1; 319 for (int i = size - 1; i >= half; --i) { 320 cvec[i] = cvec[pair]; 321 if (pair - 1 >= 0) 322 cvec[i] += cvec[pair - 1]; 323 pair -= 2; 324 } 325 326 for (int i = half - 1; i >= 0; i--) 327 cvec[i] = Counter(); 328 329 min_bucket = -max_bucket;// - (even ? bucket_size : 0); 330 bucket_size *= 2; 331} 332 333void 334HistStor::grow_up() 335{ 336 int size = cvec.size(); 337 int half = (size + 1) / 2; // round up! 338 339 int pair = 0; 340 for (int i = 0; i < half; i++) { 341 cvec[i] = cvec[pair]; 342 if (pair + 1 < size) 343 cvec[i] += cvec[pair + 1]; 344 pair += 2; 345 } 346 assert(pair == size || pair == size + 1); 347 348 for (int i = half; i < size; i++) 349 cvec[i] = Counter(); 350 351 max_bucket *= 2; 352 bucket_size *= 2; 353} 354 355void 356HistStor::add(HistStor *hs) 357{ 358 int b_size = hs->size(); 359 assert(size() == b_size); 360 assert(min_bucket == hs->min_bucket); 361 362 sum += hs->sum; 363 logs += hs->logs; 364 squares += hs->squares; 365 samples += hs->samples; 366 367 while(bucket_size > hs->bucket_size) 368 hs->grow_up(); 369 while(bucket_size < hs->bucket_size) 370 grow_up(); 371 372 for (uint32_t i = 0; i < b_size; i++) 373 cvec[i] += hs->cvec[i]; 374} 375 376Formula::Formula() 377{ 378} 379 380Formula::Formula(Temp r) 381{ 382 root = r; 383 setInit(); 384 assert(size()); 385} 386 387const Formula & 388Formula::operator=(Temp r) 389{ 390 assert(!root && "Can't change formulas"); 391 root = r; 392 setInit(); 393 assert(size()); 394 return *this; 395} 396 397const Formula & 398Formula::operator+=(Temp r) 399{ 400 if (root) 401 root = NodePtr(new BinaryNode<std::plus<Result> >(root, r)); 402 else { 403 root = r; 404 setInit(); 405 } 406 407 assert(size()); 408 return *this; 409} 410 411const Formula & 412Formula::operator/=(Temp r) 413{ 414 assert (root); 415 root = NodePtr(new BinaryNode<std::divides<Result> >(root, r)); 416 417 assert(size()); 418 return *this; 419} 420 421void 422Formula::result(VResult &vec) const 423{ 424 if (root) 425 vec = root->result(); 426} 427 428Result 429Formula::total() const 430{ 431 return root ? root->total() : 0.0; 432} 433 434size_type 435Formula::size() const 436{ 437 if (!root) 438 return 0; 439 else 440 return root->size(); 441} 442 443void 444Formula::reset() 445{ 446} 447 448bool 449Formula::zero() const 450{ 451 VResult vec; 452 result(vec); 453 for (VResult::size_type i = 0; i < vec.size(); ++i) 454 if (vec[i] != 0.0) 455 return false; 456 return true; 457} 458 459string 460Formula::str() const 461{ 462 return root ? root->str() : ""; 463} 464 465CallbackQueue dumpQueue; 466CallbackQueue resetQueue; 467 468void 469registerResetCallback(Callback *cb) 470{ 471 resetQueue.add(cb); 472} 473 474bool _enabled = false; 475 476bool 477enabled() 478{ 479 return _enabled; 480} 481 482void 483enable() 484{ 485 if (_enabled) 486 fatal("Stats are already enabled"); 487 488 _enabled = true; 489} 490 491void 492registerDumpCallback(Callback *cb) 493{ 494 dumpQueue.add(cb); 495} 496 497} // namespace Stats 498 499void 500debugDumpStats() 501{ 502 Stats::dump(); 503} 504