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