Home | History | Annotate | Download | only in metrics
      1 // Copyright (c) 2012 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 // StatisticsRecorder holds all Histograms and BucketRanges that are used by
      6 // Histograms in the system. It provides a general place for
      7 // Histograms/BucketRanges to register, and supports a global API for accessing
      8 // (i.e., dumping, or graphing) the data.
      9 
     10 #ifndef BASE_METRICS_STATISTICS_RECORDER_H_
     11 #define BASE_METRICS_STATISTICS_RECORDER_H_
     12 
     13 #include <stdint.h>
     14 
     15 #include <list>
     16 #include <map>
     17 #include <memory>
     18 #include <string>
     19 #include <vector>
     20 
     21 #include "base/base_export.h"
     22 #include "base/callback.h"
     23 #include "base/gtest_prod_util.h"
     24 #include "base/lazy_instance.h"
     25 #include "base/macros.h"
     26 #include "base/memory/weak_ptr.h"
     27 #include "base/metrics/histogram_base.h"
     28 #include "base/strings/string_piece.h"
     29 #include "base/synchronization/lock.h"
     30 
     31 namespace base {
     32 
     33 class BucketRanges;
     34 
     35 class BASE_EXPORT StatisticsRecorder {
     36  public:
     37   // A class used as a key for the histogram map below. It always references
     38   // a string owned outside of this class, likely in the value of the map.
     39   class StringKey : public StringPiece {
     40    public:
     41     // Constructs the StringKey using various sources. The source must live
     42     // at least as long as the created object.
     43     StringKey(const std::string& str) : StringPiece(str) {}
     44     StringKey(StringPiece str) : StringPiece(str) {}
     45 
     46     // Though StringPiece is better passed by value than by reference, in
     47     // this case it's being passed many times and likely already been stored
     48     // in memory (not just registers) so the benefit of pass-by-value is
     49     // negated.
     50     bool operator<(const StringKey& rhs) const {
     51       // Since order is unimportant in the map and string comparisons can be
     52       // slow, use the length as the primary sort value.
     53       if (length() < rhs.length())
     54         return true;
     55       if (length() > rhs.length())
     56         return false;
     57 
     58       // Fall back to an actual string comparison. The lengths are the same
     59       // so a simple memory-compare is sufficient. This is slightly more
     60       // efficient than calling operator<() for StringPiece which would
     61       // again have to check lengths before calling wordmemcmp().
     62       return wordmemcmp(data(), rhs.data(), length()) < 0;
     63     }
     64   };
     65 
     66   // An interface class that allows the StatisticsRecorder to forcibly merge
     67   // histograms from providers when necessary.
     68   class HistogramProvider {
     69    public:
     70     virtual ~HistogramProvider() {}
     71     // Merges all histogram information into the global versions.
     72     virtual void MergeHistogramDeltas() = 0;
     73   };
     74 
     75   typedef std::map<StringKey, HistogramBase*> HistogramMap;
     76   typedef std::vector<HistogramBase*> Histograms;
     77   typedef std::vector<WeakPtr<HistogramProvider>> HistogramProviders;
     78 
     79   // A class for iterating over the histograms held within this global resource.
     80   class BASE_EXPORT HistogramIterator {
     81    public:
     82     HistogramIterator(const HistogramMap::iterator& iter,
     83                       bool include_persistent);
     84     HistogramIterator(const HistogramIterator& rhs);  // Must be copyable.
     85     ~HistogramIterator();
     86 
     87     HistogramIterator& operator++();
     88     HistogramIterator operator++(int) {
     89       HistogramIterator tmp(*this);
     90       operator++();
     91       return tmp;
     92     }
     93 
     94     bool operator==(const HistogramIterator& rhs) const {
     95       return iter_ == rhs.iter_;
     96     }
     97     bool operator!=(const HistogramIterator& rhs) const {
     98       return iter_ != rhs.iter_;
     99     }
    100     HistogramBase* operator*() { return iter_->second; }
    101 
    102    private:
    103     HistogramMap::iterator iter_;
    104     const bool include_persistent_;
    105   };
    106 
    107   ~StatisticsRecorder();
    108 
    109   // Initializes the StatisticsRecorder system. Safe to call multiple times.
    110   static void Initialize();
    111 
    112   // Find out if histograms can now be registered into our list.
    113   static bool IsActive();
    114 
    115   // Register a provider of histograms that can be called to merge those into
    116   // the global StatisticsRecorder. Calls to ImportProvidedHistograms() will
    117   // fetch from registered providers.
    118   static void RegisterHistogramProvider(
    119       const WeakPtr<HistogramProvider>& provider);
    120 
    121   // Register, or add a new histogram to the collection of statistics. If an
    122   // identically named histogram is already registered, then the argument
    123   // |histogram| will deleted.  The returned value is always the registered
    124   // histogram (either the argument, or the pre-existing registered histogram).
    125   static HistogramBase* RegisterOrDeleteDuplicate(HistogramBase* histogram);
    126 
    127   // Register, or add a new BucketRanges. If an identically BucketRanges is
    128   // already registered, then the argument |ranges| will deleted. The returned
    129   // value is always the registered BucketRanges (either the argument, or the
    130   // pre-existing one).
    131   static const BucketRanges* RegisterOrDeleteDuplicateRanges(
    132       const BucketRanges* ranges);
    133 
    134   // Methods for appending histogram data to a string.  Only histograms which
    135   // have |query| as a substring are written to |output| (an empty string will
    136   // process all registered histograms).
    137   static void WriteHTMLGraph(const std::string& query, std::string* output);
    138   static void WriteGraph(const std::string& query, std::string* output);
    139 
    140   // Returns the histograms with |query| as a substring as JSON text (an empty
    141   // |query| will process all registered histograms).
    142   static std::string ToJSON(const std::string& query);
    143 
    144   // Method for extracting histograms which were marked for use by UMA.
    145   static void GetHistograms(Histograms* output);
    146 
    147   // Method for extracting BucketRanges used by all histograms registered.
    148   static void GetBucketRanges(std::vector<const BucketRanges*>* output);
    149 
    150   // Find a histogram by name. It matches the exact name. This method is thread
    151   // safe.  It returns NULL if a matching histogram is not found.
    152   static HistogramBase* FindHistogram(base::StringPiece name);
    153 
    154   // Imports histograms from providers. This must be called on the UI thread.
    155   static void ImportProvidedHistograms();
    156 
    157   // Support for iterating over known histograms.
    158   static HistogramIterator begin(bool include_persistent);
    159   static HistogramIterator end();
    160 
    161   // GetSnapshot copies some of the pointers to registered histograms into the
    162   // caller supplied vector (Histograms). Only histograms which have |query| as
    163   // a substring are copied (an empty string will process all registered
    164   // histograms).
    165   static void GetSnapshot(const std::string& query, Histograms* snapshot);
    166 
    167   typedef base::Callback<void(HistogramBase::Sample)> OnSampleCallback;
    168 
    169   // SetCallback sets the callback to notify when a new sample is recorded on
    170   // the histogram referred to by |histogram_name|. The call to this method can
    171   // be be done before or after the histogram is created. This method is thread
    172   // safe. The return value is whether or not the callback was successfully set.
    173   static bool SetCallback(const std::string& histogram_name,
    174                           const OnSampleCallback& callback);
    175 
    176   // ClearCallback clears any callback set on the histogram referred to by
    177   // |histogram_name|. This method is thread safe.
    178   static void ClearCallback(const std::string& histogram_name);
    179 
    180   // FindCallback retrieves the callback for the histogram referred to by
    181   // |histogram_name|, or a null callback if no callback exists for this
    182   // histogram. This method is thread safe.
    183   static OnSampleCallback FindCallback(const std::string& histogram_name);
    184 
    185   // Returns the number of known histograms.
    186   static size_t GetHistogramCount();
    187 
    188   // Initializes logging histograms with --v=1. Safe to call multiple times.
    189   // Is called from ctor but for browser it seems that it is more useful to
    190   // start logging after statistics recorder, so we need to init log-on-shutdown
    191   // later.
    192   static void InitLogOnShutdown();
    193 
    194   // Removes a histogram from the internal set of known ones. This can be
    195   // necessary during testing persistent histograms where the underlying
    196   // memory is being released.
    197   static void ForgetHistogramForTesting(base::StringPiece name);
    198 
    199   // Creates a local StatisticsRecorder object for testing purposes. All new
    200   // histograms will be registered in it until it is destructed or pushed
    201   // aside for the lifetime of yet another SR object. The destruction of the
    202   // returned object will re-activate the previous one. Always release SR
    203   // objects in the opposite order to which they're created.
    204   static std::unique_ptr<StatisticsRecorder> CreateTemporaryForTesting()
    205       WARN_UNUSED_RESULT;
    206 
    207   // Resets any global instance of the statistics-recorder that was created
    208   // by a call to Initialize().
    209   static void UninitializeForTesting();
    210 
    211  private:
    212   // We keep a map of callbacks to histograms, so that as histograms are
    213   // created, we can set the callback properly.
    214   typedef std::map<std::string, OnSampleCallback> CallbackMap;
    215 
    216   // We keep all |bucket_ranges_| in a map, from checksum to a list of
    217   // |bucket_ranges_|.  Checksum is calculated from the |ranges_| in
    218   // |bucket_ranges_|.
    219   typedef std::map<uint32_t, std::list<const BucketRanges*>*> RangesMap;
    220 
    221   friend struct LazyInstanceTraitsBase<StatisticsRecorder>;
    222   friend class StatisticsRecorderTest;
    223 
    224   // Imports histograms from global persistent memory. The global lock must
    225   // not be held during this call.
    226   static void ImportGlobalPersistentHistograms();
    227 
    228   // The constructor just initializes static members. Usually client code should
    229   // use Initialize to do this. But in test code, you can friend this class and
    230   // call the constructor to get a clean StatisticsRecorder.
    231   StatisticsRecorder();
    232 
    233   // Initialize implementation but without lock. Caller should guard
    234   // StatisticsRecorder by itself if needed (it isn't in unit tests).
    235   void InitLogOnShutdownWithoutLock();
    236 
    237   // These are copies of everything that existed when the (test) Statistics-
    238   // Recorder was created. The global ones have to be moved aside to create a
    239   // clean environment.
    240   std::unique_ptr<HistogramMap> existing_histograms_;
    241   std::unique_ptr<CallbackMap> existing_callbacks_;
    242   std::unique_ptr<RangesMap> existing_ranges_;
    243   std::unique_ptr<HistogramProviders> existing_providers_;
    244 
    245   bool vlog_initialized_ = false;
    246 
    247   static void Reset();
    248   static void DumpHistogramsToVlog(void* instance);
    249 
    250   static HistogramMap* histograms_;
    251   static CallbackMap* callbacks_;
    252   static RangesMap* ranges_;
    253   static HistogramProviders* providers_;
    254 
    255   // Lock protects access to above maps. This is a LazyInstance to avoid races
    256   // when the above methods are used before Initialize(). Previously each method
    257   // would do |if (!lock_) return;| which would race with
    258   // |lock_ = new Lock;| in StatisticsRecorder(). http://crbug.com/672852.
    259   static base::LazyInstance<base::Lock>::Leaky lock_;
    260 
    261   DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder);
    262 };
    263 
    264 }  // namespace base
    265 
    266 #endif  // BASE_METRICS_STATISTICS_RECORDER_H_
    267