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