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