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. StatsCounter(const std::string & name)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 ~StatsCounter()84 virtual ~StatsCounter() {} 85 86 // Sets the counter to a specific value. Set(int value)87 void Set(int value) { 88 int* loc = GetPtr(); 89 if (loc) *loc = value; 90 } 91 92 // Increments the counter. Increment()93 void Increment() { 94 Add(1); 95 } 96 Add(int value)97 virtual void Add(int value) { 98 int* loc = GetPtr(); 99 if (loc) 100 (*loc) += value; 101 } 102 103 // Decrements the counter. Decrement()104 void Decrement() { 105 Add(-1); 106 } 107 Subtract(int value)108 void Subtract(int value) { 109 Add(-value); 110 } 111 112 // Is this counter enabled? 113 // Returns false if table is full. Enabled()114 bool Enabled() { 115 return GetPtr() != NULL; 116 } 117 value()118 int value() { 119 int* loc = GetPtr(); 120 if (loc) return *loc; 121 return 0; 122 } 123 124 protected: StatsCounter()125 StatsCounter() 126 : counter_id_(-1) { 127 } 128 129 // Returns the cached address of this counter location. GetPtr()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. StatsCounterTimer(const std::string & name)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. Start()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. Stop()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. Running()193 bool Running() { 194 return Enabled() && !start_time_.is_null() && stop_time_.is_null(); 195 } 196 197 // Accept a TimeDelta to increment. AddTime(base::TimeDelta time)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. Record()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. StatsRate(const char * name)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 Add(int value)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) timer_(timer)241 : timer_(timer) { 242 timer_.Start(); 243 } 244 ~StatsScope()245 ~StatsScope() { 246 timer_.Stop(); 247 } 248 Stop()249 void Stop() { 250 timer_.Stop(); 251 } 252 253 private: 254 T& timer_; 255 }; 256 257 #endif // BASE_STATS_COUNTERS_H__ 258