// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_METRICS_STATS_COUNTERS_H_ #define BASE_METRICS_STATS_COUNTERS_H_ #include <string> #include "base/base_export.h" #include "base/compiler_specific.h" #include "base/metrics/stats_table.h" #include "base/time/time.h" namespace base { // StatsCounters are dynamically created values which can be tracked in // the StatsTable. They are designed to be lightweight to create and // easy to use. // // Since StatsCounters can be created dynamically by name, there is // a hash table lookup to find the counter in the table. A StatsCounter // object can be created once and used across multiple threads safely. // // Example usage: // { // StatsCounter request_count("RequestCount"); // request_count.Increment(); // } // // Note that creating counters on the stack does work, however creating // the counter object requires a hash table lookup. For inner loops, it // may be better to create the counter either as a member of another object // (or otherwise outside of the loop) for maximum performance. // // Internally, a counter represents a value in a row of a StatsTable. // The row has a 32bit value for each process/thread in the table and also // a name (stored in the table metadata). // // NOTE: In order to make stats_counters usable in lots of different code, // avoid any dependencies inside this header file. // //------------------------------------------------------------------------------ // Define macros for ease of use. They also allow us to change definitions // as the implementation varies, or depending on compile options. //------------------------------------------------------------------------------ // First provide generic macros, which exist in production as well as debug. #define STATS_COUNTER(name, delta) do { \ base::StatsCounter counter(name); \ counter.Add(delta); \ } while (0) #define SIMPLE_STATS_COUNTER(name) STATS_COUNTER(name, 1) #define RATE_COUNTER(name, duration) do { \ base::StatsRate hit_count(name); \ hit_count.AddTime(duration); \ } while (0) // Define Debug vs non-debug flavors of macros. #ifndef NDEBUG #define DSTATS_COUNTER(name, delta) STATS_COUNTER(name, delta) #define DSIMPLE_STATS_COUNTER(name) SIMPLE_STATS_COUNTER(name) #define DRATE_COUNTER(name, duration) RATE_COUNTER(name, duration) #else // NDEBUG #define DSTATS_COUNTER(name, delta) do {} while (0) #define DSIMPLE_STATS_COUNTER(name) do {} while (0) #define DRATE_COUNTER(name, duration) do {} while (0) #endif // NDEBUG //------------------------------------------------------------------------------ // StatsCounter represents a counter in the StatsTable class. class BASE_EXPORT StatsCounter { public: // Create a StatsCounter object. explicit StatsCounter(const std::string& name); virtual ~StatsCounter(); // Sets the counter to a specific value. void Set(int value); // Increments the counter. void Increment() { Add(1); } virtual void Add(int value); // Decrements the counter. void Decrement() { Add(-1); } void Subtract(int value) { Add(-value); } // Is this counter enabled? // Returns false if table is full. bool Enabled() { return GetPtr() != NULL; } int value() { int* loc = GetPtr(); if (loc) return *loc; return 0; } protected: StatsCounter(); // Returns the cached address of this counter location. int* GetPtr(); std::string name_; // The counter id in the table. We initialize to -1 (an invalid value) // and then cache it once it has been looked up. The counter_id is // valid across all threads and processes. int32 counter_id_; }; // A StatsCounterTimer is a StatsCounter which keeps a timer during // the scope of the StatsCounterTimer. On destruction, it will record // its time measurement. class BASE_EXPORT StatsCounterTimer : protected StatsCounter { public: // Constructs and starts the timer. explicit StatsCounterTimer(const std::string& name); virtual ~StatsCounterTimer(); // Start the timer. void Start(); // Stop the timer and record the results. void Stop(); // Returns true if the timer is running. bool Running(); // Accept a TimeDelta to increment. virtual void AddTime(TimeDelta time); protected: // Compute the delta between start and stop, in milliseconds. void Record(); TimeTicks start_time_; TimeTicks stop_time_; }; // A StatsRate is a timer that keeps a count of the number of intervals added so // that several statistics can be produced: // min, max, avg, count, total class BASE_EXPORT StatsRate : public StatsCounterTimer { public: // Constructs and starts the timer. explicit StatsRate(const std::string& name); virtual ~StatsRate(); virtual void Add(int value) OVERRIDE; private: StatsCounter counter_; StatsCounter largest_add_; }; // Helper class for scoping a timer or rate. template<class T> class StatsScope { public: explicit StatsScope<T>(T& timer) : timer_(timer) { timer_.Start(); } ~StatsScope() { timer_.Stop(); } void Stop() { timer_.Stop(); } private: T& timer_; }; } // namespace base #endif // BASE_METRICS_STATS_COUNTERS_H_