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 <memory>
     16 #include <string>
     17 #include <unordered_map>
     18 #include <unordered_set>
     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/metrics/record_histogram_checker.h"
     29 #include "base/strings/string_piece.h"
     30 #include "base/synchronization/lock.h"
     31 
     32 namespace base {
     33 
     34 class BucketRanges;
     35 class HistogramSnapshotManager;
     36 
     37 // In-memory recorder of usage statistics (aka metrics, aka histograms).
     38 //
     39 // All the public methods are static and act on a global recorder. This global
     40 // recorder is internally synchronized and all the static methods are thread
     41 // safe.
     42 //
     43 // StatisticsRecorder doesn't have any public constructor. For testing purpose,
     44 // you can create a temporary recorder using the factory method
     45 // CreateTemporaryForTesting(). This temporary recorder becomes the global one
     46 // until deleted. When this temporary recorder is deleted, it restores the
     47 // previous global one.
     48 class BASE_EXPORT StatisticsRecorder {
     49  public:
     50   // An interface class that allows the StatisticsRecorder to forcibly merge
     51   // histograms from providers when necessary.
     52   class HistogramProvider {
     53    public:
     54     virtual ~HistogramProvider() {}
     55     // Merges all histogram information into the global versions.
     56     virtual void MergeHistogramDeltas() = 0;
     57   };
     58 
     59   typedef std::vector<HistogramBase*> Histograms;
     60 
     61   // Restores the previous global recorder.
     62   //
     63   // When several temporary recorders are created using
     64   // CreateTemporaryForTesting(), these recorders must be deleted in reverse
     65   // order of creation.
     66   //
     67   // This method is thread safe.
     68   //
     69   // Precondition: The recorder being deleted is the current global recorder.
     70   ~StatisticsRecorder();
     71 
     72   // Registers a provider of histograms that can be called to merge those into
     73   // the global recorder. Calls to ImportProvidedHistograms() will fetch from
     74   // registered providers.
     75   //
     76   // This method is thread safe.
     77   static void RegisterHistogramProvider(
     78       const WeakPtr<HistogramProvider>& provider);
     79 
     80   // Registers or adds a new histogram to the collection of statistics. If an
     81   // identically named histogram is already registered, then the argument
     82   // |histogram| will be deleted. The returned value is always the registered
     83   // histogram (either the argument, or the pre-existing registered histogram).
     84   //
     85   // This method is thread safe.
     86   static HistogramBase* RegisterOrDeleteDuplicate(HistogramBase* histogram);
     87 
     88   // Registers or adds a new BucketRanges. If an equivalent BucketRanges is
     89   // already registered, then the argument |ranges| will be deleted. The
     90   // returned value is always the registered BucketRanges (either the argument,
     91   // or the pre-existing one).
     92   //
     93   // This method is thread safe.
     94   static const BucketRanges* RegisterOrDeleteDuplicateRanges(
     95       const BucketRanges* ranges);
     96 
     97   // Methods for appending histogram data to a string.  Only histograms which
     98   // have |query| as a substring are written to |output| (an empty string will
     99   // process all registered histograms).
    100   //
    101   // These methods are thread safe.
    102   static void WriteHTMLGraph(const std::string& query, std::string* output);
    103   static void WriteGraph(const std::string& query, std::string* output);
    104 
    105   // Returns the histograms with |verbosity_level| as the serialization
    106   // verbosity.
    107   //
    108   // This method is thread safe.
    109   static std::string ToJSON(JSONVerbosityLevel verbosity_level);
    110 
    111   // Gets existing histograms.
    112   //
    113   // The order of returned histograms is not guaranteed.
    114   //
    115   // Ownership of the individual histograms remains with the StatisticsRecorder.
    116   //
    117   // This method is thread safe.
    118   static Histograms GetHistograms();
    119 
    120   // Gets BucketRanges used by all histograms registered. The order of returned
    121   // BucketRanges is not guaranteed.
    122   //
    123   // This method is thread safe.
    124   static std::vector<const BucketRanges*> GetBucketRanges();
    125 
    126   // Finds a histogram by name. Matches the exact name. Returns a null pointer
    127   // if a matching histogram is not found.
    128   //
    129   // This method is thread safe.
    130   static HistogramBase* FindHistogram(base::StringPiece name);
    131 
    132   // Imports histograms from providers.
    133   //
    134   // This method must be called on the UI thread.
    135   static void ImportProvidedHistograms();
    136 
    137   // Snapshots all histograms via |snapshot_manager|. |flags_to_set| is used to
    138   // set flags for each histogram. |required_flags| is used to select
    139   // histograms to be recorded. Only histograms that have all the flags
    140   // specified by the argument will be chosen. If all histograms should be
    141   // recorded, set it to |Histogram::kNoFlags|.
    142   static void PrepareDeltas(bool include_persistent,
    143                             HistogramBase::Flags flags_to_set,
    144                             HistogramBase::Flags required_flags,
    145                             HistogramSnapshotManager* snapshot_manager);
    146 
    147   typedef base::Callback<void(HistogramBase::Sample)> OnSampleCallback;
    148 
    149   // Sets the callback to notify when a new sample is recorded on the histogram
    150   // referred to by |histogram_name|. Can be called before or after the
    151   // histogram is created. Returns whether the callback was successfully set.
    152   //
    153   // This method is thread safe.
    154   static bool SetCallback(const std::string& histogram_name,
    155                           const OnSampleCallback& callback);
    156 
    157   // Clears any callback set on the histogram referred to by |histogram_name|.
    158   //
    159   // This method is thread safe.
    160   static void ClearCallback(const std::string& histogram_name);
    161 
    162   // Retrieves the callback for the histogram referred to by |histogram_name|,
    163   // or a null callback if no callback exists for this histogram.
    164   //
    165   // This method is thread safe.
    166   static OnSampleCallback FindCallback(const std::string& histogram_name);
    167 
    168   // Returns the number of known histograms.
    169   //
    170   // This method is thread safe.
    171   static size_t GetHistogramCount();
    172 
    173   // Initializes logging histograms with --v=1. Safe to call multiple times.
    174   // Is called from ctor but for browser it seems that it is more useful to
    175   // start logging after statistics recorder, so we need to init log-on-shutdown
    176   // later.
    177   //
    178   // This method is thread safe.
    179   static void InitLogOnShutdown();
    180 
    181   // Removes a histogram from the internal set of known ones. This can be
    182   // necessary during testing persistent histograms where the underlying
    183   // memory is being released.
    184   //
    185   // This method is thread safe.
    186   static void ForgetHistogramForTesting(base::StringPiece name);
    187 
    188   // Creates a temporary StatisticsRecorder object for testing purposes. All new
    189   // histograms will be registered in it until it is destructed or pushed aside
    190   // for the lifetime of yet another StatisticsRecorder object. The destruction
    191   // of the returned object will re-activate the previous one.
    192   // StatisticsRecorder objects must be deleted in the opposite order to which
    193   // they're created.
    194   //
    195   // This method is thread safe.
    196   static std::unique_ptr<StatisticsRecorder> CreateTemporaryForTesting()
    197       WARN_UNUSED_RESULT;
    198 
    199   // Sets the record checker for determining if a histogram should be recorded.
    200   // Record checker doesn't affect any already recorded histograms, so this
    201   // method must be called very early, before any threads have started.
    202   // Record checker methods can be called on any thread, so they shouldn't
    203   // mutate any state.
    204   static void SetRecordChecker(
    205       std::unique_ptr<RecordHistogramChecker> record_checker);
    206 
    207   // Checks if the given histogram should be recorded based on the
    208   // ShouldRecord() method of the record checker. If the record checker is not
    209   // set, returns true.
    210   //
    211   // This method is thread safe.
    212   static bool ShouldRecordHistogram(uint64_t histogram_hash);
    213 
    214   // Sorts histograms by name.
    215   static Histograms Sort(Histograms histograms);
    216 
    217   // Filters histograms by name. Only histograms which have |query| as a
    218   // substring in their name are kept. An empty query keeps all histograms.
    219   static Histograms WithName(Histograms histograms, const std::string& query);
    220 
    221   // Filters histograms by persistency. Only non-persistent histograms are kept.
    222   static Histograms NonPersistent(Histograms histograms);
    223 
    224  private:
    225   typedef std::vector<WeakPtr<HistogramProvider>> HistogramProviders;
    226 
    227   typedef std::unordered_map<StringPiece, HistogramBase*, StringPieceHash>
    228       HistogramMap;
    229 
    230   // We keep a map of callbacks to histograms, so that as histograms are
    231   // created, we can set the callback properly.
    232   typedef std::unordered_map<std::string, OnSampleCallback> CallbackMap;
    233 
    234   struct BucketRangesHash {
    235     size_t operator()(const BucketRanges* a) const;
    236   };
    237 
    238   struct BucketRangesEqual {
    239     bool operator()(const BucketRanges* a, const BucketRanges* b) const;
    240   };
    241 
    242   typedef std::
    243       unordered_set<const BucketRanges*, BucketRangesHash, BucketRangesEqual>
    244           RangesMap;
    245 
    246   friend class StatisticsRecorderTest;
    247   FRIEND_TEST_ALL_PREFIXES(StatisticsRecorderTest, IterationTest);
    248 
    249   // Initializes the global recorder if it doesn't already exist. Safe to call
    250   // multiple times.
    251   //
    252   // Precondition: The global lock is already acquired.
    253   static void EnsureGlobalRecorderWhileLocked();
    254 
    255   // Gets histogram providers.
    256   //
    257   // This method is thread safe.
    258   static HistogramProviders GetHistogramProviders();
    259 
    260   // Imports histograms from global persistent memory.
    261   //
    262   // Precondition: The global lock must not be held during this call.
    263   static void ImportGlobalPersistentHistograms();
    264 
    265   // Constructs a new StatisticsRecorder and sets it as the current global
    266   // recorder.
    267   //
    268   // Precondition: The global lock is already acquired.
    269   StatisticsRecorder();
    270 
    271   // Initialize implementation but without lock. Caller should guard
    272   // StatisticsRecorder by itself if needed (it isn't in unit tests).
    273   //
    274   // Precondition: The global lock is already acquired.
    275   static void InitLogOnShutdownWhileLocked();
    276 
    277   HistogramMap histograms_;
    278   CallbackMap callbacks_;
    279   RangesMap ranges_;
    280   HistogramProviders providers_;
    281   std::unique_ptr<RecordHistogramChecker> record_checker_;
    282 
    283   // Previous global recorder that existed when this one was created.
    284   StatisticsRecorder* previous_ = nullptr;
    285 
    286   // Global lock for internal synchronization.
    287   static LazyInstance<Lock>::Leaky lock_;
    288 
    289   // Current global recorder. This recorder is used by static methods. When a
    290   // new global recorder is created by CreateTemporaryForTesting(), then the
    291   // previous global recorder is referenced by top_->previous_.
    292   static StatisticsRecorder* top_;
    293 
    294   // Tracks whether InitLogOnShutdownWhileLocked() has registered a logging
    295   // function that will be called when the program finishes.
    296   static bool is_vlog_initialized_;
    297 
    298   DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder);
    299 };
    300 
    301 }  // namespace base
    302 
    303 #endif  // BASE_METRICS_STATISTICS_RECORDER_H_
    304