statistics.hh revision 12517:77e8688fc670
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
2095/** Shared pointer to a function Node. */
2096typedef std::shared_ptr<Node> NodePtr;
2097
2098class ScalarStatNode : public Node
2099{
2100  private:
2101    const ScalarInfo *data;
2102    mutable VResult vresult;
2103
2104  public:
2105    ScalarStatNode(const ScalarInfo *d) : data(d), vresult(1) {}
2106
2107    const VResult &
2108    result() const
2109    {
2110        vresult[0] = data->result();
2111        return vresult;
2112    }
2113
2114    Result total() const { return data->result(); };
2115
2116    size_type size() const { return 1; }
2117
2118    /**
2119     *
2120     */
2121    std::string str() const { return data->name; }
2122};
2123
2124template <class Stat>
2125class ScalarProxyNode : public Node
2126{
2127  private:
2128    const ScalarProxy<Stat> proxy;
2129    mutable VResult vresult;
2130
2131  public:
2132    ScalarProxyNode(const ScalarProxy<Stat> &p)
2133        : proxy(p), vresult(1)
2134    { }
2135
2136    const VResult &
2137    result() const
2138    {
2139        vresult[0] = proxy.result();
2140        return vresult;
2141    }
2142
2143    Result
2144    total() const
2145    {
2146        return proxy.result();
2147    }
2148
2149    size_type
2150    size() const
2151    {
2152        return 1;
2153    }
2154
2155    /**
2156     *
2157     */
2158    std::string
2159    str() const
2160    {
2161        return proxy.str();
2162    }
2163};
2164
2165class VectorStatNode : public Node
2166{
2167  private:
2168    const VectorInfo *data;
2169
2170  public:
2171    VectorStatNode(const VectorInfo *d) : data(d) { }
2172    const VResult &result() const { return data->result(); }
2173    Result total() const { return data->total(); };
2174
2175    size_type size() const { return data->size(); }
2176
2177    std::string str() const { return data->name; }
2178};
2179
2180template <class T>
2181class ConstNode : public Node
2182{
2183  private:
2184    VResult vresult;
2185
2186  public:
2187    ConstNode(T s) : vresult(1, (Result)s) {}
2188    const VResult &result() const { return vresult; }
2189    Result total() const { return vresult[0]; };
2190    size_type size() const { return 1; }
2191    std::string str() const { return std::to_string(vresult[0]); }
2192};
2193
2194template <class T>
2195class ConstVectorNode : public Node
2196{
2197  private:
2198    VResult vresult;
2199
2200  public:
2201    ConstVectorNode(const T &s) : vresult(s.begin(), s.end()) {}
2202    const VResult &result() const { return vresult; }
2203
2204    Result
2205    total() const
2206    {
2207        size_type size = this->size();
2208        Result tmp = 0;
2209        for (off_type i = 0; i < size; i++)
2210            tmp += vresult[i];
2211        return tmp;
2212    }
2213
2214    size_type size() const { return vresult.size(); }
2215    std::string
2216    str() const
2217    {
2218        size_type size = this->size();
2219        std::string tmp = "(";
2220        for (off_type i = 0; i < size; i++)
2221            tmp += csprintf("%s ", std::to_string(vresult[i]));
2222        tmp += ")";
2223        return tmp;
2224    }
2225};
2226
2227template <class Op>
2228struct OpString;
2229
2230template<>
2231struct OpString<std::plus<Result> >
2232{
2233    static std::string str() { return "+"; }
2234};
2235
2236template<>
2237struct OpString<std::minus<Result> >
2238{
2239    static std::string str() { return "-"; }
2240};
2241
2242template<>
2243struct OpString<std::multiplies<Result> >
2244{
2245    static std::string str() { return "*"; }
2246};
2247
2248template<>
2249struct OpString<std::divides<Result> >
2250{
2251    static std::string str() { return "/"; }
2252};
2253
2254template<>
2255struct OpString<std::modulus<Result> >
2256{
2257    static std::string str() { return "%"; }
2258};
2259
2260template<>
2261struct OpString<std::negate<Result> >
2262{
2263    static std::string str() { return "-"; }
2264};
2265
2266template <class Op>
2267class UnaryNode : public Node
2268{
2269  public:
2270    NodePtr l;
2271    mutable VResult vresult;
2272
2273  public:
2274    UnaryNode(NodePtr &p) : l(p) {}
2275
2276    const VResult &
2277    result() const
2278    {
2279        const VResult &lvec = l->result();
2280        size_type size = lvec.size();
2281
2282        assert(size > 0);
2283
2284        vresult.resize(size);
2285        Op op;
2286        for (off_type i = 0; i < size; ++i)
2287            vresult[i] = op(lvec[i]);
2288
2289        return vresult;
2290    }
2291
2292    Result
2293    total() const
2294    {
2295        const VResult &vec = this->result();
2296        Result total = 0.0;
2297        for (off_type i = 0; i < size(); i++)
2298            total += vec[i];
2299        return total;
2300    }
2301
2302    size_type size() const { return l->size(); }
2303
2304    std::string
2305    str() const
2306    {
2307        return OpString<Op>::str() + l->str();
2308    }
2309};
2310
2311template <class Op>
2312class BinaryNode : public Node
2313{
2314  public:
2315    NodePtr l;
2316    NodePtr r;
2317    mutable VResult vresult;
2318
2319  public:
2320    BinaryNode(NodePtr &a, NodePtr &b) : l(a), r(b) {}
2321
2322    const VResult &
2323    result() const
2324    {
2325        Op op;
2326        const VResult &lvec = l->result();
2327        const VResult &rvec = r->result();
2328
2329        assert(lvec.size() > 0 && rvec.size() > 0);
2330
2331        if (lvec.size() == 1 && rvec.size() == 1) {
2332            vresult.resize(1);
2333            vresult[0] = op(lvec[0], rvec[0]);
2334        } else if (lvec.size() == 1) {
2335            size_type size = rvec.size();
2336            vresult.resize(size);
2337            for (off_type i = 0; i < size; ++i)
2338                vresult[i] = op(lvec[0], rvec[i]);
2339        } else if (rvec.size() == 1) {
2340            size_type size = lvec.size();
2341            vresult.resize(size);
2342            for (off_type i = 0; i < size; ++i)
2343                vresult[i] = op(lvec[i], rvec[0]);
2344        } else if (rvec.size() == lvec.size()) {
2345            size_type size = rvec.size();
2346            vresult.resize(size);
2347            for (off_type i = 0; i < size; ++i)
2348                vresult[i] = op(lvec[i], rvec[i]);
2349        }
2350
2351        return vresult;
2352    }
2353
2354    Result
2355    total() const
2356    {
2357        const VResult &vec = this->result();
2358        const VResult &lvec = l->result();
2359        const VResult &rvec = r->result();
2360        Result total = 0.0;
2361        Result lsum = 0.0;
2362        Result rsum = 0.0;
2363        Op op;
2364
2365        assert(lvec.size() > 0 && rvec.size() > 0);
2366        assert(lvec.size() == rvec.size() ||
2367               lvec.size() == 1 || rvec.size() == 1);
2368
2369        /** If vectors are the same divide their sums (x0+x1)/(y0+y1) */
2370        if (lvec.size() == rvec.size() && lvec.size() > 1) {
2371            for (off_type i = 0; i < size(); ++i) {
2372                lsum += lvec[i];
2373                rsum += rvec[i];
2374            }
2375            return op(lsum, rsum);
2376        }
2377
2378        /** Otherwise divide each item by the divisor */
2379        for (off_type i = 0; i < size(); ++i) {
2380            total += vec[i];
2381        }
2382
2383        return total;
2384    }
2385
2386    size_type
2387    size() const
2388    {
2389        size_type ls = l->size();
2390        size_type rs = r->size();
2391        if (ls == 1) {
2392            return rs;
2393        } else if (rs == 1) {
2394            return ls;
2395        } else {
2396            assert(ls == rs && "Node vector sizes are not equal");
2397            return ls;
2398        }
2399    }
2400
2401    std::string
2402    str() const
2403    {
2404        return csprintf("(%s %s %s)", l->str(), OpString<Op>::str(), r->str());
2405    }
2406};
2407
2408template <class Op>
2409class SumNode : public Node
2410{
2411  public:
2412    NodePtr l;
2413    mutable VResult vresult;
2414
2415  public:
2416    SumNode(NodePtr &p) : l(p), vresult(1) {}
2417
2418    const VResult &
2419    result() const
2420    {
2421        const VResult &lvec = l->result();
2422        size_type size = lvec.size();
2423        assert(size > 0);
2424
2425        vresult[0] = 0.0;
2426
2427        Op op;
2428        for (off_type i = 0; i < size; ++i)
2429            vresult[0] = op(vresult[0], lvec[i]);
2430
2431        return vresult;
2432    }
2433
2434    Result
2435    total() const
2436    {
2437        const VResult &lvec = l->result();
2438        size_type size = lvec.size();
2439        assert(size > 0);
2440
2441        Result result = 0.0;
2442
2443        Op op;
2444        for (off_type i = 0; i < size; ++i)
2445            result = op(result, lvec[i]);
2446
2447        return result;
2448    }
2449
2450    size_type size() const { return 1; }
2451
2452    std::string
2453    str() const
2454    {
2455        return csprintf("total(%s)", l->str());
2456    }
2457};
2458
2459
2460//////////////////////////////////////////////////////////////////////
2461//
2462// Visible Statistics Types
2463//
2464//////////////////////////////////////////////////////////////////////
2465/**
2466 * @defgroup VisibleStats "Statistic Types"
2467 * These are the statistics that are used in the simulator.
2468 * @{
2469 */
2470
2471/**
2472 * This is a simple scalar statistic, like a counter.
2473 * @sa Stat, ScalarBase, StatStor
2474 */
2475class Scalar : public ScalarBase<Scalar, StatStor>
2476{
2477  public:
2478    using ScalarBase<Scalar, StatStor>::operator=;
2479};
2480
2481/**
2482 * A stat that calculates the per tick average of a value.
2483 * @sa Stat, ScalarBase, AvgStor
2484 */
2485class Average : public ScalarBase<Average, AvgStor>
2486{
2487  public:
2488    using ScalarBase<Average, AvgStor>::operator=;
2489};
2490
2491class Value : public ValueBase<Value>
2492{
2493};
2494
2495/**
2496 * A vector of scalar stats.
2497 * @sa Stat, VectorBase, StatStor
2498 */
2499class Vector : public VectorBase<Vector, StatStor>
2500{
2501};
2502
2503/**
2504 * A vector of Average stats.
2505 * @sa Stat, VectorBase, AvgStor
2506 */
2507class AverageVector : public VectorBase<AverageVector, AvgStor>
2508{
2509};
2510
2511/**
2512 * A 2-Dimensional vecto of scalar stats.
2513 * @sa Stat, Vector2dBase, StatStor
2514 */
2515class Vector2d : public Vector2dBase<Vector2d, StatStor>
2516{
2517};
2518
2519/**
2520 * A simple distribution stat.
2521 * @sa Stat, DistBase, DistStor
2522 */
2523class Distribution : public DistBase<Distribution, DistStor>
2524{
2525  public:
2526    /**
2527     * Set the parameters of this distribution. @sa DistStor::Params
2528     * @param min The minimum value of the distribution.
2529     * @param max The maximum value of the distribution.
2530     * @param bkt The number of values in each bucket.
2531     * @return A reference to this distribution.
2532     */
2533    Distribution &
2534    init(Counter min, Counter max, Counter bkt)
2535    {
2536        DistStor::Params *params = new DistStor::Params;
2537        params->min = min;
2538        params->max = max;
2539        params->bucket_size = bkt;
2540        params->buckets = (size_type)ceil((max - min + 1.0) / bkt);
2541        this->setParams(params);
2542        this->doInit();
2543        return this->self();
2544    }
2545};
2546
2547/**
2548 * A simple histogram stat.
2549 * @sa Stat, DistBase, HistStor
2550 */
2551class Histogram : public DistBase<Histogram, HistStor>
2552{
2553  public:
2554    /**
2555     * Set the parameters of this histogram. @sa HistStor::Params
2556     * @param size The number of buckets in the histogram
2557     * @return A reference to this histogram.
2558     */
2559    Histogram &
2560    init(size_type size)
2561    {
2562        HistStor::Params *params = new HistStor::Params;
2563        params->buckets = size;
2564        this->setParams(params);
2565        this->doInit();
2566        return this->self();
2567    }
2568};
2569
2570/**
2571 * Calculates the mean and variance of all the samples.
2572 * @sa DistBase, SampleStor
2573 */
2574class StandardDeviation : public DistBase<StandardDeviation, SampleStor>
2575{
2576  public:
2577    /**
2578     * Construct and initialize this distribution.
2579     */
2580    StandardDeviation()
2581    {
2582        SampleStor::Params *params = new SampleStor::Params;
2583        this->doInit();
2584        this->setParams(params);
2585    }
2586};
2587
2588/**
2589 * Calculates the per tick mean and variance of the samples.
2590 * @sa DistBase, AvgSampleStor
2591 */
2592class AverageDeviation : public DistBase<AverageDeviation, AvgSampleStor>
2593{
2594  public:
2595    /**
2596     * Construct and initialize this distribution.
2597     */
2598    AverageDeviation()
2599    {
2600        AvgSampleStor::Params *params = new AvgSampleStor::Params;
2601        this->doInit();
2602        this->setParams(params);
2603    }
2604};
2605
2606/**
2607 * A vector of distributions.
2608 * @sa VectorDistBase, DistStor
2609 */
2610class VectorDistribution : public VectorDistBase<VectorDistribution, DistStor>
2611{
2612  public:
2613    /**
2614     * Initialize storage and parameters for this distribution.
2615     * @param size The size of the vector (the number of distributions).
2616     * @param min The minimum value of the distribution.
2617     * @param max The maximum value of the distribution.
2618     * @param bkt The number of values in each bucket.
2619     * @return A reference to this distribution.
2620     */
2621    VectorDistribution &
2622    init(size_type size, Counter min, Counter max, Counter bkt)
2623    {
2624        DistStor::Params *params = new DistStor::Params;
2625        params->min = min;
2626        params->max = max;
2627        params->bucket_size = bkt;
2628        params->buckets = (size_type)ceil((max - min + 1.0) / bkt);
2629        this->setParams(params);
2630        this->doInit(size);
2631        return this->self();
2632    }
2633};
2634
2635/**
2636 * This is a vector of StandardDeviation stats.
2637 * @sa VectorDistBase, SampleStor
2638 */
2639class VectorStandardDeviation
2640    : public VectorDistBase<VectorStandardDeviation, SampleStor>
2641{
2642  public:
2643    /**
2644     * Initialize storage for this distribution.
2645     * @param size The size of the vector.
2646     * @return A reference to this distribution.
2647     */
2648    VectorStandardDeviation &
2649    init(size_type size)
2650    {
2651        SampleStor::Params *params = new SampleStor::Params;
2652        this->doInit(size);
2653        this->setParams(params);
2654        return this->self();
2655    }
2656};
2657
2658/**
2659 * This is a vector of AverageDeviation stats.
2660 * @sa VectorDistBase, AvgSampleStor
2661 */
2662class VectorAverageDeviation
2663    : public VectorDistBase<VectorAverageDeviation, AvgSampleStor>
2664{
2665  public:
2666    /**
2667     * Initialize storage for this distribution.
2668     * @param size The size of the vector.
2669     * @return A reference to this distribution.
2670     */
2671    VectorAverageDeviation &
2672    init(size_type size)
2673    {
2674        AvgSampleStor::Params *params = new AvgSampleStor::Params;
2675        this->doInit(size);
2676        this->setParams(params);
2677        return this->self();
2678    }
2679};
2680
2681template <class Stat>
2682class FormulaInfoProxy : public InfoProxy<Stat, FormulaInfo>
2683{
2684  protected:
2685    mutable VResult vec;
2686    mutable VCounter cvec;
2687
2688  public:
2689    FormulaInfoProxy(Stat &stat) : InfoProxy<Stat, FormulaInfo>(stat) {}
2690
2691    size_type size() const { return this->s.size(); }
2692
2693    const VResult &
2694    result() const
2695    {
2696        this->s.result(vec);
2697        return vec;
2698    }
2699    Result total() const { return this->s.total(); }
2700    VCounter &value() const { return cvec; }
2701
2702    std::string str() const { return this->s.str(); }
2703};
2704
2705template <class Stat>
2706class SparseHistInfoProxy : public InfoProxy<Stat, SparseHistInfo>
2707{
2708  public:
2709    SparseHistInfoProxy(Stat &stat) : InfoProxy<Stat, SparseHistInfo>(stat) {}
2710};
2711
2712/**
2713 * Implementation of a sparse histogram stat. The storage class is
2714 * determined by the Storage template.
2715 */
2716template <class Derived, class Stor>
2717class SparseHistBase : public DataWrap<Derived, SparseHistInfoProxy>
2718{
2719  public:
2720    typedef SparseHistInfoProxy<Derived> Info;
2721    typedef Stor Storage;
2722    typedef typename Stor::Params Params;
2723
2724  protected:
2725    /** The storage for this stat. */
2726    char storage[sizeof(Storage)];
2727
2728  protected:
2729    /**
2730     * Retrieve the storage.
2731     * @return The storage object for this stat.
2732     */
2733    Storage *
2734    data()
2735    {
2736        return reinterpret_cast<Storage *>(storage);
2737    }
2738
2739    /**
2740     * Retrieve a const pointer to the storage.
2741     * @return A const pointer to the storage object for this stat.
2742     */
2743    const Storage *
2744    data() const
2745    {
2746        return reinterpret_cast<const Storage *>(storage);
2747    }
2748
2749    void
2750    doInit()
2751    {
2752        new (storage) Storage(this->info());
2753        this->setInit();
2754    }
2755
2756  public:
2757    SparseHistBase() { }
2758
2759    /**
2760     * Add a value to the distribtion n times. Calls sample on the storage
2761     * class.
2762     * @param v The value to add.
2763     * @param n The number of times to add it, defaults to 1.
2764     */
2765    template <typename U>
2766    void sample(const U &v, int n = 1) { data()->sample(v, n); }
2767
2768    /**
2769     * Return the number of entries in this stat.
2770     * @return The number of entries.
2771     */
2772    size_type size() const { return data()->size(); }
2773    /**
2774     * Return true if no samples have been added.
2775     * @return True if there haven't been any samples.
2776     */
2777    bool zero() const { return data()->zero(); }
2778
2779    void
2780    prepare()
2781    {
2782        Info *info = this->info();
2783        data()->prepare(info, info->data);
2784    }
2785
2786    /**
2787     * Reset stat value to default
2788     */
2789    void
2790    reset()
2791    {
2792        data()->reset(this->info());
2793    }
2794};
2795
2796/**
2797 * Templatized storage and interface for a sparse histogram stat.
2798 */
2799class SparseHistStor
2800{
2801  public:
2802    /** The parameters for a sparse histogram stat. */
2803    struct Params : public DistParams
2804    {
2805        Params() : DistParams(Hist) {}
2806    };
2807
2808  private:
2809    /** Counter for number of samples */
2810    Counter samples;
2811    /** Counter for each bucket. */
2812    MCounter cmap;
2813
2814  public:
2815    SparseHistStor(Info *info)
2816    {
2817        reset(info);
2818    }
2819
2820    /**
2821     * Add a value to the distribution for the given number of times.
2822     * @param val The value to add.
2823     * @param number The number of times to add the value.
2824     */
2825    void
2826    sample(Counter val, int number)
2827    {
2828        cmap[val] += number;
2829        samples += number;
2830    }
2831
2832    /**
2833     * Return the number of buckets in this distribution.
2834     * @return the number of buckets.
2835     */
2836    size_type size() const { return cmap.size(); }
2837
2838    /**
2839     * Returns true if any calls to sample have been made.
2840     * @return True if any values have been sampled.
2841     */
2842    bool
2843    zero() const
2844    {
2845        return samples == Counter();
2846    }
2847
2848    void
2849    prepare(Info *info, SparseHistData &data)
2850    {
2851        MCounter::iterator it;
2852        data.cmap.clear();
2853        for (it = cmap.begin(); it != cmap.end(); it++) {
2854            data.cmap[(*it).first] = (*it).second;
2855        }
2856
2857        data.samples = samples;
2858    }
2859
2860    /**
2861     * Reset stat value to default
2862     */
2863    void
2864    reset(Info *info)
2865    {
2866        cmap.clear();
2867        samples = 0;
2868    }
2869};
2870
2871class SparseHistogram : public SparseHistBase<SparseHistogram, SparseHistStor>
2872{
2873  public:
2874    /**
2875     * Set the parameters of this histogram. @sa HistStor::Params
2876     * @param size The number of buckets in the histogram
2877     * @return A reference to this histogram.
2878     */
2879    SparseHistogram &
2880    init(size_type size)
2881    {
2882        SparseHistStor::Params *params = new SparseHistStor::Params;
2883        this->setParams(params);
2884        this->doInit();
2885        return this->self();
2886    }
2887};
2888
2889class Temp;
2890/**
2891 * A formula for statistics that is calculated when printed. A formula is
2892 * stored as a tree of Nodes that represent the equation to calculate.
2893 * @sa Stat, ScalarStat, VectorStat, Node, Temp
2894 */
2895class Formula : public DataWrapVec<Formula, FormulaInfoProxy>
2896{
2897  protected:
2898    /** The root of the tree which represents the Formula */
2899    NodePtr root;
2900    friend class Temp;
2901
2902  public:
2903    /**
2904     * Create and initialize thie formula, and register it with the database.
2905     */
2906    Formula();
2907
2908    /**
2909     * Create a formula with the given root node, register it with the
2910     * database.
2911     * @param r The root of the expression tree.
2912     */
2913    Formula(Temp r);
2914
2915    /**
2916     * Set an unitialized Formula to the given root.
2917     * @param r The root of the expression tree.
2918     * @return a reference to this formula.
2919     */
2920    const Formula &operator=(Temp r);
2921
2922    /**
2923     * Add the given tree to the existing one.
2924     * @param r The root of the expression tree.
2925     * @return a reference to this formula.
2926     */
2927    const Formula &operator+=(Temp r);
2928
2929    /**
2930     * Divide the existing tree by the given one.
2931     * @param r The root of the expression tree.
2932     * @return a reference to this formula.
2933     */
2934    const Formula &operator/=(Temp r);
2935
2936    /**
2937     * Return the result of the Fomula in a vector.  If there were no Vector
2938     * components to the Formula, then the vector is size 1.  If there were,
2939     * like x/y with x being a vector of size 3, then the result returned will
2940     * be x[0]/y, x[1]/y, x[2]/y, respectively.
2941     * @return The result vector.
2942     */
2943    void result(VResult &vec) const;
2944
2945    /**
2946     * Return the total Formula result.  If there is a Vector
2947     * component to this Formula, then this is the result of the
2948     * Formula if the formula is applied after summing all the
2949     * components of the Vector.  For example, if Formula is x/y where
2950     * x is size 3, then total() will return (x[1]+x[2]+x[3])/y.  If
2951     * there is no Vector component, total() returns the same value as
2952     * the first entry in the VResult val() returns.
2953     * @return The total of the result vector.
2954     */
2955    Result total() const;
2956
2957    /**
2958     * Return the number of elements in the tree.
2959     */
2960    size_type size() const;
2961
2962    void prepare() { }
2963
2964    /**
2965     * Formulas don't need to be reset
2966     */
2967    void reset();
2968
2969    /**
2970     *
2971     */
2972    bool zero() const;
2973
2974    std::string str() const;
2975};
2976
2977class FormulaNode : public Node
2978{
2979  private:
2980    const Formula &formula;
2981    mutable VResult vec;
2982
2983  public:
2984    FormulaNode(const Formula &f) : formula(f) {}
2985
2986    size_type size() const { return formula.size(); }
2987    const VResult &result() const { formula.result(vec); return vec; }
2988    Result total() const { return formula.total(); }
2989
2990    std::string str() const { return formula.str(); }
2991};
2992
2993/**
2994 * Helper class to construct formula node trees.
2995 */
2996class Temp
2997{
2998  protected:
2999    /**
3000     * Pointer to a Node object.
3001     */
3002    NodePtr node;
3003
3004  public:
3005    /**
3006     * Copy the given pointer to this class.
3007     * @param n A pointer to a Node object to copy.
3008     */
3009    Temp(const NodePtr &n) : node(n) { }
3010
3011    Temp(NodePtr &&n) : node(std::move(n)) { }
3012
3013    /**
3014     * Return the node pointer.
3015     * @return the node pointer.
3016     */
3017    operator NodePtr&() { return node; }
3018
3019    /**
3020     * Makde gcc < 4.6.3 happy and explicitly get the underlying node.
3021     */
3022    NodePtr getNodePtr() const { return node; }
3023
3024  public:
3025    /**
3026     * Create a new ScalarStatNode.
3027     * @param s The ScalarStat to place in a node.
3028     */
3029    Temp(const Scalar &s)
3030        : node(new ScalarStatNode(s.info()))
3031    { }
3032
3033    /**
3034     * Create a new ScalarStatNode.
3035     * @param s The ScalarStat to place in a node.
3036     */
3037    Temp(const Value &s)
3038        : node(new ScalarStatNode(s.info()))
3039    { }
3040
3041    /**
3042     * Create a new ScalarStatNode.
3043     * @param s The ScalarStat to place in a node.
3044     */
3045    Temp(const Average &s)
3046        : node(new ScalarStatNode(s.info()))
3047    { }
3048
3049    /**
3050     * Create a new VectorStatNode.
3051     * @param s The VectorStat to place in a node.
3052     */
3053    Temp(const Vector &s)
3054        : node(new VectorStatNode(s.info()))
3055    { }
3056
3057    Temp(const AverageVector &s)
3058        : node(new VectorStatNode(s.info()))
3059    { }
3060
3061    /**
3062     *
3063     */
3064    Temp(const Formula &f)
3065        : node(new FormulaNode(f))
3066    { }
3067
3068    /**
3069     * Create a new ScalarProxyNode.
3070     * @param p The ScalarProxy to place in a node.
3071     */
3072    template <class Stat>
3073    Temp(const ScalarProxy<Stat> &p)
3074        : node(new ScalarProxyNode<Stat>(p))
3075    { }
3076
3077    /**
3078     * Create a ConstNode
3079     * @param value The value of the const node.
3080     */
3081    Temp(signed char value)
3082        : node(new ConstNode<signed char>(value))
3083    { }
3084
3085    /**
3086     * Create a ConstNode
3087     * @param value The value of the const node.
3088     */
3089    Temp(unsigned char value)
3090        : node(new ConstNode<unsigned char>(value))
3091    { }
3092
3093    /**
3094     * Create a ConstNode
3095     * @param value The value of the const node.
3096     */
3097    Temp(signed short value)
3098        : node(new ConstNode<signed short>(value))
3099    { }
3100
3101    /**
3102     * Create a ConstNode
3103     * @param value The value of the const node.
3104     */
3105    Temp(unsigned short value)
3106        : node(new ConstNode<unsigned short>(value))
3107    { }
3108
3109    /**
3110     * Create a ConstNode
3111     * @param value The value of the const node.
3112     */
3113    Temp(signed int value)
3114        : node(new ConstNode<signed int>(value))
3115    { }
3116
3117    /**
3118     * Create a ConstNode
3119     * @param value The value of the const node.
3120     */
3121    Temp(unsigned int value)
3122        : node(new ConstNode<unsigned int>(value))
3123    { }
3124
3125    /**
3126     * Create a ConstNode
3127     * @param value The value of the const node.
3128     */
3129    Temp(signed long value)
3130        : node(new ConstNode<signed long>(value))
3131    { }
3132
3133    /**
3134     * Create a ConstNode
3135     * @param value The value of the const node.
3136     */
3137    Temp(unsigned long value)
3138        : node(new ConstNode<unsigned long>(value))
3139    { }
3140
3141    /**
3142     * Create a ConstNode
3143     * @param value The value of the const node.
3144     */
3145    Temp(signed long long value)
3146        : node(new ConstNode<signed long long>(value))
3147    { }
3148
3149    /**
3150     * Create a ConstNode
3151     * @param value The value of the const node.
3152     */
3153    Temp(unsigned long long value)
3154        : node(new ConstNode<unsigned long long>(value))
3155    { }
3156
3157    /**
3158     * Create a ConstNode
3159     * @param value The value of the const node.
3160     */
3161    Temp(float value)
3162        : node(new ConstNode<float>(value))
3163    { }
3164
3165    /**
3166     * Create a ConstNode
3167     * @param value The value of the const node.
3168     */
3169    Temp(double value)
3170        : node(new ConstNode<double>(value))
3171    { }
3172};
3173
3174
3175/**
3176 * @}
3177 */
3178
3179inline Temp
3180operator+(Temp l, Temp r)
3181{
3182    return Temp(std::make_shared<BinaryNode<std::plus<Result> > >(l, r));
3183}
3184
3185inline Temp
3186operator-(Temp l, Temp r)
3187{
3188    return Temp(std::make_shared<BinaryNode<std::minus<Result> > >(l, r));
3189}
3190
3191inline Temp
3192operator*(Temp l, Temp r)
3193{
3194    return Temp(std::make_shared<BinaryNode<std::multiplies<Result> > >(l, r));
3195}
3196
3197inline Temp
3198operator/(Temp l, Temp r)
3199{
3200    return Temp(std::make_shared<BinaryNode<std::divides<Result> > >(l, r));
3201}
3202
3203inline Temp
3204operator-(Temp l)
3205{
3206    return Temp(std::make_shared<UnaryNode<std::negate<Result> > >(l));
3207}
3208
3209template <typename T>
3210inline Temp
3211constant(T val)
3212{
3213    return Temp(std::make_shared<ConstNode<T> >(val));
3214}
3215
3216template <typename T>
3217inline Temp
3218constantVector(T val)
3219{
3220    return Temp(std::make_shared<ConstVectorNode<T> >(val));
3221}
3222
3223inline Temp
3224sum(Temp val)
3225{
3226    return Temp(std::make_shared<SumNode<std::plus<Result> > >(val));
3227}
3228
3229/** Dump all statistics data to the registered outputs */
3230void dump();
3231void reset();
3232void enable();
3233bool enabled();
3234
3235/**
3236 * Register reset and dump handlers.  These are the functions which
3237 * will actually perform the whole statistics reset/dump actions
3238 * including processing the reset/dump callbacks
3239 */
3240typedef void (*Handler)();
3241
3242void registerHandlers(Handler reset_handler, Handler dump_handler);
3243
3244/**
3245 * Register a callback that should be called whenever statistics are
3246 * reset
3247 */
3248void registerResetCallback(Callback *cb);
3249
3250/**
3251 * Register a callback that should be called whenever statistics are
3252 * about to be dumped
3253 */
3254void registerDumpCallback(Callback *cb);
3255
3256/**
3257 * Process all the callbacks in the reset callbacks queue
3258 */
3259void processResetQueue();
3260
3261/**
3262 * Process all the callbacks in the dump callbacks queue
3263 */
3264void processDumpQueue();
3265
3266std::list<Info *> &statsList();
3267
3268typedef std::map<const void *, Info *> MapType;
3269MapType &statsMap();
3270
3271typedef std::map<std::string, Info *> NameMapType;
3272NameMapType &nameMap();
3273
3274bool validateStatName(const std::string &name);
3275
3276} // namespace Stats
3277
3278void debugDumpStats();
3279
3280#endif // __BASE_STATISTICS_HH__
3281