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