Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 
      6 #ifndef BASE_STATS_COUNTERS_H__
      7 #define BASE_STATS_COUNTERS_H__
      8 
      9 #include <string>
     10 #include "base/stats_table.h"
     11 #include "base/time.h"
     12 
     13 // StatsCounters are dynamically created values which can be tracked in
     14 // the StatsTable.  They are designed to be lightweight to create and
     15 // easy to use.
     16 //
     17 // Since StatsCounters can be created dynamically by name, there is
     18 // a hash table lookup to find the counter in the table.  A StatsCounter
     19 // object can be created once and used across multiple threads safely.
     20 //
     21 // Example usage:
     22 //    {
     23 //      StatsCounter request_count("RequestCount");
     24 //      request_count.Increment();
     25 //    }
     26 //
     27 // Note that creating counters on the stack does work, however creating
     28 // the counter object requires a hash table lookup.  For inner loops, it
     29 // may be better to create the counter either as a member of another object
     30 // (or otherwise outside of the loop) for maximum performance.
     31 //
     32 // Internally, a counter represents a value in a row of a StatsTable.
     33 // The row has a 32bit value for each process/thread in the table and also
     34 // a name (stored in the table metadata).
     35 //
     36 // NOTE: In order to make stats_counters usable in lots of different code,
     37 // avoid any dependencies inside this header file.
     38 //
     39 
     40 //------------------------------------------------------------------------------
     41 // Define macros for ease of use. They also allow us to change definitions
     42 // as the implementation varies, or depending on compile options.
     43 //------------------------------------------------------------------------------
     44 // First provide generic macros, which exist in production as well as debug.
     45 #define STATS_COUNTER(name, delta) do { \
     46   static StatsCounter counter(name); \
     47   counter.Add(delta); \
     48 } while (0)
     49 
     50 #define SIMPLE_STATS_COUNTER(name) STATS_COUNTER(name, 1)
     51 
     52 #define RATE_COUNTER(name, duration) do { \
     53   static StatsRate hit_count(name); \
     54   hit_count.AddTime(duration); \
     55 } while (0)
     56 
     57 // Define Debug vs non-debug flavors of macros.
     58 #ifndef NDEBUG
     59 
     60 #define DSTATS_COUNTER(name, delta) STATS_COUNTER(name, delta)
     61 #define DSIMPLE_STATS_COUNTER(name) SIMPLE_STATS_COUNTER(name)
     62 #define DRATE_COUNTER(name, duration) RATE_COUNTER(name, duration)
     63 
     64 #else  // NDEBUG
     65 
     66 #define DSTATS_COUNTER(name, delta) do {} while (0)
     67 #define DSIMPLE_STATS_COUNTER(name) do {} while (0)
     68 #define DRATE_COUNTER(name, duration) do {} while (0)
     69 
     70 #endif  // NDEBUG
     71 
     72 //------------------------------------------------------------------------------
     73 // StatsCounter represents a counter in the StatsTable class.
     74 class StatsCounter {
     75  public:
     76   // Create a StatsCounter object.
     77   explicit StatsCounter(const std::string& name)
     78        : counter_id_(-1) {
     79     // We prepend the name with 'c:' to indicate that it is a counter.
     80     name_ = "c:";
     81     name_.append(name);
     82   };
     83 
     84   virtual ~StatsCounter() {}
     85 
     86   // Sets the counter to a specific value.
     87   void Set(int value) {
     88     int* loc = GetPtr();
     89     if (loc) *loc = value;
     90   }
     91 
     92   // Increments the counter.
     93   void Increment() {
     94     Add(1);
     95   }
     96 
     97   virtual void Add(int value) {
     98     int* loc = GetPtr();
     99     if (loc)
    100       (*loc) += value;
    101   }
    102 
    103   // Decrements the counter.
    104   void Decrement() {
    105     Add(-1);
    106   }
    107 
    108   void Subtract(int value) {
    109     Add(-value);
    110   }
    111 
    112   // Is this counter enabled?
    113   // Returns false if table is full.
    114   bool Enabled() {
    115     return GetPtr() != NULL;
    116   }
    117 
    118   int value() {
    119     int* loc = GetPtr();
    120     if (loc) return *loc;
    121     return 0;
    122   }
    123 
    124  protected:
    125   StatsCounter()
    126     : counter_id_(-1) {
    127   }
    128 
    129   // Returns the cached address of this counter location.
    130   int* GetPtr() {
    131     StatsTable* table = StatsTable::current();
    132     if (!table)
    133       return NULL;
    134 
    135     // If counter_id_ is -1, then we haven't looked it up yet.
    136     if (counter_id_ == -1) {
    137       counter_id_ = table->FindCounter(name_);
    138       if (table->GetSlot() == 0) {
    139         if (!table->RegisterThread("")) {
    140           // There is no room for this thread.  This thread
    141           // cannot use counters.
    142           counter_id_ = 0;
    143           return NULL;
    144         }
    145       }
    146     }
    147 
    148     // If counter_id_ is > 0, then we have a valid counter.
    149     if (counter_id_ > 0)
    150       return table->GetLocation(counter_id_, table->GetSlot());
    151 
    152     // counter_id_ was zero, which means the table is full.
    153     return NULL;
    154   }
    155 
    156   std::string name_;
    157   // The counter id in the table.  We initialize to -1 (an invalid value)
    158   // and then cache it once it has been looked up.  The counter_id is
    159   // valid across all threads and processes.
    160   int32 counter_id_;
    161 };
    162 
    163 
    164 // A StatsCounterTimer is a StatsCounter which keeps a timer during
    165 // the scope of the StatsCounterTimer.  On destruction, it will record
    166 // its time measurement.
    167 class StatsCounterTimer : protected StatsCounter {
    168  public:
    169   // Constructs and starts the timer.
    170   explicit StatsCounterTimer(const std::string& name) {
    171     // we prepend the name with 't:' to indicate that it is a timer.
    172     name_ = "t:";
    173     name_.append(name);
    174   }
    175 
    176   // Start the timer.
    177   void Start() {
    178     if (!Enabled())
    179       return;
    180     start_time_ = base::TimeTicks::Now();
    181     stop_time_ = base::TimeTicks();
    182   }
    183 
    184   // Stop the timer and record the results.
    185   void Stop() {
    186     if (!Enabled() || !Running())
    187       return;
    188     stop_time_ = base::TimeTicks::Now();
    189     Record();
    190   }
    191 
    192   // Returns true if the timer is running.
    193   bool Running() {
    194     return Enabled() && !start_time_.is_null() && stop_time_.is_null();
    195   }
    196 
    197   // Accept a TimeDelta to increment.
    198   virtual void AddTime(base::TimeDelta time) {
    199     Add(static_cast<int>(time.InMilliseconds()));
    200   }
    201 
    202  protected:
    203   // Compute the delta between start and stop, in milliseconds.
    204   void Record() {
    205     AddTime(stop_time_ - start_time_);
    206   }
    207 
    208   base::TimeTicks start_time_;
    209   base::TimeTicks stop_time_;
    210 };
    211 
    212 // A StatsRate is a timer that keeps a count of the number of intervals added so
    213 // that several statistics can be produced:
    214 //    min, max, avg, count, total
    215 class StatsRate : public StatsCounterTimer {
    216  public:
    217   // Constructs and starts the timer.
    218   explicit StatsRate(const char* name)
    219       : StatsCounterTimer(name),
    220       counter_(name),
    221       largest_add_(std::string(" ").append(name).append("MAX").c_str()) {
    222   }
    223 
    224   virtual void Add(int value) {
    225     counter_.Increment();
    226     StatsCounterTimer::Add(value);
    227     if (value > largest_add_.value())
    228       largest_add_.Set(value);
    229   }
    230 
    231  private:
    232   StatsCounter counter_;
    233   StatsCounter largest_add_;
    234 };
    235 
    236 
    237 // Helper class for scoping a timer or rate.
    238 template<class T> class StatsScope {
    239  public:
    240   explicit StatsScope<T>(T& timer)
    241       : timer_(timer) {
    242     timer_.Start();
    243   }
    244 
    245   ~StatsScope() {
    246     timer_.Stop();
    247   }
    248 
    249   void Stop() {
    250     timer_.Stop();
    251   }
    252 
    253  private:
    254   T& timer_;
    255 };
    256 
    257 #endif  // BASE_STATS_COUNTERS_H__
    258