statistics.hh revision 14175:8cf7610e44f8
1/* 2 * Copyright (c) 2003-2005 The Regents of The University of Michigan 3 * Copyright (c) 2017, Centre National de la Recherche Scientifique 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer; 10 * redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution; 13 * neither the name of the copyright holders nor the names of its 14 * contributors may be used to endorse or promote products derived from 15 * this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * Authors: Nathan Binkert 30 * Pierre-Yves Peneau 31 */ 32 33/** @file 34 * Declaration of Statistics objects. 35 */ 36 37/** 38* @todo 39* 40* Generalized N-dimensinal vector 41* documentation 42* key stats 43* interval stats 44* -- these both can use the same function that prints out a 45* specific set of stats 46* VectorStandardDeviation totals 47* Document Namespaces 48*/ 49#ifndef __BASE_STATISTICS_HH__ 50#define __BASE_STATISTICS_HH__ 51 52#include <algorithm> 53#include <cassert> 54#ifdef __SUNPRO_CC 55#include <math.h> 56#endif 57#include <cmath> 58#include <functional> 59#include <iosfwd> 60#include <list> 61#include <map> 62#include <memory> 63#include <string> 64#include <vector> 65 66#include "base/stats/info.hh" 67#include "base/stats/output.hh" 68#include "base/stats/types.hh" 69#include "base/cast.hh" 70#include "base/cprintf.hh" 71#include "base/intmath.hh" 72#include "base/str.hh" 73#include "base/types.hh" 74 75class Callback; 76 77/** The current simulated tick. */ 78extern Tick curTick(); 79 80/* A namespace for all of the Statistics */ 81namespace Stats { 82 83template <class Stat, class Base> 84class InfoProxy : public Base 85{ 86 protected: 87 Stat &s; 88 89 public: 90 InfoProxy(Stat &stat) : s(stat) {} 91 92 bool check() const { return s.check(); } 93 void prepare() { s.prepare(); } 94 void reset() { s.reset(); } 95 void 96 visit(Output &visitor) 97 { 98 visitor.visit(*static_cast<Base *>(this)); 99 } 100 bool zero() const { return s.zero(); } 101}; 102 103template <class Stat> 104class ScalarInfoProxy : public InfoProxy<Stat, ScalarInfo> 105{ 106 public: 107 ScalarInfoProxy(Stat &stat) : InfoProxy<Stat, ScalarInfo>(stat) {} 108 109 Counter value() const { return this->s.value(); } 110 Result result() const { return this->s.result(); } 111 Result total() const { return this->s.total(); } 112}; 113 114template <class Stat> 115class VectorInfoProxy : public InfoProxy<Stat, VectorInfo> 116{ 117 protected: 118 mutable VCounter cvec; 119 mutable VResult rvec; 120 121 public: 122 VectorInfoProxy(Stat &stat) : InfoProxy<Stat, VectorInfo>(stat) {} 123 124 size_type size() const { return this->s.size(); } 125 126 VCounter & 127 value() const 128 { 129 this->s.value(cvec); 130 return cvec; 131 } 132 133 const VResult & 134 result() const 135 { 136 this->s.result(rvec); 137 return rvec; 138 } 139 140 Result total() const { return this->s.total(); } 141}; 142 143template <class Stat> 144class DistInfoProxy : public InfoProxy<Stat, DistInfo> 145{ 146 public: 147 DistInfoProxy(Stat &stat) : InfoProxy<Stat, DistInfo>(stat) {} 148}; 149 150template <class Stat> 151class VectorDistInfoProxy : public InfoProxy<Stat, VectorDistInfo> 152{ 153 public: 154 VectorDistInfoProxy(Stat &stat) : InfoProxy<Stat, VectorDistInfo>(stat) {} 155 156 size_type size() const { return this->s.size(); } 157}; 158 159template <class Stat> 160class Vector2dInfoProxy : public InfoProxy<Stat, Vector2dInfo> 161{ 162 public: 163 Vector2dInfoProxy(Stat &stat) : InfoProxy<Stat, Vector2dInfo>(stat) {} 164 165 Result total() const { return this->s.total(); } 166}; 167 168struct StorageParams 169{ 170 virtual ~StorageParams(); 171}; 172 173class InfoAccess 174{ 175 protected: 176 /** Set up an info class for this statistic */ 177 void setInfo(Info *info); 178 /** Save Storage class parameters if any */ 179 void setParams(const StorageParams *params); 180 /** Save Storage class parameters if any */ 181 void setInit(); 182 183 /** Grab the information class for this statistic */ 184 Info *info(); 185 /** Grab the information class for this statistic */ 186 const Info *info() const; 187 188 public: 189 /** 190 * Reset the stat to the default state. 191 */ 192 void reset() { } 193 194 /** 195 * @return true if this stat has a value and satisfies its 196 * requirement as a prereq 197 */ 198 bool zero() const { return true; } 199 200 /** 201 * Check that this stat has been set up properly and is ready for 202 * use 203 * @return true for success 204 */ 205 bool check() const { return true; } 206}; 207 208template <class Derived, template <class> class InfoProxyType> 209class DataWrap : public InfoAccess 210{ 211 public: 212 typedef InfoProxyType<Derived> Info; 213 214 protected: 215 Derived &self() { return *static_cast<Derived *>(this); } 216 217 protected: 218 Info * 219 info() 220 { 221 return safe_cast<Info *>(InfoAccess::info()); 222 } 223 224 public: 225 const Info * 226 info() const 227 { 228 return safe_cast<const Info *>(InfoAccess::info()); 229 } 230 231 protected: 232 /** 233 * Copy constructor, copies are not allowed. 234 */ 235 DataWrap(const DataWrap &stat) = delete; 236 237 /** 238 * Can't copy stats. 239 */ 240 void operator=(const DataWrap &) {} 241 242 public: 243 DataWrap() 244 { 245 this->setInfo(new Info(self())); 246 } 247 248 /** 249 * Set the name and marks this stat to print at the end of simulation. 250 * @param name The new name. 251 * @return A reference to this stat. 252 */ 253 Derived & 254 name(const std::string &name) 255 { 256 Info *info = this->info(); 257 info->setName(name); 258 info->flags.set(display); 259 return this->self(); 260 } 261 const std::string &name() const { return this->info()->name; } 262 263 /** 264 * Set the character(s) used between the name and vector number 265 * on vectors, dist, etc. 266 * @param _sep The new separator string 267 * @return A reference to this stat. 268 */ 269 Derived & 270 setSeparator(const std::string &_sep) 271 { 272 this->info()->setSeparator(_sep); 273 return this->self(); 274 } 275 const std::string &setSeparator() const 276 { 277 return this->info()->separatorString; 278 } 279 280 /** 281 * Set the description and marks this stat to print at the end of 282 * simulation. 283 * @param desc The new description. 284 * @return A reference to this stat. 285 */ 286 Derived & 287 desc(const std::string &_desc) 288 { 289 this->info()->desc = _desc; 290 return this->self(); 291 } 292 293 /** 294 * Set the precision and marks this stat to print at the end of simulation. 295 * @param _precision The new precision 296 * @return A reference to this stat. 297 */ 298 Derived & 299 precision(int _precision) 300 { 301 this->info()->precision = _precision; 302 return this->self(); 303 } 304 305 /** 306 * Set the flags and marks this stat to print at the end of simulation. 307 * @param f The new flags. 308 * @return A reference to this stat. 309 */ 310 Derived & 311 flags(Flags _flags) 312 { 313 this->info()->flags.set(_flags); 314 return this->self(); 315 } 316 317 /** 318 * Set the prerequisite stat and marks this stat to print at the end of 319 * simulation. 320 * @param prereq The prerequisite stat. 321 * @return A reference to this stat. 322 */ 323 template <class Stat> 324 Derived & 325 prereq(const Stat &prereq) 326 { 327 this->info()->prereq = prereq.info(); 328 return this->self(); 329 } 330}; 331 332template <class Derived, template <class> class InfoProxyType> 333class DataWrapVec : public DataWrap<Derived, InfoProxyType> 334{ 335 public: 336 typedef InfoProxyType<Derived> Info; 337 338 DataWrapVec() 339 {} 340 341 DataWrapVec(const DataWrapVec &ref) 342 {} 343 344 void operator=(const DataWrapVec &) 345 {} 346 347 // The following functions are specific to vectors. If you use them 348 // in a non vector context, you will get a nice compiler error! 349 350 /** 351 * Set the subfield name for the given index, and marks this stat to print 352 * at the end of simulation. 353 * @param index The subfield index. 354 * @param name The new name of the subfield. 355 * @return A reference to this stat. 356 */ 357 Derived & 358 subname(off_type index, const std::string &name) 359 { 360 Derived &self = this->self(); 361 Info *info = self.info(); 362 363 std::vector<std::string> &subn = info->subnames; 364 if (subn.size() <= index) 365 subn.resize(index + 1); 366 subn[index] = name; 367 return self; 368 } 369 370 // The following functions are specific to 2d vectors. If you use 371 // them in a non vector context, you will get a nice compiler 372 // error because info doesn't have the right variables. 373 374 /** 375 * Set the subfield description for the given index and marks this stat to 376 * print at the end of simulation. 377 * @param index The subfield index. 378 * @param desc The new description of the subfield 379 * @return A reference to this stat. 380 */ 381 Derived & 382 subdesc(off_type index, const std::string &desc) 383 { 384 Info *info = this->info(); 385 386 std::vector<std::string> &subd = info->subdescs; 387 if (subd.size() <= index) 388 subd.resize(index + 1); 389 subd[index] = desc; 390 391 return this->self(); 392 } 393 394 void 395 prepare() 396 { 397 Derived &self = this->self(); 398 Info *info = this->info(); 399 400 size_t size = self.size(); 401 for (off_type i = 0; i < size; ++i) 402 self.data(i)->prepare(info); 403 } 404 405 void 406 reset() 407 { 408 Derived &self = this->self(); 409 Info *info = this->info(); 410 411 size_t size = self.size(); 412 for (off_type i = 0; i < size; ++i) 413 self.data(i)->reset(info); 414 } 415}; 416 417template <class Derived, template <class> class InfoProxyType> 418class DataWrapVec2d : public DataWrapVec<Derived, InfoProxyType> 419{ 420 public: 421 typedef InfoProxyType<Derived> Info; 422 423 /** 424 * @warning This makes the assumption that if you're gonna subnames a 2d 425 * vector, you're subnaming across all y 426 */ 427 Derived & 428 ysubnames(const char **names) 429 { 430 Derived &self = this->self(); 431 Info *info = this->info(); 432 433 info->y_subnames.resize(self.y); 434 for (off_type i = 0; i < self.y; ++i) 435 info->y_subnames[i] = names[i]; 436 return self; 437 } 438 439 Derived & 440 ysubname(off_type index, const std::string &subname) 441 { 442 Derived &self = this->self(); 443 Info *info = this->info(); 444 445 assert(index < self.y); 446 info->y_subnames.resize(self.y); 447 info->y_subnames[index] = subname.c_str(); 448 return self; 449 } 450 451 std::string 452 ysubname(off_type i) const 453 { 454 return this->info()->y_subnames[i]; 455 } 456 457}; 458 459////////////////////////////////////////////////////////////////////// 460// 461// Simple Statistics 462// 463////////////////////////////////////////////////////////////////////// 464 465/** 466 * Templatized storage and interface for a simple scalar stat. 467 */ 468class StatStor 469{ 470 private: 471 /** The statistic value. */ 472 Counter data; 473 474 public: 475 struct Params : public StorageParams {}; 476 477 public: 478 /** 479 * Builds this storage element and calls the base constructor of the 480 * datatype. 481 */ 482 StatStor(Info *info) 483 : data(Counter()) 484 { } 485 486 /** 487 * The the stat to the given value. 488 * @param val The new value. 489 */ 490 void set(Counter val) { data = val; } 491 /** 492 * Increment the stat by the given value. 493 * @param val The new value. 494 */ 495 void inc(Counter val) { data += val; } 496 /** 497 * Decrement the stat by the given value. 498 * @param val The new value. 499 */ 500 void dec(Counter val) { data -= val; } 501 /** 502 * Return the value of this stat as its base type. 503 * @return The value of this stat. 504 */ 505 Counter value() const { return data; } 506 /** 507 * Return the value of this stat as a result type. 508 * @return The value of this stat. 509 */ 510 Result result() const { return (Result)data; } 511 /** 512 * Prepare stat data for dumping or serialization 513 */ 514 void prepare(Info *info) { } 515 /** 516 * Reset stat value to default 517 */ 518 void reset(Info *info) { data = Counter(); } 519 520 /** 521 * @return true if zero value 522 */ 523 bool zero() const { return data == Counter(); } 524}; 525 526/** 527 * Templatized storage and interface to a per-tick average stat. This keeps 528 * a current count and updates a total (count * ticks) when this count 529 * changes. This allows the quick calculation of a per tick count of the item 530 * being watched. This is good for keeping track of residencies in structures 531 * among other things. 532 */ 533class AvgStor 534{ 535 private: 536 /** The current count. */ 537 Counter current; 538 /** The tick of the last reset */ 539 Tick lastReset; 540 /** The total count for all tick. */ 541 mutable Result total; 542 /** The tick that current last changed. */ 543 mutable Tick last; 544 545 public: 546 struct Params : public StorageParams {}; 547 548 public: 549 /** 550 * Build and initializes this stat storage. 551 */ 552 AvgStor(Info *info) 553 : current(0), lastReset(0), total(0), last(0) 554 { } 555 556 /** 557 * Set the current count to the one provided, update the total and last 558 * set values. 559 * @param val The new count. 560 */ 561 void 562 set(Counter val) 563 { 564 total += current * (curTick() - last); 565 last = curTick(); 566 current = val; 567 } 568 569 /** 570 * Increment the current count by the provided value, calls set. 571 * @param val The amount to increment. 572 */ 573 void inc(Counter val) { set(current + val); } 574 575 /** 576 * Deccrement the current count by the provided value, calls set. 577 * @param val The amount to decrement. 578 */ 579 void dec(Counter val) { set(current - val); } 580 581 /** 582 * Return the current count. 583 * @return The current count. 584 */ 585 Counter value() const { return current; } 586 587 /** 588 * Return the current average. 589 * @return The current average. 590 */ 591 Result 592 result() const 593 { 594 assert(last == curTick()); 595 return (Result)(total + current) / (Result)(curTick() - lastReset + 1); 596 } 597 598 /** 599 * @return true if zero value 600 */ 601 bool zero() const { return total == 0.0; } 602 603 /** 604 * Prepare stat data for dumping or serialization 605 */ 606 void 607 prepare(Info *info) 608 { 609 total += current * (curTick() - last); 610 last = curTick(); 611 } 612 613 /** 614 * Reset stat value to default 615 */ 616 void 617 reset(Info *info) 618 { 619 total = 0.0; 620 last = curTick(); 621 lastReset = curTick(); 622 } 623 624}; 625 626/** 627 * Implementation of a scalar stat. The type of stat is determined by the 628 * Storage template. 629 */ 630template <class Derived, class Stor> 631class ScalarBase : public DataWrap<Derived, ScalarInfoProxy> 632{ 633 public: 634 typedef Stor Storage; 635 typedef typename Stor::Params Params; 636 637 protected: 638 /** The storage of this stat. */ 639 char storage[sizeof(Storage)] __attribute__ ((aligned (8))); 640 641 protected: 642 /** 643 * Retrieve the storage. 644 * @param index The vector index to access. 645 * @return The storage object at the given index. 646 */ 647 Storage * 648 data() 649 { 650 return reinterpret_cast<Storage *>(storage); 651 } 652 653 /** 654 * Retrieve a const pointer to the storage. 655 * for the given index. 656 * @param index The vector index to access. 657 * @return A const pointer to the storage object at the given index. 658 */ 659 const Storage * 660 data() const 661 { 662 return reinterpret_cast<const Storage *>(storage); 663 } 664 665 void 666 doInit() 667 { 668 new (storage) Storage(this->info()); 669 this->setInit(); 670 } 671 672 public: 673 /** 674 * Return the current value of this stat as its base type. 675 * @return The current value. 676 */ 677 Counter value() const { return data()->value(); } 678 679 public: 680 ScalarBase() 681 { 682 this->doInit(); 683 } 684 685 public: 686 // Common operators for stats 687 /** 688 * Increment the stat by 1. This calls the associated storage object inc 689 * function. 690 */ 691 void operator++() { data()->inc(1); } 692 /** 693 * Decrement the stat by 1. This calls the associated storage object dec 694 * function. 695 */ 696 void operator--() { data()->dec(1); } 697 698 /** Increment the stat by 1. */ 699 void operator++(int) { ++*this; } 700 /** Decrement the stat by 1. */ 701 void operator--(int) { --*this; } 702 703 /** 704 * Set the data value to the given value. This calls the associated storage 705 * object set function. 706 * @param v The new value. 707 */ 708 template <typename U> 709 void operator=(const U &v) { data()->set(v); } 710 711 /** 712 * Increment the stat by the given value. This calls the associated 713 * storage object inc function. 714 * @param v The value to add. 715 */ 716 template <typename U> 717 void operator+=(const U &v) { data()->inc(v); } 718 719 /** 720 * Decrement the stat by the given value. This calls the associated 721 * storage object dec function. 722 * @param v The value to substract. 723 */ 724 template <typename U> 725 void operator-=(const U &v) { data()->dec(v); } 726 727 /** 728 * Return the number of elements, always 1 for a scalar. 729 * @return 1. 730 */ 731 size_type size() const { return 1; } 732 733 Counter value() { return data()->value(); } 734 735 Result result() { return data()->result(); } 736 737 Result total() { return result(); } 738 739 bool zero() { return result() == 0.0; } 740 741 void reset() { data()->reset(this->info()); } 742 void prepare() { data()->prepare(this->info()); } 743}; 744 745class ProxyInfo : public ScalarInfo 746{ 747 public: 748 std::string str() const { return std::to_string(value()); } 749 size_type size() const { return 1; } 750 bool check() const { return true; } 751 void prepare() { } 752 void reset() { } 753 bool zero() const { return value() == 0; } 754 755 void visit(Output &visitor) { visitor.visit(*this); } 756}; 757 758template <class T> 759class ValueProxy : public ProxyInfo 760{ 761 private: 762 T *scalar; 763 764 public: 765 ValueProxy(T &val) : scalar(&val) {} 766 Counter value() const { return *scalar; } 767 Result result() const { return *scalar; } 768 Result total() const { return *scalar; } 769}; 770 771template <class T> 772class FunctorProxy : public ProxyInfo 773{ 774 private: 775 T *functor; 776 777 public: 778 FunctorProxy(T &func) : functor(&func) {} 779 Counter value() const { return (*functor)(); } 780 Result result() const { return (*functor)(); } 781 Result total() const { return (*functor)(); } 782}; 783 784/** 785 * A proxy similar to the FunctorProxy, but allows calling a method of a bound 786 * object, instead of a global free-standing function. 787 */ 788template <class T, class V> 789class MethodProxy : public ProxyInfo 790{ 791 private: 792 T *object; 793 typedef V (T::*MethodPointer) () const; 794 MethodPointer method; 795 796 public: 797 MethodProxy(T *obj, MethodPointer meth) : object(obj), method(meth) {} 798 Counter value() const { return (object->*method)(); } 799 Result result() const { return (object->*method)(); } 800 Result total() const { return (object->*method)(); } 801}; 802 803template <class Derived> 804class ValueBase : public DataWrap<Derived, ScalarInfoProxy> 805{ 806 private: 807 ProxyInfo *proxy; 808 809 public: 810 ValueBase() : proxy(NULL) { } 811 ~ValueBase() { if (proxy) delete proxy; } 812 813 template <class T> 814 Derived & 815 scalar(T &value) 816 { 817 proxy = new ValueProxy<T>(value); 818 this->setInit(); 819 return this->self(); 820 } 821 822 template <class T> 823 Derived & 824 functor(T &func) 825 { 826 proxy = new FunctorProxy<T>(func); 827 this->setInit(); 828 return this->self(); 829 } 830 831 /** 832 * Extended functor that calls the specified method of the provided object. 833 * 834 * @param obj Pointer to the object whose method should be called. 835 * @param method Pointer of the function / method of the object. 836 * @return Updated stats item. 837 */ 838 template <class T, class V> 839 Derived & 840 method(T *obj, V (T::*method)() const) 841 { 842 proxy = new MethodProxy<T,V>(obj, method); 843 this->setInit(); 844 return this->self(); 845 } 846 847 Counter value() { return proxy->value(); } 848 Result result() const { return proxy->result(); } 849 Result total() const { return proxy->total(); }; 850 size_type size() const { return proxy->size(); } 851 852 std::string str() const { return proxy->str(); } 853 bool zero() const { return proxy->zero(); } 854 bool check() const { return proxy != NULL; } 855 void prepare() { } 856 void reset() { } 857}; 858 859////////////////////////////////////////////////////////////////////// 860// 861// Vector Statistics 862// 863////////////////////////////////////////////////////////////////////// 864 865/** 866 * A proxy class to access the stat at a given index in a VectorBase stat. 867 * Behaves like a ScalarBase. 868 */ 869template <class Stat> 870class ScalarProxy 871{ 872 private: 873 /** Pointer to the parent Vector. */ 874 Stat &stat; 875 876 /** The index to access in the parent VectorBase. */ 877 off_type index; 878 879 public: 880 /** 881 * Return the current value of this stat as its base type. 882 * @return The current value. 883 */ 884 Counter value() const { return stat.data(index)->value(); } 885 886 /** 887 * Return the current value of this statas a result type. 888 * @return The current value. 889 */ 890 Result result() const { return stat.data(index)->result(); } 891 892 public: 893 /** 894 * Create and initialize this proxy, do not register it with the database. 895 * @param i The index to access. 896 */ 897 ScalarProxy(Stat &s, off_type i) 898 : stat(s), index(i) 899 { 900 } 901 902 /** 903 * Create a copy of the provided ScalarProxy. 904 * @param sp The proxy to copy. 905 */ 906 ScalarProxy(const ScalarProxy &sp) 907 : stat(sp.stat), index(sp.index) 908 {} 909 910 /** 911 * Set this proxy equal to the provided one. 912 * @param sp The proxy to copy. 913 * @return A reference to this proxy. 914 */ 915 const ScalarProxy & 916 operator=(const ScalarProxy &sp) 917 { 918 stat = sp.stat; 919 index = sp.index; 920 return *this; 921 } 922 923 public: 924 // Common operators for stats 925 /** 926 * Increment the stat by 1. This calls the associated storage object inc 927 * function. 928 */ 929 void operator++() { stat.data(index)->inc(1); } 930 /** 931 * Decrement the stat by 1. This calls the associated storage object dec 932 * function. 933 */ 934 void operator--() { stat.data(index)->dec(1); } 935 936 /** Increment the stat by 1. */ 937 void operator++(int) { ++*this; } 938 /** Decrement the stat by 1. */ 939 void operator--(int) { --*this; } 940 941 /** 942 * Set the data value to the given value. This calls the associated storage 943 * object set function. 944 * @param v The new value. 945 */ 946 template <typename U> 947 void 948 operator=(const U &v) 949 { 950 stat.data(index)->set(v); 951 } 952 953 /** 954 * Increment the stat by the given value. This calls the associated 955 * storage object inc function. 956 * @param v The value to add. 957 */ 958 template <typename U> 959 void 960 operator+=(const U &v) 961 { 962 stat.data(index)->inc(v); 963 } 964 965 /** 966 * Decrement the stat by the given value. This calls the associated 967 * storage object dec function. 968 * @param v The value to substract. 969 */ 970 template <typename U> 971 void 972 operator-=(const U &v) 973 { 974 stat.data(index)->dec(v); 975 } 976 977 /** 978 * Return the number of elements, always 1 for a scalar. 979 * @return 1. 980 */ 981 size_type size() const { return 1; } 982 983 public: 984 std::string 985 str() const 986 { 987 return csprintf("%s[%d]", stat.info()->name, index); 988 } 989}; 990 991/** 992 * Implementation of a vector of stats. The type of stat is determined by the 993 * Storage class. @sa ScalarBase 994 */ 995template <class Derived, class Stor> 996class VectorBase : public DataWrapVec<Derived, VectorInfoProxy> 997{ 998 public: 999 typedef Stor Storage; 1000 typedef typename Stor::Params Params; 1001 1002 /** Proxy type */ 1003 typedef ScalarProxy<Derived> Proxy; 1004 friend class ScalarProxy<Derived>; 1005 friend class DataWrapVec<Derived, VectorInfoProxy>; 1006 1007 protected: 1008 /** The storage of this stat. */ 1009 Storage *storage; 1010 size_type _size; 1011 1012 protected: 1013 /** 1014 * Retrieve the storage. 1015 * @param index The vector index to access. 1016 * @return The storage object at the given index. 1017 */ 1018 Storage *data(off_type index) { return &storage[index]; } 1019 1020 /** 1021 * Retrieve a const pointer to the storage. 1022 * @param index The vector index to access. 1023 * @return A const pointer to the storage object at the given index. 1024 */ 1025 const Storage *data(off_type index) const { return &storage[index]; } 1026 1027 void 1028 doInit(size_type s) 1029 { 1030 assert(s > 0 && "size must be positive!"); 1031 assert(!storage && "already initialized"); 1032 _size = s; 1033 1034 char *ptr = new char[_size * sizeof(Storage)]; 1035 storage = reinterpret_cast<Storage *>(ptr); 1036 1037 for (off_type i = 0; i < _size; ++i) 1038 new (&storage[i]) Storage(this->info()); 1039 1040 this->setInit(); 1041 } 1042 1043 public: 1044 void 1045 value(VCounter &vec) const 1046 { 1047 vec.resize(size()); 1048 for (off_type i = 0; i < size(); ++i) 1049 vec[i] = data(i)->value(); 1050 } 1051 1052 /** 1053 * Copy the values to a local vector and return a reference to it. 1054 * @return A reference to a vector of the stat values. 1055 */ 1056 void 1057 result(VResult &vec) const 1058 { 1059 vec.resize(size()); 1060 for (off_type i = 0; i < size(); ++i) 1061 vec[i] = data(i)->result(); 1062 } 1063 1064 /** 1065 * Return a total of all entries in this vector. 1066 * @return The total of all vector entries. 1067 */ 1068 Result 1069 total() const 1070 { 1071 Result total = 0.0; 1072 for (off_type i = 0; i < size(); ++i) 1073 total += data(i)->result(); 1074 return total; 1075 } 1076 1077 /** 1078 * @return the number of elements in this vector. 1079 */ 1080 size_type size() const { return _size; } 1081 1082 bool 1083 zero() const 1084 { 1085 for (off_type i = 0; i < size(); ++i) 1086 if (data(i)->zero()) 1087 return false; 1088 return true; 1089 } 1090 1091 bool 1092 check() const 1093 { 1094 return storage != NULL; 1095 } 1096 1097 public: 1098 VectorBase() 1099 : storage(nullptr), _size(0) 1100 {} 1101 1102 ~VectorBase() 1103 { 1104 if (!storage) 1105 return; 1106 1107 for (off_type i = 0; i < _size; ++i) 1108 data(i)->~Storage(); 1109 delete [] reinterpret_cast<char *>(storage); 1110 } 1111 1112 /** 1113 * Set this vector to have the given size. 1114 * @param size The new size. 1115 * @return A reference to this stat. 1116 */ 1117 Derived & 1118 init(size_type size) 1119 { 1120 Derived &self = this->self(); 1121 self.doInit(size); 1122 return self; 1123 } 1124 1125 /** 1126 * Return a reference (ScalarProxy) to the stat at the given index. 1127 * @param index The vector index to access. 1128 * @return A reference of the stat. 1129 */ 1130 Proxy 1131 operator[](off_type index) 1132 { 1133 assert (index >= 0 && index < size()); 1134 return Proxy(this->self(), index); 1135 } 1136}; 1137 1138template <class Stat> 1139class VectorProxy 1140{ 1141 private: 1142 Stat &stat; 1143 off_type offset; 1144 size_type len; 1145 1146 private: 1147 mutable VResult vec; 1148 1149 typename Stat::Storage * 1150 data(off_type index) 1151 { 1152 assert(index < len); 1153 return stat.data(offset + index); 1154 } 1155 1156 const typename Stat::Storage * 1157 data(off_type index) const 1158 { 1159 assert(index < len); 1160 return stat.data(offset + index); 1161 } 1162 1163 public: 1164 const VResult & 1165 result() const 1166 { 1167 vec.resize(size()); 1168 1169 for (off_type i = 0; i < size(); ++i) 1170 vec[i] = data(i)->result(); 1171 1172 return vec; 1173 } 1174 1175 Result 1176 total() const 1177 { 1178 Result total = 0.0; 1179 for (off_type i = 0; i < size(); ++i) 1180 total += data(i)->result(); 1181 return total; 1182 } 1183 1184 public: 1185 VectorProxy(Stat &s, off_type o, size_type l) 1186 : stat(s), offset(o), len(l) 1187 { 1188 } 1189 1190 VectorProxy(const VectorProxy &sp) 1191 : stat(sp.stat), offset(sp.offset), len(sp.len) 1192 { 1193 } 1194 1195 const VectorProxy & 1196 operator=(const VectorProxy &sp) 1197 { 1198 stat = sp.stat; 1199 offset = sp.offset; 1200 len = sp.len; 1201 return *this; 1202 } 1203 1204 ScalarProxy<Stat> 1205 operator[](off_type index) 1206 { 1207 assert (index >= 0 && index < size()); 1208 return ScalarProxy<Stat>(stat, offset + index); 1209 } 1210 1211 size_type size() const { return len; } 1212}; 1213 1214template <class Derived, class Stor> 1215class Vector2dBase : public DataWrapVec2d<Derived, Vector2dInfoProxy> 1216{ 1217 public: 1218 typedef Vector2dInfoProxy<Derived> Info; 1219 typedef Stor Storage; 1220 typedef typename Stor::Params Params; 1221 typedef VectorProxy<Derived> Proxy; 1222 friend class ScalarProxy<Derived>; 1223 friend class VectorProxy<Derived>; 1224 friend class DataWrapVec<Derived, Vector2dInfoProxy>; 1225 friend class DataWrapVec2d<Derived, Vector2dInfoProxy>; 1226 1227 protected: 1228 size_type x; 1229 size_type y; 1230 size_type _size; 1231 Storage *storage; 1232 1233 protected: 1234 Storage *data(off_type index) { return &storage[index]; } 1235 const Storage *data(off_type index) const { return &storage[index]; } 1236 1237 public: 1238 Vector2dBase() 1239 : x(0), y(0), _size(0), storage(nullptr) 1240 {} 1241 1242 ~Vector2dBase() 1243 { 1244 if (!storage) 1245 return; 1246 1247 for (off_type i = 0; i < _size; ++i) 1248 data(i)->~Storage(); 1249 delete [] reinterpret_cast<char *>(storage); 1250 } 1251 1252 Derived & 1253 init(size_type _x, size_type _y) 1254 { 1255 assert(_x > 0 && _y > 0 && "sizes must be positive!"); 1256 assert(!storage && "already initialized"); 1257 1258 Derived &self = this->self(); 1259 Info *info = this->info(); 1260 1261 x = _x; 1262 y = _y; 1263 info->x = _x; 1264 info->y = _y; 1265 _size = x * y; 1266 1267 char *ptr = new char[_size * sizeof(Storage)]; 1268 storage = reinterpret_cast<Storage *>(ptr); 1269 1270 for (off_type i = 0; i < _size; ++i) 1271 new (&storage[i]) Storage(info); 1272 1273 this->setInit(); 1274 1275 return self; 1276 } 1277 1278 Proxy 1279 operator[](off_type index) 1280 { 1281 off_type offset = index * y; 1282 assert (index >= 0 && offset + y <= size()); 1283 return Proxy(this->self(), offset, y); 1284 } 1285 1286 1287 size_type 1288 size() const 1289 { 1290 return _size; 1291 } 1292 1293 bool 1294 zero() const 1295 { 1296 return data(0)->zero(); 1297 } 1298 1299 /** 1300 * Return a total of all entries in this vector. 1301 * @return The total of all vector entries. 1302 */ 1303 Result 1304 total() const 1305 { 1306 Result total = 0.0; 1307 for (off_type i = 0; i < size(); ++i) 1308 total += data(i)->result(); 1309 return total; 1310 } 1311 1312 void 1313 prepare() 1314 { 1315 Info *info = this->info(); 1316 size_type size = this->size(); 1317 1318 for (off_type i = 0; i < size; ++i) 1319 data(i)->prepare(info); 1320 1321 info->cvec.resize(size); 1322 for (off_type i = 0; i < size; ++i) 1323 info->cvec[i] = data(i)->value(); 1324 } 1325 1326 /** 1327 * Reset stat value to default 1328 */ 1329 void 1330 reset() 1331 { 1332 Info *info = this->info(); 1333 size_type size = this->size(); 1334 for (off_type i = 0; i < size; ++i) 1335 data(i)->reset(info); 1336 } 1337 1338 bool 1339 check() const 1340 { 1341 return storage != NULL; 1342 } 1343}; 1344 1345////////////////////////////////////////////////////////////////////// 1346// 1347// Non formula statistics 1348// 1349////////////////////////////////////////////////////////////////////// 1350/** The parameters for a distribution stat. */ 1351struct DistParams : public StorageParams 1352{ 1353 const DistType type; 1354 DistParams(DistType t) : type(t) {} 1355}; 1356 1357/** 1358 * Templatized storage and interface for a distribution stat. 1359 */ 1360class DistStor 1361{ 1362 public: 1363 /** The parameters for a distribution stat. */ 1364 struct Params : public DistParams 1365 { 1366 /** The minimum value to track. */ 1367 Counter min; 1368 /** The maximum value to track. */ 1369 Counter max; 1370 /** The number of entries in each bucket. */ 1371 Counter bucket_size; 1372 /** The number of buckets. Equal to (max-min)/bucket_size. */ 1373 size_type buckets; 1374 1375 Params() : DistParams(Dist), min(0), max(0), bucket_size(0), 1376 buckets(0) {} 1377 }; 1378 1379 private: 1380 /** The minimum value to track. */ 1381 Counter min_track; 1382 /** The maximum value to track. */ 1383 Counter max_track; 1384 /** The number of entries in each bucket. */ 1385 Counter bucket_size; 1386 1387 /** The smallest value sampled. */ 1388 Counter min_val; 1389 /** The largest value sampled. */ 1390 Counter max_val; 1391 /** The number of values sampled less than min. */ 1392 Counter underflow; 1393 /** The number of values sampled more than max. */ 1394 Counter overflow; 1395 /** The current sum. */ 1396 Counter sum; 1397 /** The sum of squares. */ 1398 Counter squares; 1399 /** The number of samples. */ 1400 Counter samples; 1401 /** Counter for each bucket. */ 1402 VCounter cvec; 1403 1404 public: 1405 DistStor(Info *info) 1406 : cvec(safe_cast<const Params *>(info->storageParams)->buckets) 1407 { 1408 reset(info); 1409 } 1410 1411 /** 1412 * Add a value to the distribution for the given number of times. 1413 * @param val The value to add. 1414 * @param number The number of times to add the value. 1415 */ 1416 void 1417 sample(Counter val, int number) 1418 { 1419 if (val < min_track) 1420 underflow += number; 1421 else if (val > max_track) 1422 overflow += number; 1423 else { 1424 size_type index = 1425 (size_type)std::floor((val - min_track) / bucket_size); 1426 assert(index < size()); 1427 cvec[index] += number; 1428 } 1429 1430 if (val < min_val) 1431 min_val = val; 1432 1433 if (val > max_val) 1434 max_val = val; 1435 1436 sum += val * number; 1437 squares += val * val * number; 1438 samples += number; 1439 } 1440 1441 /** 1442 * Return the number of buckets in this distribution. 1443 * @return the number of buckets. 1444 */ 1445 size_type size() const { return cvec.size(); } 1446 1447 /** 1448 * Returns true if any calls to sample have been made. 1449 * @return True if any values have been sampled. 1450 */ 1451 bool 1452 zero() const 1453 { 1454 return samples == Counter(); 1455 } 1456 1457 void 1458 prepare(Info *info, DistData &data) 1459 { 1460 const Params *params = safe_cast<const Params *>(info->storageParams); 1461 1462 assert(params->type == Dist); 1463 data.type = params->type; 1464 data.min = params->min; 1465 data.max = params->max; 1466 data.bucket_size = params->bucket_size; 1467 1468 data.min_val = (min_val == CounterLimits::max()) ? 0 : min_val; 1469 data.max_val = (max_val == CounterLimits::min()) ? 0 : max_val; 1470 data.underflow = underflow; 1471 data.overflow = overflow; 1472 1473 data.cvec.resize(params->buckets); 1474 for (off_type i = 0; i < params->buckets; ++i) 1475 data.cvec[i] = cvec[i]; 1476 1477 data.sum = sum; 1478 data.squares = squares; 1479 data.samples = samples; 1480 } 1481 1482 /** 1483 * Reset stat value to default 1484 */ 1485 void 1486 reset(Info *info) 1487 { 1488 const Params *params = safe_cast<const Params *>(info->storageParams); 1489 min_track = params->min; 1490 max_track = params->max; 1491 bucket_size = params->bucket_size; 1492 1493 min_val = CounterLimits::max(); 1494 max_val = CounterLimits::min(); 1495 underflow = Counter(); 1496 overflow = Counter(); 1497 1498 size_type size = cvec.size(); 1499 for (off_type i = 0; i < size; ++i) 1500 cvec[i] = Counter(); 1501 1502 sum = Counter(); 1503 squares = Counter(); 1504 samples = Counter(); 1505 } 1506}; 1507 1508/** 1509 * Templatized storage and interface for a histogram stat. 1510 */ 1511class HistStor 1512{ 1513 public: 1514 /** The parameters for a distribution stat. */ 1515 struct Params : public DistParams 1516 { 1517 /** The number of buckets.. */ 1518 size_type buckets; 1519 1520 Params() : DistParams(Hist), buckets(0) {} 1521 }; 1522 1523 private: 1524 /** The minimum value to track. */ 1525 Counter min_bucket; 1526 /** The maximum value to track. */ 1527 Counter max_bucket; 1528 /** The number of entries in each bucket. */ 1529 Counter bucket_size; 1530 1531 /** The current sum. */ 1532 Counter sum; 1533 /** The sum of logarithm of each sample, used to compute geometric mean. */ 1534 Counter logs; 1535 /** The sum of squares. */ 1536 Counter squares; 1537 /** The number of samples. */ 1538 Counter samples; 1539 /** Counter for each bucket. */ 1540 VCounter cvec; 1541 1542 public: 1543 HistStor(Info *info) 1544 : cvec(safe_cast<const Params *>(info->storageParams)->buckets) 1545 { 1546 reset(info); 1547 } 1548 1549 void grow_up(); 1550 void grow_out(); 1551 void grow_convert(); 1552 void add(HistStor *); 1553 1554 /** 1555 * Add a value to the distribution for the given number of times. 1556 * @param val The value to add. 1557 * @param number The number of times to add the value. 1558 */ 1559 void 1560 sample(Counter val, int number) 1561 { 1562 assert(min_bucket < max_bucket); 1563 if (val < min_bucket) { 1564 if (min_bucket == 0) 1565 grow_convert(); 1566 1567 while (val < min_bucket) 1568 grow_out(); 1569 } else if (val >= max_bucket + bucket_size) { 1570 if (min_bucket == 0) { 1571 while (val >= max_bucket + bucket_size) 1572 grow_up(); 1573 } else { 1574 while (val >= max_bucket + bucket_size) 1575 grow_out(); 1576 } 1577 } 1578 1579 size_type index = 1580 (int64_t)std::floor((val - min_bucket) / bucket_size); 1581 1582 assert(index < size()); 1583 cvec[index] += number; 1584 1585 sum += val * number; 1586 squares += val * val * number; 1587 logs += log(val) * number; 1588 samples += number; 1589 } 1590 1591 /** 1592 * Return the number of buckets in this distribution. 1593 * @return the number of buckets. 1594 */ 1595 size_type size() const { return cvec.size(); } 1596 1597 /** 1598 * Returns true if any calls to sample have been made. 1599 * @return True if any values have been sampled. 1600 */ 1601 bool 1602 zero() const 1603 { 1604 return samples == Counter(); 1605 } 1606 1607 void 1608 prepare(Info *info, DistData &data) 1609 { 1610 const Params *params = safe_cast<const Params *>(info->storageParams); 1611 1612 assert(params->type == Hist); 1613 data.type = params->type; 1614 data.min = min_bucket; 1615 data.max = max_bucket + bucket_size - 1; 1616 data.bucket_size = bucket_size; 1617 1618 data.min_val = min_bucket; 1619 data.max_val = max_bucket; 1620 1621 int buckets = params->buckets; 1622 data.cvec.resize(buckets); 1623 for (off_type i = 0; i < buckets; ++i) 1624 data.cvec[i] = cvec[i]; 1625 1626 data.sum = sum; 1627 data.logs = logs; 1628 data.squares = squares; 1629 data.samples = samples; 1630 } 1631 1632 /** 1633 * Reset stat value to default 1634 */ 1635 void 1636 reset(Info *info) 1637 { 1638 const Params *params = safe_cast<const Params *>(info->storageParams); 1639 min_bucket = 0; 1640 max_bucket = params->buckets - 1; 1641 bucket_size = 1; 1642 1643 size_type size = cvec.size(); 1644 for (off_type i = 0; i < size; ++i) 1645 cvec[i] = Counter(); 1646 1647 sum = Counter(); 1648 squares = Counter(); 1649 samples = Counter(); 1650 logs = Counter(); 1651 } 1652}; 1653 1654/** 1655 * Templatized storage and interface for a distribution that calculates mean 1656 * and variance. 1657 */ 1658class SampleStor 1659{ 1660 public: 1661 struct Params : public DistParams 1662 { 1663 Params() : DistParams(Deviation) {} 1664 }; 1665 1666 private: 1667 /** The current sum. */ 1668 Counter sum; 1669 /** The sum of squares. */ 1670 Counter squares; 1671 /** The number of samples. */ 1672 Counter samples; 1673 1674 public: 1675 /** 1676 * Create and initialize this storage. 1677 */ 1678 SampleStor(Info *info) 1679 : sum(Counter()), squares(Counter()), samples(Counter()) 1680 { } 1681 1682 /** 1683 * Add a value the given number of times to this running average. 1684 * Update the running sum and sum of squares, increment the number of 1685 * values seen by the given number. 1686 * @param val The value to add. 1687 * @param number The number of times to add the value. 1688 */ 1689 void 1690 sample(Counter val, int number) 1691 { 1692 Counter value = val * number; 1693 sum += value; 1694 squares += value * value; 1695 samples += number; 1696 } 1697 1698 /** 1699 * Return the number of entries in this stat, 1 1700 * @return 1. 1701 */ 1702 size_type size() const { return 1; } 1703 1704 /** 1705 * Return true if no samples have been added. 1706 * @return True if no samples have been added. 1707 */ 1708 bool zero() const { return samples == Counter(); } 1709 1710 void 1711 prepare(Info *info, DistData &data) 1712 { 1713 const Params *params = safe_cast<const Params *>(info->storageParams); 1714 1715 assert(params->type == Deviation); 1716 data.type = params->type; 1717 data.sum = sum; 1718 data.squares = squares; 1719 data.samples = samples; 1720 } 1721 1722 /** 1723 * Reset stat value to default 1724 */ 1725 void 1726 reset(Info *info) 1727 { 1728 sum = Counter(); 1729 squares = Counter(); 1730 samples = Counter(); 1731 } 1732}; 1733 1734/** 1735 * Templatized storage for distribution that calculates per tick mean and 1736 * variance. 1737 */ 1738class AvgSampleStor 1739{ 1740 public: 1741 struct Params : public DistParams 1742 { 1743 Params() : DistParams(Deviation) {} 1744 }; 1745 1746 private: 1747 /** Current total. */ 1748 Counter sum; 1749 /** Current sum of squares. */ 1750 Counter squares; 1751 1752 public: 1753 /** 1754 * Create and initialize this storage. 1755 */ 1756 AvgSampleStor(Info *info) 1757 : sum(Counter()), squares(Counter()) 1758 {} 1759 1760 /** 1761 * Add a value to the distribution for the given number of times. 1762 * Update the running sum and sum of squares. 1763 * @param val The value to add. 1764 * @param number The number of times to add the value. 1765 */ 1766 void 1767 sample(Counter val, int number) 1768 { 1769 Counter value = val * number; 1770 sum += value; 1771 squares += value * value; 1772 } 1773 1774 /** 1775 * Return the number of entries, in this case 1. 1776 * @return 1. 1777 */ 1778 size_type size() const { return 1; } 1779 1780 /** 1781 * Return true if no samples have been added. 1782 * @return True if the sum is zero. 1783 */ 1784 bool zero() const { return sum == Counter(); } 1785 1786 void 1787 prepare(Info *info, DistData &data) 1788 { 1789 const Params *params = safe_cast<const Params *>(info->storageParams); 1790 1791 assert(params->type == Deviation); 1792 data.type = params->type; 1793 data.sum = sum; 1794 data.squares = squares; 1795 data.samples = curTick(); 1796 } 1797 1798 /** 1799 * Reset stat value to default 1800 */ 1801 void 1802 reset(Info *info) 1803 { 1804 sum = Counter(); 1805 squares = Counter(); 1806 } 1807}; 1808 1809/** 1810 * Implementation of a distribution stat. The type of distribution is 1811 * determined by the Storage template. @sa ScalarBase 1812 */ 1813template <class Derived, class Stor> 1814class DistBase : public DataWrap<Derived, DistInfoProxy> 1815{ 1816 public: 1817 typedef DistInfoProxy<Derived> Info; 1818 typedef Stor Storage; 1819 typedef typename Stor::Params Params; 1820 1821 protected: 1822 /** The storage for this stat. */ 1823 char storage[sizeof(Storage)] __attribute__ ((aligned (8))); 1824 1825 protected: 1826 /** 1827 * Retrieve the storage. 1828 * @return The storage object for this stat. 1829 */ 1830 Storage * 1831 data() 1832 { 1833 return reinterpret_cast<Storage *>(storage); 1834 } 1835 1836 /** 1837 * Retrieve a const pointer to the storage. 1838 * @return A const pointer to the storage object for this stat. 1839 */ 1840 const Storage * 1841 data() const 1842 { 1843 return reinterpret_cast<const Storage *>(storage); 1844 } 1845 1846 void 1847 doInit() 1848 { 1849 new (storage) Storage(this->info()); 1850 this->setInit(); 1851 } 1852 1853 public: 1854 DistBase() { } 1855 1856 /** 1857 * Add a value to the distribtion n times. Calls sample on the storage 1858 * class. 1859 * @param v The value to add. 1860 * @param n The number of times to add it, defaults to 1. 1861 */ 1862 template <typename U> 1863 void sample(const U &v, int n = 1) { data()->sample(v, n); } 1864 1865 /** 1866 * Return the number of entries in this stat. 1867 * @return The number of entries. 1868 */ 1869 size_type size() const { return data()->size(); } 1870 /** 1871 * Return true if no samples have been added. 1872 * @return True if there haven't been any samples. 1873 */ 1874 bool zero() const { return data()->zero(); } 1875 1876 void 1877 prepare() 1878 { 1879 Info *info = this->info(); 1880 data()->prepare(info, info->data); 1881 } 1882 1883 /** 1884 * Reset stat value to default 1885 */ 1886 void 1887 reset() 1888 { 1889 data()->reset(this->info()); 1890 } 1891 1892 /** 1893 * Add the argument distribution to the this distribution. 1894 */ 1895 void add(DistBase &d) { data()->add(d.data()); } 1896 1897}; 1898 1899template <class Stat> 1900class DistProxy; 1901 1902template <class Derived, class Stor> 1903class VectorDistBase : public DataWrapVec<Derived, VectorDistInfoProxy> 1904{ 1905 public: 1906 typedef VectorDistInfoProxy<Derived> Info; 1907 typedef Stor Storage; 1908 typedef typename Stor::Params Params; 1909 typedef DistProxy<Derived> Proxy; 1910 friend class DistProxy<Derived>; 1911 friend class DataWrapVec<Derived, VectorDistInfoProxy>; 1912 1913 protected: 1914 Storage *storage; 1915 size_type _size; 1916 1917 protected: 1918 Storage * 1919 data(off_type index) 1920 { 1921 return &storage[index]; 1922 } 1923 1924 const Storage * 1925 data(off_type index) const 1926 { 1927 return &storage[index]; 1928 } 1929 1930 void 1931 doInit(size_type s) 1932 { 1933 assert(s > 0 && "size must be positive!"); 1934 assert(!storage && "already initialized"); 1935 _size = s; 1936 1937 char *ptr = new char[_size * sizeof(Storage)]; 1938 storage = reinterpret_cast<Storage *>(ptr); 1939 1940 Info *info = this->info(); 1941 for (off_type i = 0; i < _size; ++i) 1942 new (&storage[i]) Storage(info); 1943 1944 this->setInit(); 1945 } 1946 1947 public: 1948 VectorDistBase() 1949 : storage(NULL) 1950 {} 1951 1952 ~VectorDistBase() 1953 { 1954 if (!storage) 1955 return ; 1956 1957 for (off_type i = 0; i < _size; ++i) 1958 data(i)->~Storage(); 1959 delete [] reinterpret_cast<char *>(storage); 1960 } 1961 1962 Proxy operator[](off_type index) 1963 { 1964 assert(index >= 0 && index < size()); 1965 return Proxy(this->self(), index); 1966 } 1967 1968 size_type 1969 size() const 1970 { 1971 return _size; 1972 } 1973 1974 bool 1975 zero() const 1976 { 1977 for (off_type i = 0; i < size(); ++i) 1978 if (!data(i)->zero()) 1979 return false; 1980 return true; 1981 } 1982 1983 void 1984 prepare() 1985 { 1986 Info *info = this->info(); 1987 size_type size = this->size(); 1988 info->data.resize(size); 1989 for (off_type i = 0; i < size; ++i) 1990 data(i)->prepare(info, info->data[i]); 1991 } 1992 1993 bool 1994 check() const 1995 { 1996 return storage != NULL; 1997 } 1998}; 1999 2000template <class Stat> 2001class DistProxy 2002{ 2003 private: 2004 Stat &stat; 2005 off_type index; 2006 2007 protected: 2008 typename Stat::Storage *data() { return stat.data(index); } 2009 const typename Stat::Storage *data() const { return stat.data(index); } 2010 2011 public: 2012 DistProxy(Stat &s, off_type i) 2013 : stat(s), index(i) 2014 {} 2015 2016 DistProxy(const DistProxy &sp) 2017 : stat(sp.stat), index(sp.index) 2018 {} 2019 2020 const DistProxy & 2021 operator=(const DistProxy &sp) 2022 { 2023 stat = sp.stat; 2024 index = sp.index; 2025 return *this; 2026 } 2027 2028 public: 2029 template <typename U> 2030 void 2031 sample(const U &v, int n = 1) 2032 { 2033 data()->sample(v, n); 2034 } 2035 2036 size_type 2037 size() const 2038 { 2039 return 1; 2040 } 2041 2042 bool 2043 zero() const 2044 { 2045 return data()->zero(); 2046 } 2047 2048 /** 2049 * Proxy has no state. Nothing to reset. 2050 */ 2051 void reset() { } 2052}; 2053 2054////////////////////////////////////////////////////////////////////// 2055// 2056// Formula Details 2057// 2058////////////////////////////////////////////////////////////////////// 2059 2060/** 2061 * Base class for formula statistic node. These nodes are used to build a tree 2062 * that represents the formula. 2063 */ 2064class Node 2065{ 2066 public: 2067 /** 2068 * Return the number of nodes in the subtree starting at this node. 2069 * @return the number of nodes in this subtree. 2070 */ 2071 virtual size_type size() const = 0; 2072 /** 2073 * Return the result vector of this subtree. 2074 * @return The result vector of this subtree. 2075 */ 2076 virtual const VResult &result() const = 0; 2077 /** 2078 * Return the total of the result vector. 2079 * @return The total of the result vector. 2080 */ 2081 virtual Result total() const = 0; 2082 2083 /** 2084 * 2085 */ 2086 virtual std::string str() const = 0; 2087 2088 virtual ~Node() {}; 2089}; 2090 2091/** Shared pointer to a function Node. */ 2092typedef std::shared_ptr<Node> NodePtr; 2093 2094class ScalarStatNode : public Node 2095{ 2096 private: 2097 const ScalarInfo *data; 2098 mutable VResult vresult; 2099 2100 public: 2101 ScalarStatNode(const ScalarInfo *d) : data(d), vresult(1) {} 2102 2103 const VResult & 2104 result() const 2105 { 2106 vresult[0] = data->result(); 2107 return vresult; 2108 } 2109 2110 Result total() const { return data->result(); }; 2111 2112 size_type size() const { return 1; } 2113 2114 /** 2115 * 2116 */ 2117 std::string str() const { return data->name; } 2118}; 2119 2120template <class Stat> 2121class ScalarProxyNode : public Node 2122{ 2123 private: 2124 const ScalarProxy<Stat> proxy; 2125 mutable VResult vresult; 2126 2127 public: 2128 ScalarProxyNode(const ScalarProxy<Stat> &p) 2129 : proxy(p), vresult(1) 2130 { } 2131 2132 const VResult & 2133 result() const 2134 { 2135 vresult[0] = proxy.result(); 2136 return vresult; 2137 } 2138 2139 Result 2140 total() const 2141 { 2142 return proxy.result(); 2143 } 2144 2145 size_type 2146 size() const 2147 { 2148 return 1; 2149 } 2150 2151 /** 2152 * 2153 */ 2154 std::string 2155 str() const 2156 { 2157 return proxy.str(); 2158 } 2159}; 2160 2161class VectorStatNode : public Node 2162{ 2163 private: 2164 const VectorInfo *data; 2165 2166 public: 2167 VectorStatNode(const VectorInfo *d) : data(d) { } 2168 const VResult &result() const { return data->result(); } 2169 Result total() const { return data->total(); }; 2170 2171 size_type size() const { return data->size(); } 2172 2173 std::string str() const { return data->name; } 2174}; 2175 2176template <class T> 2177class ConstNode : public Node 2178{ 2179 private: 2180 VResult vresult; 2181 2182 public: 2183 ConstNode(T s) : vresult(1, (Result)s) {} 2184 const VResult &result() const { return vresult; } 2185 Result total() const { return vresult[0]; }; 2186 size_type size() const { return 1; } 2187 std::string str() const { return std::to_string(vresult[0]); } 2188}; 2189 2190template <class T> 2191class ConstVectorNode : public Node 2192{ 2193 private: 2194 VResult vresult; 2195 2196 public: 2197 ConstVectorNode(const T &s) : vresult(s.begin(), s.end()) {} 2198 const VResult &result() const { return vresult; } 2199 2200 Result 2201 total() const 2202 { 2203 size_type size = this->size(); 2204 Result tmp = 0; 2205 for (off_type i = 0; i < size; i++) 2206 tmp += vresult[i]; 2207 return tmp; 2208 } 2209 2210 size_type size() const { return vresult.size(); } 2211 std::string 2212 str() const 2213 { 2214 size_type size = this->size(); 2215 std::string tmp = "("; 2216 for (off_type i = 0; i < size; i++) 2217 tmp += csprintf("%s ", std::to_string(vresult[i])); 2218 tmp += ")"; 2219 return tmp; 2220 } 2221}; 2222 2223template <class Op> 2224struct OpString; 2225 2226template<> 2227struct OpString<std::plus<Result> > 2228{ 2229 static std::string str() { return "+"; } 2230}; 2231 2232template<> 2233struct OpString<std::minus<Result> > 2234{ 2235 static std::string str() { return "-"; } 2236}; 2237 2238template<> 2239struct OpString<std::multiplies<Result> > 2240{ 2241 static std::string str() { return "*"; } 2242}; 2243 2244template<> 2245struct OpString<std::divides<Result> > 2246{ 2247 static std::string str() { return "/"; } 2248}; 2249 2250template<> 2251struct OpString<std::modulus<Result> > 2252{ 2253 static std::string str() { return "%"; } 2254}; 2255 2256template<> 2257struct OpString<std::negate<Result> > 2258{ 2259 static std::string str() { return "-"; } 2260}; 2261 2262template <class Op> 2263class UnaryNode : public Node 2264{ 2265 public: 2266 NodePtr l; 2267 mutable VResult vresult; 2268 2269 public: 2270 UnaryNode(NodePtr &p) : l(p) {} 2271 2272 const VResult & 2273 result() const 2274 { 2275 const VResult &lvec = l->result(); 2276 size_type size = lvec.size(); 2277 2278 assert(size > 0); 2279 2280 vresult.resize(size); 2281 Op op; 2282 for (off_type i = 0; i < size; ++i) 2283 vresult[i] = op(lvec[i]); 2284 2285 return vresult; 2286 } 2287 2288 Result 2289 total() const 2290 { 2291 const VResult &vec = this->result(); 2292 Result total = 0.0; 2293 for (off_type i = 0; i < size(); i++) 2294 total += vec[i]; 2295 return total; 2296 } 2297 2298 size_type size() const { return l->size(); } 2299 2300 std::string 2301 str() const 2302 { 2303 return OpString<Op>::str() + l->str(); 2304 } 2305}; 2306 2307template <class Op> 2308class BinaryNode : public Node 2309{ 2310 public: 2311 NodePtr l; 2312 NodePtr r; 2313 mutable VResult vresult; 2314 2315 public: 2316 BinaryNode(NodePtr &a, NodePtr &b) : l(a), r(b) {} 2317 2318 const VResult & 2319 result() const override 2320 { 2321 Op op; 2322 const VResult &lvec = l->result(); 2323 const VResult &rvec = r->result(); 2324 2325 assert(lvec.size() > 0 && rvec.size() > 0); 2326 2327 if (lvec.size() == 1 && rvec.size() == 1) { 2328 vresult.resize(1); 2329 vresult[0] = op(lvec[0], rvec[0]); 2330 } else if (lvec.size() == 1) { 2331 size_type size = rvec.size(); 2332 vresult.resize(size); 2333 for (off_type i = 0; i < size; ++i) 2334 vresult[i] = op(lvec[0], rvec[i]); 2335 } else if (rvec.size() == 1) { 2336 size_type size = lvec.size(); 2337 vresult.resize(size); 2338 for (off_type i = 0; i < size; ++i) 2339 vresult[i] = op(lvec[i], rvec[0]); 2340 } else if (rvec.size() == lvec.size()) { 2341 size_type size = rvec.size(); 2342 vresult.resize(size); 2343 for (off_type i = 0; i < size; ++i) 2344 vresult[i] = op(lvec[i], rvec[i]); 2345 } 2346 2347 return vresult; 2348 } 2349 2350 Result 2351 total() const override 2352 { 2353 const VResult &vec = this->result(); 2354 const VResult &lvec = l->result(); 2355 const VResult &rvec = r->result(); 2356 Result total = 0.0; 2357 Result lsum = 0.0; 2358 Result rsum = 0.0; 2359 Op op; 2360 2361 assert(lvec.size() > 0 && rvec.size() > 0); 2362 assert(lvec.size() == rvec.size() || 2363 lvec.size() == 1 || rvec.size() == 1); 2364 2365 /** If vectors are the same divide their sums (x0+x1)/(y0+y1) */ 2366 if (lvec.size() == rvec.size() && lvec.size() > 1) { 2367 for (off_type i = 0; i < size(); ++i) { 2368 lsum += lvec[i]; 2369 rsum += rvec[i]; 2370 } 2371 return op(lsum, rsum); 2372 } 2373 2374 /** Otherwise divide each item by the divisor */ 2375 for (off_type i = 0; i < size(); ++i) { 2376 total += vec[i]; 2377 } 2378 2379 return total; 2380 } 2381 2382 size_type 2383 size() const override 2384 { 2385 size_type ls = l->size(); 2386 size_type rs = r->size(); 2387 if (ls == 1) { 2388 return rs; 2389 } else if (rs == 1) { 2390 return ls; 2391 } else { 2392 assert(ls == rs && "Node vector sizes are not equal"); 2393 return ls; 2394 } 2395 } 2396 2397 std::string 2398 str() const override 2399 { 2400 return csprintf("(%s %s %s)", l->str(), OpString<Op>::str(), r->str()); 2401 } 2402}; 2403 2404template <class Op> 2405class SumNode : public Node 2406{ 2407 public: 2408 NodePtr l; 2409 mutable VResult vresult; 2410 2411 public: 2412 SumNode(NodePtr &p) : l(p), vresult(1) {} 2413 2414 const VResult & 2415 result() const 2416 { 2417 const VResult &lvec = l->result(); 2418 size_type size = lvec.size(); 2419 assert(size > 0); 2420 2421 vresult[0] = 0.0; 2422 2423 Op op; 2424 for (off_type i = 0; i < size; ++i) 2425 vresult[0] = op(vresult[0], lvec[i]); 2426 2427 return vresult; 2428 } 2429 2430 Result 2431 total() const 2432 { 2433 const VResult &lvec = l->result(); 2434 size_type size = lvec.size(); 2435 assert(size > 0); 2436 2437 Result result = 0.0; 2438 2439 Op op; 2440 for (off_type i = 0; i < size; ++i) 2441 result = op(result, lvec[i]); 2442 2443 return result; 2444 } 2445 2446 size_type size() const { return 1; } 2447 2448 std::string 2449 str() const 2450 { 2451 return csprintf("total(%s)", l->str()); 2452 } 2453}; 2454 2455 2456////////////////////////////////////////////////////////////////////// 2457// 2458// Visible Statistics Types 2459// 2460////////////////////////////////////////////////////////////////////// 2461/** 2462 * @defgroup VisibleStats "Statistic Types" 2463 * These are the statistics that are used in the simulator. 2464 * @{ 2465 */ 2466 2467/** 2468 * This is a simple scalar statistic, like a counter. 2469 * @sa Stat, ScalarBase, StatStor 2470 */ 2471class Scalar : public ScalarBase<Scalar, StatStor> 2472{ 2473 public: 2474 using ScalarBase<Scalar, StatStor>::operator=; 2475}; 2476 2477/** 2478 * A stat that calculates the per tick average of a value. 2479 * @sa Stat, ScalarBase, AvgStor 2480 */ 2481class Average : public ScalarBase<Average, AvgStor> 2482{ 2483 public: 2484 using ScalarBase<Average, AvgStor>::operator=; 2485}; 2486 2487class Value : public ValueBase<Value> 2488{ 2489}; 2490 2491/** 2492 * A vector of scalar stats. 2493 * @sa Stat, VectorBase, StatStor 2494 */ 2495class Vector : public VectorBase<Vector, StatStor> 2496{ 2497}; 2498 2499/** 2500 * A vector of Average stats. 2501 * @sa Stat, VectorBase, AvgStor 2502 */ 2503class AverageVector : public VectorBase<AverageVector, AvgStor> 2504{ 2505}; 2506 2507/** 2508 * A 2-Dimensional vecto of scalar stats. 2509 * @sa Stat, Vector2dBase, StatStor 2510 */ 2511class Vector2d : public Vector2dBase<Vector2d, StatStor> 2512{ 2513}; 2514 2515/** 2516 * A simple distribution stat. 2517 * @sa Stat, DistBase, DistStor 2518 */ 2519class Distribution : public DistBase<Distribution, DistStor> 2520{ 2521 public: 2522 /** 2523 * Set the parameters of this distribution. @sa DistStor::Params 2524 * @param min The minimum value of the distribution. 2525 * @param max The maximum value of the distribution. 2526 * @param bkt The number of values in each bucket. 2527 * @return A reference to this distribution. 2528 */ 2529 Distribution & 2530 init(Counter min, Counter max, Counter bkt) 2531 { 2532 DistStor::Params *params = new DistStor::Params; 2533 params->min = min; 2534 params->max = max; 2535 params->bucket_size = bkt; 2536 // Division by zero is especially serious in an Aarch64 host, 2537 // where it gets rounded to allocate 32GiB RAM. 2538 assert(bkt > 0); 2539 params->buckets = (size_type)ceil((max - min + 1.0) / bkt); 2540 this->setParams(params); 2541 this->doInit(); 2542 return this->self(); 2543 } 2544}; 2545 2546/** 2547 * A simple histogram stat. 2548 * @sa Stat, DistBase, HistStor 2549 */ 2550class Histogram : public DistBase<Histogram, HistStor> 2551{ 2552 public: 2553 /** 2554 * Set the parameters of this histogram. @sa HistStor::Params 2555 * @param size The number of buckets in the histogram 2556 * @return A reference to this histogram. 2557 */ 2558 Histogram & 2559 init(size_type size) 2560 { 2561 HistStor::Params *params = new HistStor::Params; 2562 params->buckets = size; 2563 this->setParams(params); 2564 this->doInit(); 2565 return this->self(); 2566 } 2567}; 2568 2569/** 2570 * Calculates the mean and variance of all the samples. 2571 * @sa DistBase, SampleStor 2572 */ 2573class StandardDeviation : public DistBase<StandardDeviation, SampleStor> 2574{ 2575 public: 2576 /** 2577 * Construct and initialize this distribution. 2578 */ 2579 StandardDeviation() 2580 { 2581 SampleStor::Params *params = new SampleStor::Params; 2582 this->doInit(); 2583 this->setParams(params); 2584 } 2585}; 2586 2587/** 2588 * Calculates the per tick mean and variance of the samples. 2589 * @sa DistBase, AvgSampleStor 2590 */ 2591class AverageDeviation : public DistBase<AverageDeviation, AvgSampleStor> 2592{ 2593 public: 2594 /** 2595 * Construct and initialize this distribution. 2596 */ 2597 AverageDeviation() 2598 { 2599 AvgSampleStor::Params *params = new AvgSampleStor::Params; 2600 this->doInit(); 2601 this->setParams(params); 2602 } 2603}; 2604 2605/** 2606 * A vector of distributions. 2607 * @sa VectorDistBase, DistStor 2608 */ 2609class VectorDistribution : public VectorDistBase<VectorDistribution, DistStor> 2610{ 2611 public: 2612 /** 2613 * Initialize storage and parameters for this distribution. 2614 * @param size The size of the vector (the number of distributions). 2615 * @param min The minimum value of the distribution. 2616 * @param max The maximum value of the distribution. 2617 * @param bkt The number of values in each bucket. 2618 * @return A reference to this distribution. 2619 */ 2620 VectorDistribution & 2621 init(size_type size, Counter min, Counter max, Counter bkt) 2622 { 2623 DistStor::Params *params = new DistStor::Params; 2624 params->min = min; 2625 params->max = max; 2626 params->bucket_size = bkt; 2627 params->buckets = (size_type)ceil((max - min + 1.0) / bkt); 2628 this->setParams(params); 2629 this->doInit(size); 2630 return this->self(); 2631 } 2632}; 2633 2634/** 2635 * This is a vector of StandardDeviation stats. 2636 * @sa VectorDistBase, SampleStor 2637 */ 2638class VectorStandardDeviation 2639 : public VectorDistBase<VectorStandardDeviation, SampleStor> 2640{ 2641 public: 2642 /** 2643 * Initialize storage for this distribution. 2644 * @param size The size of the vector. 2645 * @return A reference to this distribution. 2646 */ 2647 VectorStandardDeviation & 2648 init(size_type size) 2649 { 2650 SampleStor::Params *params = new SampleStor::Params; 2651 this->doInit(size); 2652 this->setParams(params); 2653 return this->self(); 2654 } 2655}; 2656 2657/** 2658 * This is a vector of AverageDeviation stats. 2659 * @sa VectorDistBase, AvgSampleStor 2660 */ 2661class VectorAverageDeviation 2662 : public VectorDistBase<VectorAverageDeviation, AvgSampleStor> 2663{ 2664 public: 2665 /** 2666 * Initialize storage for this distribution. 2667 * @param size The size of the vector. 2668 * @return A reference to this distribution. 2669 */ 2670 VectorAverageDeviation & 2671 init(size_type size) 2672 { 2673 AvgSampleStor::Params *params = new AvgSampleStor::Params; 2674 this->doInit(size); 2675 this->setParams(params); 2676 return this->self(); 2677 } 2678}; 2679 2680template <class Stat> 2681class FormulaInfoProxy : public InfoProxy<Stat, FormulaInfo> 2682{ 2683 protected: 2684 mutable VResult vec; 2685 mutable VCounter cvec; 2686 2687 public: 2688 FormulaInfoProxy(Stat &stat) : InfoProxy<Stat, FormulaInfo>(stat) {} 2689 2690 size_type size() const { return this->s.size(); } 2691 2692 const VResult & 2693 result() const 2694 { 2695 this->s.result(vec); 2696 return vec; 2697 } 2698 Result total() const { return this->s.total(); } 2699 VCounter &value() const { return cvec; } 2700 2701 std::string str() const { return this->s.str(); } 2702}; 2703 2704template <class Stat> 2705class SparseHistInfoProxy : public InfoProxy<Stat, SparseHistInfo> 2706{ 2707 public: 2708 SparseHistInfoProxy(Stat &stat) : InfoProxy<Stat, SparseHistInfo>(stat) {} 2709}; 2710 2711/** 2712 * Implementation of a sparse histogram stat. The storage class is 2713 * determined by the Storage template. 2714 */ 2715template <class Derived, class Stor> 2716class SparseHistBase : public DataWrap<Derived, SparseHistInfoProxy> 2717{ 2718 public: 2719 typedef SparseHistInfoProxy<Derived> Info; 2720 typedef Stor Storage; 2721 typedef typename Stor::Params Params; 2722 2723 protected: 2724 /** The storage for this stat. */ 2725 char storage[sizeof(Storage)]; 2726 2727 protected: 2728 /** 2729 * Retrieve the storage. 2730 * @return The storage object for this stat. 2731 */ 2732 Storage * 2733 data() 2734 { 2735 return reinterpret_cast<Storage *>(storage); 2736 } 2737 2738 /** 2739 * Retrieve a const pointer to the storage. 2740 * @return A const pointer to the storage object for this stat. 2741 */ 2742 const Storage * 2743 data() const 2744 { 2745 return reinterpret_cast<const Storage *>(storage); 2746 } 2747 2748 void 2749 doInit() 2750 { 2751 new (storage) Storage(this->info()); 2752 this->setInit(); 2753 } 2754 2755 public: 2756 SparseHistBase() { } 2757 2758 /** 2759 * Add a value to the distribtion n times. Calls sample on the storage 2760 * class. 2761 * @param v The value to add. 2762 * @param n The number of times to add it, defaults to 1. 2763 */ 2764 template <typename U> 2765 void sample(const U &v, int n = 1) { data()->sample(v, n); } 2766 2767 /** 2768 * Return the number of entries in this stat. 2769 * @return The number of entries. 2770 */ 2771 size_type size() const { return data()->size(); } 2772 /** 2773 * Return true if no samples have been added. 2774 * @return True if there haven't been any samples. 2775 */ 2776 bool zero() const { return data()->zero(); } 2777 2778 void 2779 prepare() 2780 { 2781 Info *info = this->info(); 2782 data()->prepare(info, info->data); 2783 } 2784 2785 /** 2786 * Reset stat value to default 2787 */ 2788 void 2789 reset() 2790 { 2791 data()->reset(this->info()); 2792 } 2793}; 2794 2795/** 2796 * Templatized storage and interface for a sparse histogram stat. 2797 */ 2798class SparseHistStor 2799{ 2800 public: 2801 /** The parameters for a sparse histogram stat. */ 2802 struct Params : public DistParams 2803 { 2804 Params() : DistParams(Hist) {} 2805 }; 2806 2807 private: 2808 /** Counter for number of samples */ 2809 Counter samples; 2810 /** Counter for each bucket. */ 2811 MCounter cmap; 2812 2813 public: 2814 SparseHistStor(Info *info) 2815 { 2816 reset(info); 2817 } 2818 2819 /** 2820 * Add a value to the distribution for the given number of times. 2821 * @param val The value to add. 2822 * @param number The number of times to add the value. 2823 */ 2824 void 2825 sample(Counter val, int number) 2826 { 2827 cmap[val] += number; 2828 samples += number; 2829 } 2830 2831 /** 2832 * Return the number of buckets in this distribution. 2833 * @return the number of buckets. 2834 */ 2835 size_type size() const { return cmap.size(); } 2836 2837 /** 2838 * Returns true if any calls to sample have been made. 2839 * @return True if any values have been sampled. 2840 */ 2841 bool 2842 zero() const 2843 { 2844 return samples == Counter(); 2845 } 2846 2847 void 2848 prepare(Info *info, SparseHistData &data) 2849 { 2850 MCounter::iterator it; 2851 data.cmap.clear(); 2852 for (it = cmap.begin(); it != cmap.end(); it++) { 2853 data.cmap[(*it).first] = (*it).second; 2854 } 2855 2856 data.samples = samples; 2857 } 2858 2859 /** 2860 * Reset stat value to default 2861 */ 2862 void 2863 reset(Info *info) 2864 { 2865 cmap.clear(); 2866 samples = 0; 2867 } 2868}; 2869 2870class SparseHistogram : public SparseHistBase<SparseHistogram, SparseHistStor> 2871{ 2872 public: 2873 /** 2874 * Set the parameters of this histogram. @sa HistStor::Params 2875 * @param size The number of buckets in the histogram 2876 * @return A reference to this histogram. 2877 */ 2878 SparseHistogram & 2879 init(size_type size) 2880 { 2881 SparseHistStor::Params *params = new SparseHistStor::Params; 2882 this->setParams(params); 2883 this->doInit(); 2884 return this->self(); 2885 } 2886}; 2887 2888class Temp; 2889/** 2890 * A formula for statistics that is calculated when printed. A formula is 2891 * stored as a tree of Nodes that represent the equation to calculate. 2892 * @sa Stat, ScalarStat, VectorStat, Node, Temp 2893 */ 2894class Formula : public DataWrapVec<Formula, FormulaInfoProxy> 2895{ 2896 protected: 2897 /** The root of the tree which represents the Formula */ 2898 NodePtr root; 2899 friend class Temp; 2900 2901 public: 2902 /** 2903 * Create and initialize thie formula, and register it with the database. 2904 */ 2905 Formula(); 2906 2907 /** 2908 * Create a formula with the given root node, register it with the 2909 * database. 2910 * @param r The root of the expression tree. 2911 */ 2912 Formula(Temp r); 2913 2914 /** 2915 * Set an unitialized Formula to the given root. 2916 * @param r The root of the expression tree. 2917 * @return a reference to this formula. 2918 */ 2919 const Formula &operator=(Temp r); 2920 2921 /** 2922 * Add the given tree to the existing one. 2923 * @param r The root of the expression tree. 2924 * @return a reference to this formula. 2925 */ 2926 const Formula &operator+=(Temp r); 2927 2928 /** 2929 * Divide the existing tree by the given one. 2930 * @param r The root of the expression tree. 2931 * @return a reference to this formula. 2932 */ 2933 const Formula &operator/=(Temp r); 2934 2935 /** 2936 * Return the result of the Fomula in a vector. If there were no Vector 2937 * components to the Formula, then the vector is size 1. If there were, 2938 * like x/y with x being a vector of size 3, then the result returned will 2939 * be x[0]/y, x[1]/y, x[2]/y, respectively. 2940 * @return The result vector. 2941 */ 2942 void result(VResult &vec) const; 2943 2944 /** 2945 * Return the total Formula result. If there is a Vector 2946 * component to this Formula, then this is the result of the 2947 * Formula if the formula is applied after summing all the 2948 * components of the Vector. For example, if Formula is x/y where 2949 * x is size 3, then total() will return (x[1]+x[2]+x[3])/y. If 2950 * there is no Vector component, total() returns the same value as 2951 * the first entry in the VResult val() returns. 2952 * @return The total of the result vector. 2953 */ 2954 Result total() const; 2955 2956 /** 2957 * Return the number of elements in the tree. 2958 */ 2959 size_type size() const; 2960 2961 void prepare() { } 2962 2963 /** 2964 * Formulas don't need to be reset 2965 */ 2966 void reset(); 2967 2968 /** 2969 * 2970 */ 2971 bool zero() const; 2972 2973 std::string str() const; 2974}; 2975 2976class FormulaNode : public Node 2977{ 2978 private: 2979 const Formula &formula; 2980 mutable VResult vec; 2981 2982 public: 2983 FormulaNode(const Formula &f) : formula(f) {} 2984 2985 size_type size() const { return formula.size(); } 2986 const VResult &result() const { formula.result(vec); return vec; } 2987 Result total() const { return formula.total(); } 2988 2989 std::string str() const { return formula.str(); } 2990}; 2991 2992/** 2993 * Helper class to construct formula node trees. 2994 */ 2995class Temp 2996{ 2997 protected: 2998 /** 2999 * Pointer to a Node object. 3000 */ 3001 NodePtr node; 3002 3003 public: 3004 /** 3005 * Copy the given pointer to this class. 3006 * @param n A pointer to a Node object to copy. 3007 */ 3008 Temp(const NodePtr &n) : node(n) { } 3009 3010 Temp(NodePtr &&n) : node(std::move(n)) { } 3011 3012 /** 3013 * Return the node pointer. 3014 * @return the node pointer. 3015 */ 3016 operator NodePtr&() { return node; } 3017 3018 /** 3019 * Makde gcc < 4.6.3 happy and explicitly get the underlying node. 3020 */ 3021 NodePtr getNodePtr() const { return node; } 3022 3023 public: 3024 /** 3025 * Create a new ScalarStatNode. 3026 * @param s The ScalarStat to place in a node. 3027 */ 3028 Temp(const Scalar &s) 3029 : node(new ScalarStatNode(s.info())) 3030 { } 3031 3032 /** 3033 * Create a new ScalarStatNode. 3034 * @param s The ScalarStat to place in a node. 3035 */ 3036 Temp(const Value &s) 3037 : node(new ScalarStatNode(s.info())) 3038 { } 3039 3040 /** 3041 * Create a new ScalarStatNode. 3042 * @param s The ScalarStat to place in a node. 3043 */ 3044 Temp(const Average &s) 3045 : node(new ScalarStatNode(s.info())) 3046 { } 3047 3048 /** 3049 * Create a new VectorStatNode. 3050 * @param s The VectorStat to place in a node. 3051 */ 3052 Temp(const Vector &s) 3053 : node(new VectorStatNode(s.info())) 3054 { } 3055 3056 Temp(const AverageVector &s) 3057 : node(new VectorStatNode(s.info())) 3058 { } 3059 3060 /** 3061 * 3062 */ 3063 Temp(const Formula &f) 3064 : node(new FormulaNode(f)) 3065 { } 3066 3067 /** 3068 * Create a new ScalarProxyNode. 3069 * @param p The ScalarProxy to place in a node. 3070 */ 3071 template <class Stat> 3072 Temp(const ScalarProxy<Stat> &p) 3073 : node(new ScalarProxyNode<Stat>(p)) 3074 { } 3075 3076 /** 3077 * Create a ConstNode 3078 * @param value The value of the const node. 3079 */ 3080 Temp(signed char value) 3081 : node(new ConstNode<signed char>(value)) 3082 { } 3083 3084 /** 3085 * Create a ConstNode 3086 * @param value The value of the const node. 3087 */ 3088 Temp(unsigned char value) 3089 : node(new ConstNode<unsigned char>(value)) 3090 { } 3091 3092 /** 3093 * Create a ConstNode 3094 * @param value The value of the const node. 3095 */ 3096 Temp(signed short value) 3097 : node(new ConstNode<signed short>(value)) 3098 { } 3099 3100 /** 3101 * Create a ConstNode 3102 * @param value The value of the const node. 3103 */ 3104 Temp(unsigned short value) 3105 : node(new ConstNode<unsigned short>(value)) 3106 { } 3107 3108 /** 3109 * Create a ConstNode 3110 * @param value The value of the const node. 3111 */ 3112 Temp(signed int value) 3113 : node(new ConstNode<signed int>(value)) 3114 { } 3115 3116 /** 3117 * Create a ConstNode 3118 * @param value The value of the const node. 3119 */ 3120 Temp(unsigned int value) 3121 : node(new ConstNode<unsigned int>(value)) 3122 { } 3123 3124 /** 3125 * Create a ConstNode 3126 * @param value The value of the const node. 3127 */ 3128 Temp(signed long value) 3129 : node(new ConstNode<signed long>(value)) 3130 { } 3131 3132 /** 3133 * Create a ConstNode 3134 * @param value The value of the const node. 3135 */ 3136 Temp(unsigned long value) 3137 : node(new ConstNode<unsigned long>(value)) 3138 { } 3139 3140 /** 3141 * Create a ConstNode 3142 * @param value The value of the const node. 3143 */ 3144 Temp(signed long long value) 3145 : node(new ConstNode<signed long long>(value)) 3146 { } 3147 3148 /** 3149 * Create a ConstNode 3150 * @param value The value of the const node. 3151 */ 3152 Temp(unsigned long long value) 3153 : node(new ConstNode<unsigned long long>(value)) 3154 { } 3155 3156 /** 3157 * Create a ConstNode 3158 * @param value The value of the const node. 3159 */ 3160 Temp(float value) 3161 : node(new ConstNode<float>(value)) 3162 { } 3163 3164 /** 3165 * Create a ConstNode 3166 * @param value The value of the const node. 3167 */ 3168 Temp(double value) 3169 : node(new ConstNode<double>(value)) 3170 { } 3171}; 3172 3173 3174/** 3175 * @} 3176 */ 3177 3178inline Temp 3179operator+(Temp l, Temp r) 3180{ 3181 return Temp(std::make_shared<BinaryNode<std::plus<Result> > >(l, r)); 3182} 3183 3184inline Temp 3185operator-(Temp l, Temp r) 3186{ 3187 return Temp(std::make_shared<BinaryNode<std::minus<Result> > >(l, r)); 3188} 3189 3190inline Temp 3191operator*(Temp l, Temp r) 3192{ 3193 return Temp(std::make_shared<BinaryNode<std::multiplies<Result> > >(l, r)); 3194} 3195 3196inline Temp 3197operator/(Temp l, Temp r) 3198{ 3199 return Temp(std::make_shared<BinaryNode<std::divides<Result> > >(l, r)); 3200} 3201 3202inline Temp 3203operator-(Temp l) 3204{ 3205 return Temp(std::make_shared<UnaryNode<std::negate<Result> > >(l)); 3206} 3207 3208template <typename T> 3209inline Temp 3210constant(T val) 3211{ 3212 return Temp(std::make_shared<ConstNode<T> >(val)); 3213} 3214 3215template <typename T> 3216inline Temp 3217constantVector(T val) 3218{ 3219 return Temp(std::make_shared<ConstVectorNode<T> >(val)); 3220} 3221 3222inline Temp 3223sum(Temp val) 3224{ 3225 return Temp(std::make_shared<SumNode<std::plus<Result> > >(val)); 3226} 3227 3228/** Dump all statistics data to the registered outputs */ 3229void dump(); 3230void reset(); 3231void enable(); 3232bool enabled(); 3233 3234/** 3235 * Register reset and dump handlers. These are the functions which 3236 * will actually perform the whole statistics reset/dump actions 3237 * including processing the reset/dump callbacks 3238 */ 3239typedef void (*Handler)(); 3240 3241void registerHandlers(Handler reset_handler, Handler dump_handler); 3242 3243/** 3244 * Register a callback that should be called whenever statistics are 3245 * reset 3246 */ 3247void registerResetCallback(Callback *cb); 3248 3249/** 3250 * Register a callback that should be called whenever statistics are 3251 * about to be dumped 3252 */ 3253void registerDumpCallback(Callback *cb); 3254 3255/** 3256 * Process all the callbacks in the reset callbacks queue 3257 */ 3258void processResetQueue(); 3259 3260/** 3261 * Process all the callbacks in the dump callbacks queue 3262 */ 3263void processDumpQueue(); 3264 3265std::list<Info *> &statsList(); 3266 3267typedef std::map<const void *, Info *> MapType; 3268MapType &statsMap(); 3269 3270typedef std::map<std::string, Info *> NameMapType; 3271NameMapType &nameMap(); 3272 3273bool validateStatName(const std::string &name); 3274 3275} // namespace Stats 3276 3277void debugDumpStats(); 3278 3279#endif // __BASE_STATISTICS_HH__ 3280