1 // Copyright 2012 The Chromium Authors 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 <atomic> 16 #include <memory> 17 #include <string> 18 #include <unordered_map> 19 #include <unordered_set> 20 #include <vector> 21 22 #include "base/base_export.h" 23 #include "base/functional/callback.h" 24 #include "base/gtest_prod_util.h" 25 #include "base/lazy_instance.h" 26 #include "base/memory/raw_ptr.h" 27 #include "base/memory/weak_ptr.h" 28 #include "base/metrics/histogram_base.h" 29 #include "base/metrics/ranges_manager.h" 30 #include "base/metrics/record_histogram_checker.h" 31 #include "base/observer_list_threadsafe.h" 32 #include "base/strings/string_piece.h" 33 #include "base/synchronization/lock.h" 34 #include "base/thread_annotations.h" 35 #include "base/types/pass_key.h" 36 37 namespace base { 38 39 class BucketRanges; 40 class HistogramSnapshotManager; 41 42 // In-memory recorder of usage statistics (aka metrics, aka histograms). 43 // 44 // All the public methods are static and act on a global recorder. This global 45 // recorder is internally synchronized and all the static methods are thread 46 // safe. This is intended to only be run/used in the browser process. 47 // 48 // StatisticsRecorder doesn't have any public constructor. For testing purpose, 49 // you can create a temporary recorder using the factory method 50 // CreateTemporaryForTesting(). This temporary recorder becomes the global one 51 // until deleted. When this temporary recorder is deleted, it restores the 52 // previous global one. 53 class BASE_EXPORT StatisticsRecorder { 54 public: 55 // An interface class that allows the StatisticsRecorder to forcibly merge 56 // histograms from providers when necessary. 57 class HistogramProvider { 58 public: 59 // Merges all histogram information into the global versions. 60 virtual void MergeHistogramDeltas() = 0; 61 }; 62 63 // OnSampleCallback is a convenient callback type that provides information 64 // about a histogram sample. This is used in conjunction with 65 // ScopedHistogramSampleObserver to get notified when a sample is collected. 66 using OnSampleCallback = 67 base::RepeatingCallback<void(const char* /*=histogram_name*/, 68 uint64_t /*=name_hash*/, 69 HistogramBase::Sample)>; 70 71 // An observer that gets notified whenever a new sample is recorded for a 72 // particular histogram. Clients only need to construct it with the histogram 73 // name and the callback to be invoked. The class starts observing on 74 // construction and removes itself from the observer list on destruction. The 75 // clients are always notified on the same sequence in which they were 76 // registered. 77 class BASE_EXPORT ScopedHistogramSampleObserver { 78 public: 79 // Constructor. Called with the desired histogram name and the callback to 80 // be invoked when a sample is recorded. 81 explicit ScopedHistogramSampleObserver(const std::string& histogram_name, 82 OnSampleCallback callback); 83 ~ScopedHistogramSampleObserver(); 84 85 private: 86 friend class StatisticsRecorder; 87 88 // Runs the callback. 89 void RunCallback(const char* histogram_name, 90 uint64_t name_hash, 91 HistogramBase::Sample sample); 92 93 // The name of the histogram to observe. 94 const std::string histogram_name_; 95 96 // The client supplied callback that is invoked when the histogram sample is 97 // collected. 98 const OnSampleCallback callback_; 99 }; 100 101 typedef std::vector<HistogramBase*> Histograms; 102 typedef size_t SnapshotTransactionId; 103 104 StatisticsRecorder(const StatisticsRecorder&) = delete; 105 StatisticsRecorder& operator=(const StatisticsRecorder&) = delete; 106 107 // Restores the previous global recorder. 108 // 109 // When several temporary recorders are created using 110 // CreateTemporaryForTesting(), these recorders must be deleted in reverse 111 // order of creation. 112 // 113 // This method is thread safe. 114 // 115 // Precondition: The recorder being deleted is the current global recorder. 116 ~StatisticsRecorder(); 117 118 // Registers a provider of histograms that can be called to merge those into 119 // the global recorder. Calls to ImportProvidedHistograms() will fetch from 120 // registered providers. 121 // 122 // This method is thread safe. 123 static void RegisterHistogramProvider( 124 const WeakPtr<HistogramProvider>& provider); 125 126 // Registers or adds a new histogram to the collection of statistics. If an 127 // identically named histogram is already registered, then the argument 128 // |histogram| will be deleted. The returned value is always the registered 129 // histogram (either the argument, or the pre-existing registered histogram). 130 // 131 // This method is thread safe. 132 static HistogramBase* RegisterOrDeleteDuplicate(HistogramBase* histogram); 133 134 // Registers or adds a new BucketRanges. If an equivalent BucketRanges is 135 // already registered, then the argument |ranges| will be deleted. The 136 // returned value is always the registered BucketRanges (either the argument, 137 // or the pre-existing one). 138 // 139 // This method is thread safe. 140 static const BucketRanges* RegisterOrDeleteDuplicateRanges( 141 const BucketRanges* ranges); 142 143 // A method for appending histogram data to a string. Only histograms which 144 // have |query| as a substring are written to |output| (an empty string will 145 // process all registered histograms). 146 // 147 // This method is thread safe. 148 static void WriteGraph(const std::string& query, std::string* output); 149 150 // Returns the histograms with |verbosity_level| as the serialization 151 // verbosity. 152 // 153 // This method is thread safe. 154 static std::string ToJSON(JSONVerbosityLevel verbosity_level); 155 156 // Gets existing histograms. |include_persistent| determines whether 157 // histograms held in persistent storage are included. 158 // 159 // The order of returned histograms is not guaranteed. 160 // 161 // Ownership of the individual histograms remains with the StatisticsRecorder. 162 // 163 // This method is thread safe. 164 static Histograms GetHistograms(bool include_persistent = true) 165 LOCKS_EXCLUDED(lock_.Pointer()); 166 167 // Gets BucketRanges used by all histograms registered. The order of returned 168 // BucketRanges is not guaranteed. 169 // 170 // This method is thread safe. 171 static std::vector<const BucketRanges*> GetBucketRanges(); 172 173 // Finds a histogram by name. Matches the exact name. Returns a null pointer 174 // if a matching histogram is not found. 175 // 176 // This method is thread safe. 177 static HistogramBase* FindHistogram(base::StringPiece name); 178 179 // Imports histograms from providers. 180 // 181 // This method must be called on the UI thread. 182 static void ImportProvidedHistograms(); 183 184 // Snapshots all histogram deltas via |snapshot_manager|. This marks the 185 // deltas as logged. |include_persistent| determines whether histograms held 186 // in persistent storage are snapshotted. |flags_to_set| is used to set flags 187 // for each histogram. |required_flags| is used to select which histograms to 188 // record. Only histograms with all required flags are selected. If all 189 // histograms should be recorded, use |Histogram::kNoFlags| as the required 190 // flag. This is logically equivalent to calling SnapshotUnloggedSamples() 191 // followed by HistogramSnapshotManager::MarkUnloggedSamplesAsLogged() on 192 // |snapshot_manager|. Returns the snapshot transaction ID associated with 193 // this operation. Thread-safe. 194 static SnapshotTransactionId PrepareDeltas( 195 bool include_persistent, 196 HistogramBase::Flags flags_to_set, 197 HistogramBase::Flags required_flags, 198 HistogramSnapshotManager* snapshot_manager) 199 LOCKS_EXCLUDED(snapshot_lock_.Pointer()); 200 201 // Same as PrepareDeltas() above, but the samples are not marked as logged. 202 // This includes persistent histograms, and no flags will be set. A call to 203 // HistogramSnapshotManager::MarkUnloggedSamplesAsLogged() on the passed 204 // |snapshot_manager| should be made to mark them as logged. Returns the 205 // snapshot transaction ID associated with this operation. Thread-safe. 206 static SnapshotTransactionId SnapshotUnloggedSamples( 207 HistogramBase::Flags required_flags, 208 HistogramSnapshotManager* snapshot_manager) 209 LOCKS_EXCLUDED(snapshot_lock_.Pointer()); 210 211 // Returns the transaction ID of the last snapshot performed (either through 212 // PrepareDeltas() or SnapshotUnloggedSamples()). Returns 0 if a snapshot was 213 // never taken so far. Thread-safe. 214 static SnapshotTransactionId GetLastSnapshotTransactionId() 215 LOCKS_EXCLUDED(snapshot_lock_.Pointer()); 216 217 // Retrieves and runs the list of callbacks for the histogram referred to by 218 // |histogram_name|, if any. 219 // 220 // This method is thread safe. 221 static void FindAndRunHistogramCallbacks(base::PassKey<HistogramBase>, 222 const char* histogram_name, 223 uint64_t name_hash, 224 HistogramBase::Sample sample); 225 226 // Returns the number of known histograms. 227 // 228 // This method is thread safe. 229 static size_t GetHistogramCount(); 230 231 // Initializes logging histograms with --v=1. Safe to call multiple times. 232 // Is called from ctor but for browser it seems that it is more useful to 233 // start logging after statistics recorder, so we need to init log-on-shutdown 234 // later. 235 // 236 // This method is thread safe. 237 static void InitLogOnShutdown(); 238 239 // Removes a histogram from the internal set of known ones. This can be 240 // necessary during testing persistent histograms where the underlying 241 // memory is being released. 242 // 243 // This method is thread safe. 244 static void ForgetHistogramForTesting(base::StringPiece name); 245 246 // Creates a temporary StatisticsRecorder object for testing purposes. All new 247 // histograms will be registered in it until it is destructed or pushed aside 248 // for the lifetime of yet another StatisticsRecorder object. The destruction 249 // of the returned object will re-activate the previous one. 250 // StatisticsRecorder objects must be deleted in the opposite order to which 251 // they're created. 252 // 253 // This method is thread safe. 254 [[nodiscard]] static std::unique_ptr<StatisticsRecorder> 255 CreateTemporaryForTesting(); 256 257 // Sets the record checker for determining if a histogram should be recorded. 258 // Record checker doesn't affect any already recorded histograms, so this 259 // method must be called very early, before any threads have started. 260 // Record checker methods can be called on any thread, so they shouldn't 261 // mutate any state. 262 static void SetRecordChecker( 263 std::unique_ptr<RecordHistogramChecker> record_checker); 264 265 // Checks if the given histogram should be recorded based on the 266 // ShouldRecord() method of the record checker. If the record checker is not 267 // set, returns true. 268 // |histogram_hash| corresponds to the result of HashMetricNameAs32Bits(). 269 // 270 // This method is thread safe. 271 static bool ShouldRecordHistogram(uint32_t histogram_hash); 272 273 // Sorts histograms by name. 274 static Histograms Sort(Histograms histograms); 275 276 // Filters histograms by name. Only histograms which have |query| as a 277 // substring in their name are kept. An empty query keeps all histograms. 278 // |case_sensitive| determines whether the matching should be done in a 279 // case sensitive way. 280 static Histograms WithName(Histograms histograms, 281 const std::string& query, 282 bool case_sensitive = true); 283 284 using GlobalSampleCallback = void (*)(const char* /*=histogram_name*/, 285 uint64_t /*=name_hash*/, 286 HistogramBase::Sample); 287 // Installs a global callback which will be called for every added 288 // histogram sample. The given callback is a raw function pointer in order 289 // to be accessed lock-free and can be called on any thread. 290 static void SetGlobalSampleCallback( 291 const GlobalSampleCallback& global_sample_callback); 292 293 // Returns the global callback, if any, that should be called every time a 294 // histogram sample is added. global_sample_callback()295 static GlobalSampleCallback global_sample_callback() { 296 return global_sample_callback_.load(std::memory_order_relaxed); 297 } 298 299 // Returns whether there's either a global histogram callback set, 300 // or if any individual histograms have callbacks set. Used for early return 301 // when histogram samples are added. have_active_callbacks()302 static bool have_active_callbacks() { 303 return have_active_callbacks_.load(std::memory_order_relaxed); 304 } 305 306 private: 307 // Adds an observer to be notified when a new sample is recorded on the 308 // histogram referred to by |histogram_name|. Can be called before or after 309 // the histogram is created. 310 // 311 // This method is thread safe. 312 static void AddHistogramSampleObserver( 313 const std::string& histogram_name, 314 ScopedHistogramSampleObserver* observer); 315 316 // Clears the given |observer| set on the histogram referred to by 317 // |histogram_name|. 318 // 319 // This method is thread safe. 320 static void RemoveHistogramSampleObserver( 321 const std::string& histogram_name, 322 ScopedHistogramSampleObserver* observer); 323 324 typedef std::vector<WeakPtr<HistogramProvider>> HistogramProviders; 325 326 typedef std::unordered_map<StringPiece, HistogramBase*, StringPieceHash> 327 HistogramMap; 328 329 // A map of histogram name to registered observers. If the histogram isn't 330 // created yet, the observers will be added after creation. 331 using HistogramSampleObserverList = 332 base::ObserverListThreadSafe<ScopedHistogramSampleObserver>; 333 typedef std::unordered_map<std::string, 334 scoped_refptr<HistogramSampleObserverList>> 335 ObserverMap; 336 337 friend class StatisticsRecorderTest; 338 FRIEND_TEST_ALL_PREFIXES(StatisticsRecorderTest, IterationTest); 339 340 // Initializes the global recorder if it doesn't already exist. Safe to call 341 // multiple times. 342 // 343 // Precondition: The global lock is already acquired. 344 static void EnsureGlobalRecorderWhileLocked(); 345 346 // Gets histogram providers. 347 // 348 // This method is thread safe. 349 static HistogramProviders GetHistogramProviders(); 350 351 // Imports histograms from global persistent memory. 352 // 353 // Precondition: The global lock must not be held during this call. 354 static void ImportGlobalPersistentHistograms(); 355 356 // Constructs a new StatisticsRecorder and sets it as the current global 357 // recorder. 358 // 359 // This singleton instance should be started during the single-threaded 360 // portion of startup and hence it is not thread safe. It initializes globals 361 // to provide support for all future calls. 362 // 363 // Precondition: The global lock is already acquired. 364 StatisticsRecorder(); 365 366 // Initialize implementation but without lock. Caller should guard 367 // StatisticsRecorder by itself if needed (it isn't in unit tests). 368 // 369 // Precondition: The global lock is already acquired. 370 static void InitLogOnShutdownWhileLocked(); 371 372 HistogramMap histograms_; 373 ObserverMap observers_; 374 HistogramProviders providers_; 375 RangesManager ranges_manager_; 376 std::unique_ptr<RecordHistogramChecker> record_checker_; 377 378 // Previous global recorder that existed when this one was created. 379 raw_ptr<StatisticsRecorder> previous_ = nullptr; 380 381 // Global lock for internal synchronization. 382 static LazyInstance<Lock>::Leaky lock_; 383 384 // Global lock for internal synchronization of histogram snapshots. 385 static LazyInstance<base::Lock>::Leaky snapshot_lock_; 386 387 // A strictly increasing number that is incremented every time a snapshot is 388 // taken (by either calling SnapshotUnloggedSamples() or PrepareDeltas()). 389 // This represents the transaction ID of the last snapshot taken. 390 static SnapshotTransactionId last_snapshot_transaction_id_ 391 GUARDED_BY(snapshot_lock_.Get()); 392 393 // Current global recorder. This recorder is used by static methods. When a 394 // new global recorder is created by CreateTemporaryForTesting(), then the 395 // previous global recorder is referenced by top_->previous_. 396 static StatisticsRecorder* top_; 397 398 // Tracks whether InitLogOnShutdownWhileLocked() has registered a logging 399 // function that will be called when the program finishes. 400 static bool is_vlog_initialized_; 401 402 // Track whether there are active histogram callbacks present. 403 static std::atomic<bool> have_active_callbacks_; 404 405 // Stores a raw callback which should be called on any every histogram sample 406 // which gets added. 407 static std::atomic<GlobalSampleCallback> global_sample_callback_; 408 }; 409 410 } // namespace base 411 412 #endif // BASE_METRICS_STATISTICS_RECORDER_H_ 413