statistics.hh revision 13475:5189e2334f1a
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#if 0
1298        for (off_type i = 0; i < size(); ++i)
1299            if (!data(i)->zero())
1300                return false;
1301        return true;
1302#endif
1303    }
1304
1305    /**
1306     * Return a total of all entries in this vector.
1307     * @return The total of all vector entries.
1308     */
1309    Result
1310    total() const
1311    {
1312        Result total = 0.0;
1313        for (off_type i = 0; i < size(); ++i)
1314            total += data(i)->result();
1315        return total;
1316    }
1317
1318    void
1319    prepare()
1320    {
1321        Info *info = this->info();
1322        size_type size = this->size();
1323
1324        for (off_type i = 0; i < size; ++i)
1325            data(i)->prepare(info);
1326
1327        info->cvec.resize(size);
1328        for (off_type i = 0; i < size; ++i)
1329            info->cvec[i] = data(i)->value();
1330    }
1331
1332    /**
1333     * Reset stat value to default
1334     */
1335    void
1336    reset()
1337    {
1338        Info *info = this->info();
1339        size_type size = this->size();
1340        for (off_type i = 0; i < size; ++i)
1341            data(i)->reset(info);
1342    }
1343
1344    bool
1345    check() const
1346    {
1347        return storage != NULL;
1348    }
1349};
1350
1351//////////////////////////////////////////////////////////////////////
1352//
1353// Non formula statistics
1354//
1355//////////////////////////////////////////////////////////////////////
1356/** The parameters for a distribution stat. */
1357struct DistParams : public StorageParams
1358{
1359    const DistType type;
1360    DistParams(DistType t) : type(t) {}
1361};
1362
1363/**
1364 * Templatized storage and interface for a distribution stat.
1365 */
1366class DistStor
1367{
1368  public:
1369    /** The parameters for a distribution stat. */
1370    struct Params : public DistParams
1371    {
1372        /** The minimum value to track. */
1373        Counter min;
1374        /** The maximum value to track. */
1375        Counter max;
1376        /** The number of entries in each bucket. */
1377        Counter bucket_size;
1378        /** The number of buckets. Equal to (max-min)/bucket_size. */
1379        size_type buckets;
1380
1381        Params() : DistParams(Dist), min(0), max(0), bucket_size(0),
1382                   buckets(0) {}
1383    };
1384
1385  private:
1386    /** The minimum value to track. */
1387    Counter min_track;
1388    /** The maximum value to track. */
1389    Counter max_track;
1390    /** The number of entries in each bucket. */
1391    Counter bucket_size;
1392
1393    /** The smallest value sampled. */
1394    Counter min_val;
1395    /** The largest value sampled. */
1396    Counter max_val;
1397    /** The number of values sampled less than min. */
1398    Counter underflow;
1399    /** The number of values sampled more than max. */
1400    Counter overflow;
1401    /** The current sum. */
1402    Counter sum;
1403    /** The sum of squares. */
1404    Counter squares;
1405    /** The number of samples. */
1406    Counter samples;
1407    /** Counter for each bucket. */
1408    VCounter cvec;
1409
1410  public:
1411    DistStor(Info *info)
1412        : cvec(safe_cast<const Params *>(info->storageParams)->buckets)
1413    {
1414        reset(info);
1415    }
1416
1417    /**
1418     * Add a value to the distribution for the given number of times.
1419     * @param val The value to add.
1420     * @param number The number of times to add the value.
1421     */
1422    void
1423    sample(Counter val, int number)
1424    {
1425        if (val < min_track)
1426            underflow += number;
1427        else if (val > max_track)
1428            overflow += number;
1429        else {
1430            size_type index =
1431                (size_type)std::floor((val - min_track) / bucket_size);
1432            assert(index < size());
1433            cvec[index] += number;
1434        }
1435
1436        if (val < min_val)
1437            min_val = val;
1438
1439        if (val > max_val)
1440            max_val = val;
1441
1442        sum += val * number;
1443        squares += val * val * number;
1444        samples += number;
1445    }
1446
1447    /**
1448     * Return the number of buckets in this distribution.
1449     * @return the number of buckets.
1450     */
1451    size_type size() const { return cvec.size(); }
1452
1453    /**
1454     * Returns true if any calls to sample have been made.
1455     * @return True if any values have been sampled.
1456     */
1457    bool
1458    zero() const
1459    {
1460        return samples == Counter();
1461    }
1462
1463    void
1464    prepare(Info *info, DistData &data)
1465    {
1466        const Params *params = safe_cast<const Params *>(info->storageParams);
1467
1468        assert(params->type == Dist);
1469        data.type = params->type;
1470        data.min = params->min;
1471        data.max = params->max;
1472        data.bucket_size = params->bucket_size;
1473
1474        data.min_val = (min_val == CounterLimits::max()) ? 0 : min_val;
1475        data.max_val = (max_val == CounterLimits::min()) ? 0 : max_val;
1476        data.underflow = underflow;
1477        data.overflow = overflow;
1478
1479        data.cvec.resize(params->buckets);
1480        for (off_type i = 0; i < params->buckets; ++i)
1481            data.cvec[i] = cvec[i];
1482
1483        data.sum = sum;
1484        data.squares = squares;
1485        data.samples = samples;
1486    }
1487
1488    /**
1489     * Reset stat value to default
1490     */
1491    void
1492    reset(Info *info)
1493    {
1494        const Params *params = safe_cast<const Params *>(info->storageParams);
1495        min_track = params->min;
1496        max_track = params->max;
1497        bucket_size = params->bucket_size;
1498
1499        min_val = CounterLimits::max();
1500        max_val = CounterLimits::min();
1501        underflow = Counter();
1502        overflow = Counter();
1503
1504        size_type size = cvec.size();
1505        for (off_type i = 0; i < size; ++i)
1506            cvec[i] = Counter();
1507
1508        sum = Counter();
1509        squares = Counter();
1510        samples = Counter();
1511    }
1512};
1513
1514/**
1515 * Templatized storage and interface for a histogram stat.
1516 */
1517class HistStor
1518{
1519  public:
1520    /** The parameters for a distribution stat. */
1521    struct Params : public DistParams
1522    {
1523        /** The number of buckets.. */
1524        size_type buckets;
1525
1526        Params() : DistParams(Hist), buckets(0) {}
1527    };
1528
1529  private:
1530    /** The minimum value to track. */
1531    Counter min_bucket;
1532    /** The maximum value to track. */
1533    Counter max_bucket;
1534    /** The number of entries in each bucket. */
1535    Counter bucket_size;
1536
1537    /** The current sum. */
1538    Counter sum;
1539    /** The sum of logarithm of each sample, used to compute geometric mean. */
1540    Counter logs;
1541    /** The sum of squares. */
1542    Counter squares;
1543    /** The number of samples. */
1544    Counter samples;
1545    /** Counter for each bucket. */
1546    VCounter cvec;
1547
1548  public:
1549    HistStor(Info *info)
1550        : cvec(safe_cast<const Params *>(info->storageParams)->buckets)
1551    {
1552        reset(info);
1553    }
1554
1555    void grow_up();
1556    void grow_out();
1557    void grow_convert();
1558    void add(HistStor *);
1559
1560    /**
1561     * Add a value to the distribution for the given number of times.
1562     * @param val The value to add.
1563     * @param number The number of times to add the value.
1564     */
1565    void
1566    sample(Counter val, int number)
1567    {
1568        assert(min_bucket < max_bucket);
1569        if (val < min_bucket) {
1570            if (min_bucket == 0)
1571                grow_convert();
1572
1573            while (val < min_bucket)
1574                grow_out();
1575        } else if (val >= max_bucket + bucket_size) {
1576            if (min_bucket == 0) {
1577                while (val >= max_bucket + bucket_size)
1578                    grow_up();
1579            } else {
1580                while (val >= max_bucket + bucket_size)
1581                    grow_out();
1582            }
1583        }
1584
1585        size_type index =
1586            (int64_t)std::floor((val - min_bucket) / bucket_size);
1587
1588        assert(index < size());
1589        cvec[index] += number;
1590
1591        sum += val * number;
1592        squares += val * val * number;
1593        logs += log(val) * number;
1594        samples += number;
1595    }
1596
1597    /**
1598     * Return the number of buckets in this distribution.
1599     * @return the number of buckets.
1600     */
1601    size_type size() const { return cvec.size(); }
1602
1603    /**
1604     * Returns true if any calls to sample have been made.
1605     * @return True if any values have been sampled.
1606     */
1607    bool
1608    zero() const
1609    {
1610        return samples == Counter();
1611    }
1612
1613    void
1614    prepare(Info *info, DistData &data)
1615    {
1616        const Params *params = safe_cast<const Params *>(info->storageParams);
1617
1618        assert(params->type == Hist);
1619        data.type = params->type;
1620        data.min = min_bucket;
1621        data.max = max_bucket + bucket_size - 1;
1622        data.bucket_size = bucket_size;
1623
1624        data.min_val = min_bucket;
1625        data.max_val = max_bucket;
1626
1627        int buckets = params->buckets;
1628        data.cvec.resize(buckets);
1629        for (off_type i = 0; i < buckets; ++i)
1630            data.cvec[i] = cvec[i];
1631
1632        data.sum = sum;
1633        data.logs = logs;
1634        data.squares = squares;
1635        data.samples = samples;
1636    }
1637
1638    /**
1639     * Reset stat value to default
1640     */
1641    void
1642    reset(Info *info)
1643    {
1644        const Params *params = safe_cast<const Params *>(info->storageParams);
1645        min_bucket = 0;
1646        max_bucket = params->buckets - 1;
1647        bucket_size = 1;
1648
1649        size_type size = cvec.size();
1650        for (off_type i = 0; i < size; ++i)
1651            cvec[i] = Counter();
1652
1653        sum = Counter();
1654        squares = Counter();
1655        samples = Counter();
1656        logs = Counter();
1657    }
1658};
1659
1660/**
1661 * Templatized storage and interface for a distribution that calculates mean
1662 * and variance.
1663 */
1664class SampleStor
1665{
1666  public:
1667    struct Params : public DistParams
1668    {
1669        Params() : DistParams(Deviation) {}
1670    };
1671
1672  private:
1673    /** The current sum. */
1674    Counter sum;
1675    /** The sum of squares. */
1676    Counter squares;
1677    /** The number of samples. */
1678    Counter samples;
1679
1680  public:
1681    /**
1682     * Create and initialize this storage.
1683     */
1684    SampleStor(Info *info)
1685        : sum(Counter()), squares(Counter()), samples(Counter())
1686    { }
1687
1688    /**
1689     * Add a value the given number of times to this running average.
1690     * Update the running sum and sum of squares, increment the number of
1691     * values seen by the given number.
1692     * @param val The value to add.
1693     * @param number The number of times to add the value.
1694     */
1695    void
1696    sample(Counter val, int number)
1697    {
1698        Counter value = val * number;
1699        sum += value;
1700        squares += value * value;
1701        samples += number;
1702    }
1703
1704    /**
1705     * Return the number of entries in this stat, 1
1706     * @return 1.
1707     */
1708    size_type size() const { return 1; }
1709
1710    /**
1711     * Return true if no samples have been added.
1712     * @return True if no samples have been added.
1713     */
1714    bool zero() const { return samples == Counter(); }
1715
1716    void
1717    prepare(Info *info, DistData &data)
1718    {
1719        const Params *params = safe_cast<const Params *>(info->storageParams);
1720
1721        assert(params->type == Deviation);
1722        data.type = params->type;
1723        data.sum = sum;
1724        data.squares = squares;
1725        data.samples = samples;
1726    }
1727
1728    /**
1729     * Reset stat value to default
1730     */
1731    void
1732    reset(Info *info)
1733    {
1734        sum = Counter();
1735        squares = Counter();
1736        samples = Counter();
1737    }
1738};
1739
1740/**
1741 * Templatized storage for distribution that calculates per tick mean and
1742 * variance.
1743 */
1744class AvgSampleStor
1745{
1746  public:
1747    struct Params : public DistParams
1748    {
1749        Params() : DistParams(Deviation) {}
1750    };
1751
1752  private:
1753    /** Current total. */
1754    Counter sum;
1755    /** Current sum of squares. */
1756    Counter squares;
1757
1758  public:
1759    /**
1760     * Create and initialize this storage.
1761     */
1762    AvgSampleStor(Info *info)
1763        : sum(Counter()), squares(Counter())
1764    {}
1765
1766    /**
1767     * Add a value to the distribution for the given number of times.
1768     * Update the running sum and sum of squares.
1769     * @param val The value to add.
1770     * @param number The number of times to add the value.
1771     */
1772    void
1773    sample(Counter val, int number)
1774    {
1775        Counter value = val * number;
1776        sum += value;
1777        squares += value * value;
1778    }
1779
1780    /**
1781     * Return the number of entries, in this case 1.
1782     * @return 1.
1783     */
1784    size_type size() const { return 1; }
1785
1786    /**
1787     * Return true if no samples have been added.
1788     * @return True if the sum is zero.
1789     */
1790    bool zero() const { return sum == Counter(); }
1791
1792    void
1793    prepare(Info *info, DistData &data)
1794    {
1795        const Params *params = safe_cast<const Params *>(info->storageParams);
1796
1797        assert(params->type == Deviation);
1798        data.type = params->type;
1799        data.sum = sum;
1800        data.squares = squares;
1801        data.samples = curTick();
1802    }
1803
1804    /**
1805     * Reset stat value to default
1806     */
1807    void
1808    reset(Info *info)
1809    {
1810        sum = Counter();
1811        squares = Counter();
1812    }
1813};
1814
1815/**
1816 * Implementation of a distribution stat. The type of distribution is
1817 * determined by the Storage template. @sa ScalarBase
1818 */
1819template <class Derived, class Stor>
1820class DistBase : public DataWrap<Derived, DistInfoProxy>
1821{
1822  public:
1823    typedef DistInfoProxy<Derived> Info;
1824    typedef Stor Storage;
1825    typedef typename Stor::Params Params;
1826
1827  protected:
1828    /** The storage for this stat. */
1829    char storage[sizeof(Storage)] __attribute__ ((aligned (8)));
1830
1831  protected:
1832    /**
1833     * Retrieve the storage.
1834     * @return The storage object for this stat.
1835     */
1836    Storage *
1837    data()
1838    {
1839        return reinterpret_cast<Storage *>(storage);
1840    }
1841
1842    /**
1843     * Retrieve a const pointer to the storage.
1844     * @return A const pointer to the storage object for this stat.
1845     */
1846    const Storage *
1847    data() const
1848    {
1849        return reinterpret_cast<const Storage *>(storage);
1850    }
1851
1852    void
1853    doInit()
1854    {
1855        new (storage) Storage(this->info());
1856        this->setInit();
1857    }
1858
1859  public:
1860    DistBase() { }
1861
1862    /**
1863     * Add a value to the distribtion n times. Calls sample on the storage
1864     * class.
1865     * @param v The value to add.
1866     * @param n The number of times to add it, defaults to 1.
1867     */
1868    template <typename U>
1869    void sample(const U &v, int n = 1) { data()->sample(v, n); }
1870
1871    /**
1872     * Return the number of entries in this stat.
1873     * @return The number of entries.
1874     */
1875    size_type size() const { return data()->size(); }
1876    /**
1877     * Return true if no samples have been added.
1878     * @return True if there haven't been any samples.
1879     */
1880    bool zero() const { return data()->zero(); }
1881
1882    void
1883    prepare()
1884    {
1885        Info *info = this->info();
1886        data()->prepare(info, info->data);
1887    }
1888
1889    /**
1890     * Reset stat value to default
1891     */
1892    void
1893    reset()
1894    {
1895        data()->reset(this->info());
1896    }
1897
1898    /**
1899     *  Add the argument distribution to the this distribution.
1900     */
1901    void add(DistBase &d) { data()->add(d.data()); }
1902
1903};
1904
1905template <class Stat>
1906class DistProxy;
1907
1908template <class Derived, class Stor>
1909class VectorDistBase : public DataWrapVec<Derived, VectorDistInfoProxy>
1910{
1911  public:
1912    typedef VectorDistInfoProxy<Derived> Info;
1913    typedef Stor Storage;
1914    typedef typename Stor::Params Params;
1915    typedef DistProxy<Derived> Proxy;
1916    friend class DistProxy<Derived>;
1917    friend class DataWrapVec<Derived, VectorDistInfoProxy>;
1918
1919  protected:
1920    Storage *storage;
1921    size_type _size;
1922
1923  protected:
1924    Storage *
1925    data(off_type index)
1926    {
1927        return &storage[index];
1928    }
1929
1930    const Storage *
1931    data(off_type index) const
1932    {
1933        return &storage[index];
1934    }
1935
1936    void
1937    doInit(size_type s)
1938    {
1939        assert(s > 0 && "size must be positive!");
1940        assert(!storage && "already initialized");
1941        _size = s;
1942
1943        char *ptr = new char[_size * sizeof(Storage)];
1944        storage = reinterpret_cast<Storage *>(ptr);
1945
1946        Info *info = this->info();
1947        for (off_type i = 0; i < _size; ++i)
1948            new (&storage[i]) Storage(info);
1949
1950        this->setInit();
1951    }
1952
1953  public:
1954    VectorDistBase()
1955        : storage(NULL)
1956    {}
1957
1958    ~VectorDistBase()
1959    {
1960        if (!storage)
1961            return ;
1962
1963        for (off_type i = 0; i < _size; ++i)
1964            data(i)->~Storage();
1965        delete [] reinterpret_cast<char *>(storage);
1966    }
1967
1968    Proxy operator[](off_type index)
1969    {
1970        assert(index >= 0 && index < size());
1971        return Proxy(this->self(), index);
1972    }
1973
1974    size_type
1975    size() const
1976    {
1977        return _size;
1978    }
1979
1980    bool
1981    zero() const
1982    {
1983        for (off_type i = 0; i < size(); ++i)
1984            if (!data(i)->zero())
1985                return false;
1986        return true;
1987    }
1988
1989    void
1990    prepare()
1991    {
1992        Info *info = this->info();
1993        size_type size = this->size();
1994        info->data.resize(size);
1995        for (off_type i = 0; i < size; ++i)
1996            data(i)->prepare(info, info->data[i]);
1997    }
1998
1999    bool
2000    check() const
2001    {
2002        return storage != NULL;
2003    }
2004};
2005
2006template <class Stat>
2007class DistProxy
2008{
2009  private:
2010    Stat &stat;
2011    off_type index;
2012
2013  protected:
2014    typename Stat::Storage *data() { return stat.data(index); }
2015    const typename Stat::Storage *data() const { return stat.data(index); }
2016
2017  public:
2018    DistProxy(Stat &s, off_type i)
2019        : stat(s), index(i)
2020    {}
2021
2022    DistProxy(const DistProxy &sp)
2023        : stat(sp.stat), index(sp.index)
2024    {}
2025
2026    const DistProxy &
2027    operator=(const DistProxy &sp)
2028    {
2029        stat = sp.stat;
2030        index = sp.index;
2031        return *this;
2032    }
2033
2034  public:
2035    template <typename U>
2036    void
2037    sample(const U &v, int n = 1)
2038    {
2039        data()->sample(v, n);
2040    }
2041
2042    size_type
2043    size() const
2044    {
2045        return 1;
2046    }
2047
2048    bool
2049    zero() const
2050    {
2051        return data()->zero();
2052    }
2053
2054    /**
2055     * Proxy has no state.  Nothing to reset.
2056     */
2057    void reset() { }
2058};
2059
2060//////////////////////////////////////////////////////////////////////
2061//
2062//  Formula Details
2063//
2064//////////////////////////////////////////////////////////////////////
2065
2066/**
2067 * Base class for formula statistic node. These nodes are used to build a tree
2068 * that represents the formula.
2069 */
2070class Node
2071{
2072  public:
2073    /**
2074     * Return the number of nodes in the subtree starting at this node.
2075     * @return the number of nodes in this subtree.
2076     */
2077    virtual size_type size() const = 0;
2078    /**
2079     * Return the result vector of this subtree.
2080     * @return The result vector of this subtree.
2081     */
2082    virtual const VResult &result() const = 0;
2083    /**
2084     * Return the total of the result vector.
2085     * @return The total of the result vector.
2086     */
2087    virtual Result total() const = 0;
2088
2089    /**
2090     *
2091     */
2092    virtual std::string str() const = 0;
2093
2094    virtual ~Node() {};
2095};
2096
2097/** Shared pointer to a function Node. */
2098typedef std::shared_ptr<Node> NodePtr;
2099
2100class ScalarStatNode : public Node
2101{
2102  private:
2103    const ScalarInfo *data;
2104    mutable VResult vresult;
2105
2106  public:
2107    ScalarStatNode(const ScalarInfo *d) : data(d), vresult(1) {}
2108
2109    const VResult &
2110    result() const
2111    {
2112        vresult[0] = data->result();
2113        return vresult;
2114    }
2115
2116    Result total() const { return data->result(); };
2117
2118    size_type size() const { return 1; }
2119
2120    /**
2121     *
2122     */
2123    std::string str() const { return data->name; }
2124};
2125
2126template <class Stat>
2127class ScalarProxyNode : public Node
2128{
2129  private:
2130    const ScalarProxy<Stat> proxy;
2131    mutable VResult vresult;
2132
2133  public:
2134    ScalarProxyNode(const ScalarProxy<Stat> &p)
2135        : proxy(p), vresult(1)
2136    { }
2137
2138    const VResult &
2139    result() const
2140    {
2141        vresult[0] = proxy.result();
2142        return vresult;
2143    }
2144
2145    Result
2146    total() const
2147    {
2148        return proxy.result();
2149    }
2150
2151    size_type
2152    size() const
2153    {
2154        return 1;
2155    }
2156
2157    /**
2158     *
2159     */
2160    std::string
2161    str() const
2162    {
2163        return proxy.str();
2164    }
2165};
2166
2167class VectorStatNode : public Node
2168{
2169  private:
2170    const VectorInfo *data;
2171
2172  public:
2173    VectorStatNode(const VectorInfo *d) : data(d) { }
2174    const VResult &result() const { return data->result(); }
2175    Result total() const { return data->total(); };
2176
2177    size_type size() const { return data->size(); }
2178
2179    std::string str() const { return data->name; }
2180};
2181
2182template <class T>
2183class ConstNode : public Node
2184{
2185  private:
2186    VResult vresult;
2187
2188  public:
2189    ConstNode(T s) : vresult(1, (Result)s) {}
2190    const VResult &result() const { return vresult; }
2191    Result total() const { return vresult[0]; };
2192    size_type size() const { return 1; }
2193    std::string str() const { return std::to_string(vresult[0]); }
2194};
2195
2196template <class T>
2197class ConstVectorNode : public Node
2198{
2199  private:
2200    VResult vresult;
2201
2202  public:
2203    ConstVectorNode(const T &s) : vresult(s.begin(), s.end()) {}
2204    const VResult &result() const { return vresult; }
2205
2206    Result
2207    total() const
2208    {
2209        size_type size = this->size();
2210        Result tmp = 0;
2211        for (off_type i = 0; i < size; i++)
2212            tmp += vresult[i];
2213        return tmp;
2214    }
2215
2216    size_type size() const { return vresult.size(); }
2217    std::string
2218    str() const
2219    {
2220        size_type size = this->size();
2221        std::string tmp = "(";
2222        for (off_type i = 0; i < size; i++)
2223            tmp += csprintf("%s ", std::to_string(vresult[i]));
2224        tmp += ")";
2225        return tmp;
2226    }
2227};
2228
2229template <class Op>
2230struct OpString;
2231
2232template<>
2233struct OpString<std::plus<Result> >
2234{
2235    static std::string str() { return "+"; }
2236};
2237
2238template<>
2239struct OpString<std::minus<Result> >
2240{
2241    static std::string str() { return "-"; }
2242};
2243
2244template<>
2245struct OpString<std::multiplies<Result> >
2246{
2247    static std::string str() { return "*"; }
2248};
2249
2250template<>
2251struct OpString<std::divides<Result> >
2252{
2253    static std::string str() { return "/"; }
2254};
2255
2256template<>
2257struct OpString<std::modulus<Result> >
2258{
2259    static std::string str() { return "%"; }
2260};
2261
2262template<>
2263struct OpString<std::negate<Result> >
2264{
2265    static std::string str() { return "-"; }
2266};
2267
2268template <class Op>
2269class UnaryNode : public Node
2270{
2271  public:
2272    NodePtr l;
2273    mutable VResult vresult;
2274
2275  public:
2276    UnaryNode(NodePtr &p) : l(p) {}
2277
2278    const VResult &
2279    result() const
2280    {
2281        const VResult &lvec = l->result();
2282        size_type size = lvec.size();
2283
2284        assert(size > 0);
2285
2286        vresult.resize(size);
2287        Op op;
2288        for (off_type i = 0; i < size; ++i)
2289            vresult[i] = op(lvec[i]);
2290
2291        return vresult;
2292    }
2293
2294    Result
2295    total() const
2296    {
2297        const VResult &vec = this->result();
2298        Result total = 0.0;
2299        for (off_type i = 0; i < size(); i++)
2300            total += vec[i];
2301        return total;
2302    }
2303
2304    size_type size() const { return l->size(); }
2305
2306    std::string
2307    str() const
2308    {
2309        return OpString<Op>::str() + l->str();
2310    }
2311};
2312
2313template <class Op>
2314class BinaryNode : public Node
2315{
2316  public:
2317    NodePtr l;
2318    NodePtr r;
2319    mutable VResult vresult;
2320
2321  public:
2322    BinaryNode(NodePtr &a, NodePtr &b) : l(a), r(b) {}
2323
2324    const VResult &
2325    result() const override
2326    {
2327        Op op;
2328        const VResult &lvec = l->result();
2329        const VResult &rvec = r->result();
2330
2331        assert(lvec.size() > 0 && rvec.size() > 0);
2332
2333        if (lvec.size() == 1 && rvec.size() == 1) {
2334            vresult.resize(1);
2335            vresult[0] = op(lvec[0], rvec[0]);
2336        } else if (lvec.size() == 1) {
2337            size_type size = rvec.size();
2338            vresult.resize(size);
2339            for (off_type i = 0; i < size; ++i)
2340                vresult[i] = op(lvec[0], rvec[i]);
2341        } else if (rvec.size() == 1) {
2342            size_type size = lvec.size();
2343            vresult.resize(size);
2344            for (off_type i = 0; i < size; ++i)
2345                vresult[i] = op(lvec[i], rvec[0]);
2346        } else if (rvec.size() == lvec.size()) {
2347            size_type size = rvec.size();
2348            vresult.resize(size);
2349            for (off_type i = 0; i < size; ++i)
2350                vresult[i] = op(lvec[i], rvec[i]);
2351        }
2352
2353        return vresult;
2354    }
2355
2356    Result
2357    total() const override
2358    {
2359        const VResult &vec = this->result();
2360        const VResult &lvec = l->result();
2361        const VResult &rvec = r->result();
2362        Result total = 0.0;
2363        Result lsum = 0.0;
2364        Result rsum = 0.0;
2365        Op op;
2366
2367        assert(lvec.size() > 0 && rvec.size() > 0);
2368        assert(lvec.size() == rvec.size() ||
2369               lvec.size() == 1 || rvec.size() == 1);
2370
2371        /** If vectors are the same divide their sums (x0+x1)/(y0+y1) */
2372        if (lvec.size() == rvec.size() && lvec.size() > 1) {
2373            for (off_type i = 0; i < size(); ++i) {
2374                lsum += lvec[i];
2375                rsum += rvec[i];
2376            }
2377            return op(lsum, rsum);
2378        }
2379
2380        /** Otherwise divide each item by the divisor */
2381        for (off_type i = 0; i < size(); ++i) {
2382            total += vec[i];
2383        }
2384
2385        return total;
2386    }
2387
2388    size_type
2389    size() const override
2390    {
2391        size_type ls = l->size();
2392        size_type rs = r->size();
2393        if (ls == 1) {
2394            return rs;
2395        } else if (rs == 1) {
2396            return ls;
2397        } else {
2398            assert(ls == rs && "Node vector sizes are not equal");
2399            return ls;
2400        }
2401    }
2402
2403    std::string
2404    str() const override
2405    {
2406        return csprintf("(%s %s %s)", l->str(), OpString<Op>::str(), r->str());
2407    }
2408};
2409
2410template <class Op>
2411class SumNode : public Node
2412{
2413  public:
2414    NodePtr l;
2415    mutable VResult vresult;
2416
2417  public:
2418    SumNode(NodePtr &p) : l(p), vresult(1) {}
2419
2420    const VResult &
2421    result() const
2422    {
2423        const VResult &lvec = l->result();
2424        size_type size = lvec.size();
2425        assert(size > 0);
2426
2427        vresult[0] = 0.0;
2428
2429        Op op;
2430        for (off_type i = 0; i < size; ++i)
2431            vresult[0] = op(vresult[0], lvec[i]);
2432
2433        return vresult;
2434    }
2435
2436    Result
2437    total() const
2438    {
2439        const VResult &lvec = l->result();
2440        size_type size = lvec.size();
2441        assert(size > 0);
2442
2443        Result result = 0.0;
2444
2445        Op op;
2446        for (off_type i = 0; i < size; ++i)
2447            result = op(result, lvec[i]);
2448
2449        return result;
2450    }
2451
2452    size_type size() const { return 1; }
2453
2454    std::string
2455    str() const
2456    {
2457        return csprintf("total(%s)", l->str());
2458    }
2459};
2460
2461
2462//////////////////////////////////////////////////////////////////////
2463//
2464// Visible Statistics Types
2465//
2466//////////////////////////////////////////////////////////////////////
2467/**
2468 * @defgroup VisibleStats "Statistic Types"
2469 * These are the statistics that are used in the simulator.
2470 * @{
2471 */
2472
2473/**
2474 * This is a simple scalar statistic, like a counter.
2475 * @sa Stat, ScalarBase, StatStor
2476 */
2477class Scalar : public ScalarBase<Scalar, StatStor>
2478{
2479  public:
2480    using ScalarBase<Scalar, StatStor>::operator=;
2481};
2482
2483/**
2484 * A stat that calculates the per tick average of a value.
2485 * @sa Stat, ScalarBase, AvgStor
2486 */
2487class Average : public ScalarBase<Average, AvgStor>
2488{
2489  public:
2490    using ScalarBase<Average, AvgStor>::operator=;
2491};
2492
2493class Value : public ValueBase<Value>
2494{
2495};
2496
2497/**
2498 * A vector of scalar stats.
2499 * @sa Stat, VectorBase, StatStor
2500 */
2501class Vector : public VectorBase<Vector, StatStor>
2502{
2503};
2504
2505/**
2506 * A vector of Average stats.
2507 * @sa Stat, VectorBase, AvgStor
2508 */
2509class AverageVector : public VectorBase<AverageVector, AvgStor>
2510{
2511};
2512
2513/**
2514 * A 2-Dimensional vecto of scalar stats.
2515 * @sa Stat, Vector2dBase, StatStor
2516 */
2517class Vector2d : public Vector2dBase<Vector2d, StatStor>
2518{
2519};
2520
2521/**
2522 * A simple distribution stat.
2523 * @sa Stat, DistBase, DistStor
2524 */
2525class Distribution : public DistBase<Distribution, DistStor>
2526{
2527  public:
2528    /**
2529     * Set the parameters of this distribution. @sa DistStor::Params
2530     * @param min The minimum value of the distribution.
2531     * @param max The maximum value of the distribution.
2532     * @param bkt The number of values in each bucket.
2533     * @return A reference to this distribution.
2534     */
2535    Distribution &
2536    init(Counter min, Counter max, Counter bkt)
2537    {
2538        DistStor::Params *params = new DistStor::Params;
2539        params->min = min;
2540        params->max = max;
2541        params->bucket_size = bkt;
2542        params->buckets = (size_type)ceil((max - min + 1.0) / bkt);
2543        this->setParams(params);
2544        this->doInit();
2545        return this->self();
2546    }
2547};
2548
2549/**
2550 * A simple histogram stat.
2551 * @sa Stat, DistBase, HistStor
2552 */
2553class Histogram : public DistBase<Histogram, HistStor>
2554{
2555  public:
2556    /**
2557     * Set the parameters of this histogram. @sa HistStor::Params
2558     * @param size The number of buckets in the histogram
2559     * @return A reference to this histogram.
2560     */
2561    Histogram &
2562    init(size_type size)
2563    {
2564        HistStor::Params *params = new HistStor::Params;
2565        params->buckets = size;
2566        this->setParams(params);
2567        this->doInit();
2568        return this->self();
2569    }
2570};
2571
2572/**
2573 * Calculates the mean and variance of all the samples.
2574 * @sa DistBase, SampleStor
2575 */
2576class StandardDeviation : public DistBase<StandardDeviation, SampleStor>
2577{
2578  public:
2579    /**
2580     * Construct and initialize this distribution.
2581     */
2582    StandardDeviation()
2583    {
2584        SampleStor::Params *params = new SampleStor::Params;
2585        this->doInit();
2586        this->setParams(params);
2587    }
2588};
2589
2590/**
2591 * Calculates the per tick mean and variance of the samples.
2592 * @sa DistBase, AvgSampleStor
2593 */
2594class AverageDeviation : public DistBase<AverageDeviation, AvgSampleStor>
2595{
2596  public:
2597    /**
2598     * Construct and initialize this distribution.
2599     */
2600    AverageDeviation()
2601    {
2602        AvgSampleStor::Params *params = new AvgSampleStor::Params;
2603        this->doInit();
2604        this->setParams(params);
2605    }
2606};
2607
2608/**
2609 * A vector of distributions.
2610 * @sa VectorDistBase, DistStor
2611 */
2612class VectorDistribution : public VectorDistBase<VectorDistribution, DistStor>
2613{
2614  public:
2615    /**
2616     * Initialize storage and parameters for this distribution.
2617     * @param size The size of the vector (the number of distributions).
2618     * @param min The minimum value of the distribution.
2619     * @param max The maximum value of the distribution.
2620     * @param bkt The number of values in each bucket.
2621     * @return A reference to this distribution.
2622     */
2623    VectorDistribution &
2624    init(size_type size, Counter min, Counter max, Counter bkt)
2625    {
2626        DistStor::Params *params = new DistStor::Params;
2627        params->min = min;
2628        params->max = max;
2629        params->bucket_size = bkt;
2630        params->buckets = (size_type)ceil((max - min + 1.0) / bkt);
2631        this->setParams(params);
2632        this->doInit(size);
2633        return this->self();
2634    }
2635};
2636
2637/**
2638 * This is a vector of StandardDeviation stats.
2639 * @sa VectorDistBase, SampleStor
2640 */
2641class VectorStandardDeviation
2642    : public VectorDistBase<VectorStandardDeviation, SampleStor>
2643{
2644  public:
2645    /**
2646     * Initialize storage for this distribution.
2647     * @param size The size of the vector.
2648     * @return A reference to this distribution.
2649     */
2650    VectorStandardDeviation &
2651    init(size_type size)
2652    {
2653        SampleStor::Params *params = new SampleStor::Params;
2654        this->doInit(size);
2655        this->setParams(params);
2656        return this->self();
2657    }
2658};
2659
2660/**
2661 * This is a vector of AverageDeviation stats.
2662 * @sa VectorDistBase, AvgSampleStor
2663 */
2664class VectorAverageDeviation
2665    : public VectorDistBase<VectorAverageDeviation, AvgSampleStor>
2666{
2667  public:
2668    /**
2669     * Initialize storage for this distribution.
2670     * @param size The size of the vector.
2671     * @return A reference to this distribution.
2672     */
2673    VectorAverageDeviation &
2674    init(size_type size)
2675    {
2676        AvgSampleStor::Params *params = new AvgSampleStor::Params;
2677        this->doInit(size);
2678        this->setParams(params);
2679        return this->self();
2680    }
2681};
2682
2683template <class Stat>
2684class FormulaInfoProxy : public InfoProxy<Stat, FormulaInfo>
2685{
2686  protected:
2687    mutable VResult vec;
2688    mutable VCounter cvec;
2689
2690  public:
2691    FormulaInfoProxy(Stat &stat) : InfoProxy<Stat, FormulaInfo>(stat) {}
2692
2693    size_type size() const { return this->s.size(); }
2694
2695    const VResult &
2696    result() const
2697    {
2698        this->s.result(vec);
2699        return vec;
2700    }
2701    Result total() const { return this->s.total(); }
2702    VCounter &value() const { return cvec; }
2703
2704    std::string str() const { return this->s.str(); }
2705};
2706
2707template <class Stat>
2708class SparseHistInfoProxy : public InfoProxy<Stat, SparseHistInfo>
2709{
2710  public:
2711    SparseHistInfoProxy(Stat &stat) : InfoProxy<Stat, SparseHistInfo>(stat) {}
2712};
2713
2714/**
2715 * Implementation of a sparse histogram stat. The storage class is
2716 * determined by the Storage template.
2717 */
2718template <class Derived, class Stor>
2719class SparseHistBase : public DataWrap<Derived, SparseHistInfoProxy>
2720{
2721  public:
2722    typedef SparseHistInfoProxy<Derived> Info;
2723    typedef Stor Storage;
2724    typedef typename Stor::Params Params;
2725
2726  protected:
2727    /** The storage for this stat. */
2728    char storage[sizeof(Storage)];
2729
2730  protected:
2731    /**
2732     * Retrieve the storage.
2733     * @return The storage object for this stat.
2734     */
2735    Storage *
2736    data()
2737    {
2738        return reinterpret_cast<Storage *>(storage);
2739    }
2740
2741    /**
2742     * Retrieve a const pointer to the storage.
2743     * @return A const pointer to the storage object for this stat.
2744     */
2745    const Storage *
2746    data() const
2747    {
2748        return reinterpret_cast<const Storage *>(storage);
2749    }
2750
2751    void
2752    doInit()
2753    {
2754        new (storage) Storage(this->info());
2755        this->setInit();
2756    }
2757
2758  public:
2759    SparseHistBase() { }
2760
2761    /**
2762     * Add a value to the distribtion n times. Calls sample on the storage
2763     * class.
2764     * @param v The value to add.
2765     * @param n The number of times to add it, defaults to 1.
2766     */
2767    template <typename U>
2768    void sample(const U &v, int n = 1) { data()->sample(v, n); }
2769
2770    /**
2771     * Return the number of entries in this stat.
2772     * @return The number of entries.
2773     */
2774    size_type size() const { return data()->size(); }
2775    /**
2776     * Return true if no samples have been added.
2777     * @return True if there haven't been any samples.
2778     */
2779    bool zero() const { return data()->zero(); }
2780
2781    void
2782    prepare()
2783    {
2784        Info *info = this->info();
2785        data()->prepare(info, info->data);
2786    }
2787
2788    /**
2789     * Reset stat value to default
2790     */
2791    void
2792    reset()
2793    {
2794        data()->reset(this->info());
2795    }
2796};
2797
2798/**
2799 * Templatized storage and interface for a sparse histogram stat.
2800 */
2801class SparseHistStor
2802{
2803  public:
2804    /** The parameters for a sparse histogram stat. */
2805    struct Params : public DistParams
2806    {
2807        Params() : DistParams(Hist) {}
2808    };
2809
2810  private:
2811    /** Counter for number of samples */
2812    Counter samples;
2813    /** Counter for each bucket. */
2814    MCounter cmap;
2815
2816  public:
2817    SparseHistStor(Info *info)
2818    {
2819        reset(info);
2820    }
2821
2822    /**
2823     * Add a value to the distribution for the given number of times.
2824     * @param val The value to add.
2825     * @param number The number of times to add the value.
2826     */
2827    void
2828    sample(Counter val, int number)
2829    {
2830        cmap[val] += number;
2831        samples += number;
2832    }
2833
2834    /**
2835     * Return the number of buckets in this distribution.
2836     * @return the number of buckets.
2837     */
2838    size_type size() const { return cmap.size(); }
2839
2840    /**
2841     * Returns true if any calls to sample have been made.
2842     * @return True if any values have been sampled.
2843     */
2844    bool
2845    zero() const
2846    {
2847        return samples == Counter();
2848    }
2849
2850    void
2851    prepare(Info *info, SparseHistData &data)
2852    {
2853        MCounter::iterator it;
2854        data.cmap.clear();
2855        for (it = cmap.begin(); it != cmap.end(); it++) {
2856            data.cmap[(*it).first] = (*it).second;
2857        }
2858
2859        data.samples = samples;
2860    }
2861
2862    /**
2863     * Reset stat value to default
2864     */
2865    void
2866    reset(Info *info)
2867    {
2868        cmap.clear();
2869        samples = 0;
2870    }
2871};
2872
2873class SparseHistogram : public SparseHistBase<SparseHistogram, SparseHistStor>
2874{
2875  public:
2876    /**
2877     * Set the parameters of this histogram. @sa HistStor::Params
2878     * @param size The number of buckets in the histogram
2879     * @return A reference to this histogram.
2880     */
2881    SparseHistogram &
2882    init(size_type size)
2883    {
2884        SparseHistStor::Params *params = new SparseHistStor::Params;
2885        this->setParams(params);
2886        this->doInit();
2887        return this->self();
2888    }
2889};
2890
2891class Temp;
2892/**
2893 * A formula for statistics that is calculated when printed. A formula is
2894 * stored as a tree of Nodes that represent the equation to calculate.
2895 * @sa Stat, ScalarStat, VectorStat, Node, Temp
2896 */
2897class Formula : public DataWrapVec<Formula, FormulaInfoProxy>
2898{
2899  protected:
2900    /** The root of the tree which represents the Formula */
2901    NodePtr root;
2902    friend class Temp;
2903
2904  public:
2905    /**
2906     * Create and initialize thie formula, and register it with the database.
2907     */
2908    Formula();
2909
2910    /**
2911     * Create a formula with the given root node, register it with the
2912     * database.
2913     * @param r The root of the expression tree.
2914     */
2915    Formula(Temp r);
2916
2917    /**
2918     * Set an unitialized Formula to the given root.
2919     * @param r The root of the expression tree.
2920     * @return a reference to this formula.
2921     */
2922    const Formula &operator=(Temp r);
2923
2924    /**
2925     * Add the given tree to the existing one.
2926     * @param r The root of the expression tree.
2927     * @return a reference to this formula.
2928     */
2929    const Formula &operator+=(Temp r);
2930
2931    /**
2932     * Divide the existing tree by the given one.
2933     * @param r The root of the expression tree.
2934     * @return a reference to this formula.
2935     */
2936    const Formula &operator/=(Temp r);
2937
2938    /**
2939     * Return the result of the Fomula in a vector.  If there were no Vector
2940     * components to the Formula, then the vector is size 1.  If there were,
2941     * like x/y with x being a vector of size 3, then the result returned will
2942     * be x[0]/y, x[1]/y, x[2]/y, respectively.
2943     * @return The result vector.
2944     */
2945    void result(VResult &vec) const;
2946
2947    /**
2948     * Return the total Formula result.  If there is a Vector
2949     * component to this Formula, then this is the result of the
2950     * Formula if the formula is applied after summing all the
2951     * components of the Vector.  For example, if Formula is x/y where
2952     * x is size 3, then total() will return (x[1]+x[2]+x[3])/y.  If
2953     * there is no Vector component, total() returns the same value as
2954     * the first entry in the VResult val() returns.
2955     * @return The total of the result vector.
2956     */
2957    Result total() const;
2958
2959    /**
2960     * Return the number of elements in the tree.
2961     */
2962    size_type size() const;
2963
2964    void prepare() { }
2965
2966    /**
2967     * Formulas don't need to be reset
2968     */
2969    void reset();
2970
2971    /**
2972     *
2973     */
2974    bool zero() const;
2975
2976    std::string str() const;
2977};
2978
2979class FormulaNode : public Node
2980{
2981  private:
2982    const Formula &formula;
2983    mutable VResult vec;
2984
2985  public:
2986    FormulaNode(const Formula &f) : formula(f) {}
2987
2988    size_type size() const { return formula.size(); }
2989    const VResult &result() const { formula.result(vec); return vec; }
2990    Result total() const { return formula.total(); }
2991
2992    std::string str() const { return formula.str(); }
2993};
2994
2995/**
2996 * Helper class to construct formula node trees.
2997 */
2998class Temp
2999{
3000  protected:
3001    /**
3002     * Pointer to a Node object.
3003     */
3004    NodePtr node;
3005
3006  public:
3007    /**
3008     * Copy the given pointer to this class.
3009     * @param n A pointer to a Node object to copy.
3010     */
3011    Temp(const NodePtr &n) : node(n) { }
3012
3013    Temp(NodePtr &&n) : node(std::move(n)) { }
3014
3015    /**
3016     * Return the node pointer.
3017     * @return the node pointer.
3018     */
3019    operator NodePtr&() { return node; }
3020
3021    /**
3022     * Makde gcc < 4.6.3 happy and explicitly get the underlying node.
3023     */
3024    NodePtr getNodePtr() const { return node; }
3025
3026  public:
3027    /**
3028     * Create a new ScalarStatNode.
3029     * @param s The ScalarStat to place in a node.
3030     */
3031    Temp(const Scalar &s)
3032        : node(new ScalarStatNode(s.info()))
3033    { }
3034
3035    /**
3036     * Create a new ScalarStatNode.
3037     * @param s The ScalarStat to place in a node.
3038     */
3039    Temp(const Value &s)
3040        : node(new ScalarStatNode(s.info()))
3041    { }
3042
3043    /**
3044     * Create a new ScalarStatNode.
3045     * @param s The ScalarStat to place in a node.
3046     */
3047    Temp(const Average &s)
3048        : node(new ScalarStatNode(s.info()))
3049    { }
3050
3051    /**
3052     * Create a new VectorStatNode.
3053     * @param s The VectorStat to place in a node.
3054     */
3055    Temp(const Vector &s)
3056        : node(new VectorStatNode(s.info()))
3057    { }
3058
3059    Temp(const AverageVector &s)
3060        : node(new VectorStatNode(s.info()))
3061    { }
3062
3063    /**
3064     *
3065     */
3066    Temp(const Formula &f)
3067        : node(new FormulaNode(f))
3068    { }
3069
3070    /**
3071     * Create a new ScalarProxyNode.
3072     * @param p The ScalarProxy to place in a node.
3073     */
3074    template <class Stat>
3075    Temp(const ScalarProxy<Stat> &p)
3076        : node(new ScalarProxyNode<Stat>(p))
3077    { }
3078
3079    /**
3080     * Create a ConstNode
3081     * @param value The value of the const node.
3082     */
3083    Temp(signed char value)
3084        : node(new ConstNode<signed char>(value))
3085    { }
3086
3087    /**
3088     * Create a ConstNode
3089     * @param value The value of the const node.
3090     */
3091    Temp(unsigned char value)
3092        : node(new ConstNode<unsigned char>(value))
3093    { }
3094
3095    /**
3096     * Create a ConstNode
3097     * @param value The value of the const node.
3098     */
3099    Temp(signed short value)
3100        : node(new ConstNode<signed short>(value))
3101    { }
3102
3103    /**
3104     * Create a ConstNode
3105     * @param value The value of the const node.
3106     */
3107    Temp(unsigned short value)
3108        : node(new ConstNode<unsigned short>(value))
3109    { }
3110
3111    /**
3112     * Create a ConstNode
3113     * @param value The value of the const node.
3114     */
3115    Temp(signed int value)
3116        : node(new ConstNode<signed int>(value))
3117    { }
3118
3119    /**
3120     * Create a ConstNode
3121     * @param value The value of the const node.
3122     */
3123    Temp(unsigned int value)
3124        : node(new ConstNode<unsigned int>(value))
3125    { }
3126
3127    /**
3128     * Create a ConstNode
3129     * @param value The value of the const node.
3130     */
3131    Temp(signed long value)
3132        : node(new ConstNode<signed long>(value))
3133    { }
3134
3135    /**
3136     * Create a ConstNode
3137     * @param value The value of the const node.
3138     */
3139    Temp(unsigned long value)
3140        : node(new ConstNode<unsigned long>(value))
3141    { }
3142
3143    /**
3144     * Create a ConstNode
3145     * @param value The value of the const node.
3146     */
3147    Temp(signed long long value)
3148        : node(new ConstNode<signed long long>(value))
3149    { }
3150
3151    /**
3152     * Create a ConstNode
3153     * @param value The value of the const node.
3154     */
3155    Temp(unsigned long long value)
3156        : node(new ConstNode<unsigned long long>(value))
3157    { }
3158
3159    /**
3160     * Create a ConstNode
3161     * @param value The value of the const node.
3162     */
3163    Temp(float value)
3164        : node(new ConstNode<float>(value))
3165    { }
3166
3167    /**
3168     * Create a ConstNode
3169     * @param value The value of the const node.
3170     */
3171    Temp(double value)
3172        : node(new ConstNode<double>(value))
3173    { }
3174};
3175
3176
3177/**
3178 * @}
3179 */
3180
3181inline Temp
3182operator+(Temp l, Temp r)
3183{
3184    return Temp(std::make_shared<BinaryNode<std::plus<Result> > >(l, r));
3185}
3186
3187inline Temp
3188operator-(Temp l, Temp r)
3189{
3190    return Temp(std::make_shared<BinaryNode<std::minus<Result> > >(l, r));
3191}
3192
3193inline Temp
3194operator*(Temp l, Temp r)
3195{
3196    return Temp(std::make_shared<BinaryNode<std::multiplies<Result> > >(l, r));
3197}
3198
3199inline Temp
3200operator/(Temp l, Temp r)
3201{
3202    return Temp(std::make_shared<BinaryNode<std::divides<Result> > >(l, r));
3203}
3204
3205inline Temp
3206operator-(Temp l)
3207{
3208    return Temp(std::make_shared<UnaryNode<std::negate<Result> > >(l));
3209}
3210
3211template <typename T>
3212inline Temp
3213constant(T val)
3214{
3215    return Temp(std::make_shared<ConstNode<T> >(val));
3216}
3217
3218template <typename T>
3219inline Temp
3220constantVector(T val)
3221{
3222    return Temp(std::make_shared<ConstVectorNode<T> >(val));
3223}
3224
3225inline Temp
3226sum(Temp val)
3227{
3228    return Temp(std::make_shared<SumNode<std::plus<Result> > >(val));
3229}
3230
3231/** Dump all statistics data to the registered outputs */
3232void dump();
3233void reset();
3234void enable();
3235bool enabled();
3236
3237/**
3238 * Register reset and dump handlers.  These are the functions which
3239 * will actually perform the whole statistics reset/dump actions
3240 * including processing the reset/dump callbacks
3241 */
3242typedef void (*Handler)();
3243
3244void registerHandlers(Handler reset_handler, Handler dump_handler);
3245
3246/**
3247 * Register a callback that should be called whenever statistics are
3248 * reset
3249 */
3250void registerResetCallback(Callback *cb);
3251
3252/**
3253 * Register a callback that should be called whenever statistics are
3254 * about to be dumped
3255 */
3256void registerDumpCallback(Callback *cb);
3257
3258/**
3259 * Process all the callbacks in the reset callbacks queue
3260 */
3261void processResetQueue();
3262
3263/**
3264 * Process all the callbacks in the dump callbacks queue
3265 */
3266void processDumpQueue();
3267
3268std::list<Info *> &statsList();
3269
3270typedef std::map<const void *, Info *> MapType;
3271MapType &statsMap();
3272
3273typedef std::map<std::string, Info *> NameMapType;
3274NameMapType &nameMap();
3275
3276bool validateStatName(const std::string &name);
3277
3278} // namespace Stats
3279
3280void debugDumpStats();
3281
3282#endif // __BASE_STATISTICS_HH__
3283