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: ~HistogramProvider()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