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