• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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