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