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