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