blob: 75352d1bf4674da767751bbbcf88294e6128e7b6 [file] [log] [blame]
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +09001// 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
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +09005// 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.
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +09009
10#ifndef BASE_METRICS_STATISTICS_RECORDER_H_
11#define BASE_METRICS_STATISTICS_RECORDER_H_
12
avia6a6a682015-12-27 07:15:14 +090013#include <stdint.h>
14
bcwhiteb9b48bb2016-04-09 02:38:29 +090015#include <memory>
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +090016#include <string>
François Degros2a5c8902017-12-19 10:58:49 +090017#include <unordered_map>
18#include <unordered_set>
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +090019#include <vector>
20
21#include "base/base_export.h"
simonhatch91fbd4d2015-07-16 07:22:57 +090022#include "base/callback.h"
rtenneti@chromium.org00491d42012-07-20 04:17:32 +090023#include "base/gtest_prod_util.h"
24#include "base/lazy_instance.h"
avia6a6a682015-12-27 07:15:14 +090025#include "base/macros.h"
bcwhite9b3ea232017-02-01 10:58:56 +090026#include "base/memory/weak_ptr.h"
simonhatch91fbd4d2015-07-16 07:22:57 +090027#include "base/metrics/histogram_base.h"
Ira Burak14aeed02017-09-13 22:43:28 +090028#include "base/metrics/record_histogram_checker.h"
bcwhite85fe1c82016-02-18 07:40:35 +090029#include "base/strings/string_piece.h"
gab4d4cd0c2016-12-13 07:36:39 +090030#include "base/synchronization/lock.h"
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +090031
32namespace base {
33
kaiwang@chromium.org7c4acad2012-07-26 05:02:48 +090034class BucketRanges;
Alexei Svitkine16c27602017-07-25 03:31:31 +090035class HistogramSnapshotManager;
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +090036
François Degrosbbe88cc2018-01-05 07:54:17 +090037// In-memory recorder of usage statistics (aka metrics, aka histograms).
38//
François Degrose9835932018-01-08 07:42:27 +090039// 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.
François Degrosbbe88cc2018-01-05 07:54:17 +090042//
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.
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +090048class BASE_EXPORT StatisticsRecorder {
49 public:
bcwhite9b3ea232017-02-01 10:58:56 +090050 // An interface class that allows the StatisticsRecorder to forcibly merge
51 // histograms from providers when necessary.
52 class HistogramProvider {
53 public:
54 // Merges all histogram information into the global versions.
55 virtual void MergeHistogramDeltas() = 0;
56 };
57
kaiwang@chromium.org7881e422013-03-01 12:53:25 +090058 typedef std::vector<HistogramBase*> Histograms;
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +090059
François Degrosbbe88cc2018-01-05 07:54:17 +090060 // Restores the previous global recorder.
61 //
62 // When several temporary recorders are created using
63 // CreateTemporaryForTesting(), these recorders must be deleted in reverse
64 // order of creation.
65 //
66 // This method is thread safe.
67 //
68 // Precondition: The recorder being deleted is the current global recorder.
bcwhite5d8f9102016-03-17 02:25:41 +090069 ~StatisticsRecorder();
70
François Degrosbbe88cc2018-01-05 07:54:17 +090071 // Registers a provider of histograms that can be called to merge those into
72 // the global recorder. Calls to ImportProvidedHistograms() will fetch from
73 // registered providers.
74 //
75 // This method is thread safe.
bcwhite9b3ea232017-02-01 10:58:56 +090076 static void RegisterHistogramProvider(
77 const WeakPtr<HistogramProvider>& provider);
78
François Degrosbbe88cc2018-01-05 07:54:17 +090079 // Registers or adds a new histogram to the collection of statistics. If an
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +090080 // identically named histogram is already registered, then the argument
François Degrosbbe88cc2018-01-05 07:54:17 +090081 // |histogram| will be deleted. The returned value is always the registered
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +090082 // histogram (either the argument, or the pre-existing registered histogram).
François Degrosbbe88cc2018-01-05 07:54:17 +090083 //
84 // This method is thread safe.
kaiwang@chromium.org7881e422013-03-01 12:53:25 +090085 static HistogramBase* RegisterOrDeleteDuplicate(HistogramBase* histogram);
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +090086
François Degrosbbe88cc2018-01-05 07:54:17 +090087 // Registers or adds a new BucketRanges. If an equivalent BucketRanges is
88 // already registered, then the argument |ranges| will be deleted. The
89 // returned value is always the registered BucketRanges (either the argument,
90 // or the pre-existing one).
91 //
92 // This method is thread safe.
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +090093 static const BucketRanges* RegisterOrDeleteDuplicateRanges(
94 const BucketRanges* ranges);
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +090095
grt@chromium.orge29d3e52013-11-15 03:33:53 +090096 // Methods for appending histogram data to a string. Only histograms which
97 // have |query| as a substring are written to |output| (an empty string will
98 // process all registered histograms).
François Degrosbbe88cc2018-01-05 07:54:17 +090099 //
100 // These methods are thread safe.
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +0900101 static void WriteHTMLGraph(const std::string& query, std::string* output);
102 static void WriteGraph(const std::string& query, std::string* output);
103
Tarun Bansal9ba53ac2017-11-29 23:44:12 +0900104 // Returns the histograms with |verbosity_level| as the serialization
105 // verbosity.
François Degrosbbe88cc2018-01-05 07:54:17 +0900106 //
107 // This method is thread safe.
Tarun Bansal9ba53ac2017-11-29 23:44:12 +0900108 static std::string ToJSON(JSONVerbosityLevel verbosity_level);
grt@chromium.orge29d3e52013-11-15 03:33:53 +0900109
François Degrosbbe88cc2018-01-05 07:54:17 +0900110 // Extracts histograms which were marked for use by UMA.
François Degros2a5c8902017-12-19 10:58:49 +0900111 //
112 // This method is thread safe.
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +0900113 static void GetHistograms(Histograms* output);
114
François Degrosbbe88cc2018-01-05 07:54:17 +0900115 // Extracts BucketRanges used by all histograms registered.
kaiwang@chromium.orga97a5ae2012-08-02 06:34:08 +0900116 static void GetBucketRanges(std::vector<const BucketRanges*>* output);
117
François Degrosbbe88cc2018-01-05 07:54:17 +0900118 // Finds a histogram by name. Matches the exact name. Returns a null pointer
119 // if a matching histogram is not found.
François Degros2a5c8902017-12-19 10:58:49 +0900120 //
121 // This method is thread safe.
bcwhite76dc9632016-02-20 02:12:37 +0900122 static HistogramBase* FindHistogram(base::StringPiece name);
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +0900123
François Degrosbbe88cc2018-01-05 07:54:17 +0900124 // Imports histograms from providers.
125 //
126 // This method must be called on the UI thread.
bcwhite9b3ea232017-02-01 10:58:56 +0900127 static void ImportProvidedHistograms();
128
Alexei Svitkine16c27602017-07-25 03:31:31 +0900129 // Snapshots all histograms via |snapshot_manager|. |flags_to_set| is used to
130 // set flags for each histogram. |required_flags| is used to select
131 // histograms to be recorded. Only histograms that have all the flags
132 // specified by the argument will be chosen. If all histograms should be
133 // recorded, set it to |Histogram::kNoFlags|.
134 static void PrepareDeltas(bool include_persistent,
135 HistogramBase::Flags flags_to_set,
136 HistogramBase::Flags required_flags,
137 HistogramSnapshotManager* snapshot_manager);
bcwhitee93a8012016-02-02 06:07:56 +0900138
François Degrosbbe88cc2018-01-05 07:54:17 +0900139 // Extracts registered histograms. Only histograms which have |query| as a
140 // substring are extracted. An empty query will extract all registered
141 // histograms.
François Degros2a5c8902017-12-19 10:58:49 +0900142 //
143 // This method is thread safe.
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +0900144 static void GetSnapshot(const std::string& query, Histograms* snapshot);
145
simonhatch91fbd4d2015-07-16 07:22:57 +0900146 typedef base::Callback<void(HistogramBase::Sample)> OnSampleCallback;
147
François Degrosbbe88cc2018-01-05 07:54:17 +0900148 // Sets the callback to notify when a new sample is recorded on the histogram
149 // referred to by |histogram_name|. Can be called before or after the
150 // histogram is created. Returns whether the callback was successfully set.
151 //
152 // This method is thread safe.
simonhatch91fbd4d2015-07-16 07:22:57 +0900153 static bool SetCallback(const std::string& histogram_name,
154 const OnSampleCallback& callback);
155
François Degrosbbe88cc2018-01-05 07:54:17 +0900156 // Clears any callback set on the histogram referred to by |histogram_name|.
157 //
158 // This method is thread safe.
simonhatch91fbd4d2015-07-16 07:22:57 +0900159 static void ClearCallback(const std::string& histogram_name);
160
François Degrosbbe88cc2018-01-05 07:54:17 +0900161 // Retrieves the callback for the histogram referred to by |histogram_name|,
162 // or a null callback if no callback exists for this histogram.
163 //
164 // This method is thread safe.
simonhatch91fbd4d2015-07-16 07:22:57 +0900165 static OnSampleCallback FindCallback(const std::string& histogram_name);
166
bcwhite5d8f9102016-03-17 02:25:41 +0900167 // Returns the number of known histograms.
François Degrosbbe88cc2018-01-05 07:54:17 +0900168 //
169 // This method is thread safe.
bcwhite5d8f9102016-03-17 02:25:41 +0900170 static size_t GetHistogramCount();
171
boriay826ae202016-07-05 17:15:29 +0900172 // Initializes logging histograms with --v=1. Safe to call multiple times.
173 // Is called from ctor but for browser it seems that it is more useful to
174 // start logging after statistics recorder, so we need to init log-on-shutdown
175 // later.
François Degrosbbe88cc2018-01-05 07:54:17 +0900176 //
177 // This method is thread safe.
boriay826ae202016-07-05 17:15:29 +0900178 static void InitLogOnShutdown();
179
bcwhite85fe1c82016-02-18 07:40:35 +0900180 // Removes a histogram from the internal set of known ones. This can be
181 // necessary during testing persistent histograms where the underlying
182 // memory is being released.
François Degrosbbe88cc2018-01-05 07:54:17 +0900183 //
184 // This method is thread safe.
bcwhite85fe1c82016-02-18 07:40:35 +0900185 static void ForgetHistogramForTesting(base::StringPiece name);
186
François Degrosbbe88cc2018-01-05 07:54:17 +0900187 // Creates a temporary StatisticsRecorder object for testing purposes. All new
188 // histograms will be registered in it until it is destructed or pushed aside
189 // for the lifetime of yet another StatisticsRecorder object. The destruction
190 // of the returned object will re-activate the previous one.
191 // StatisticsRecorder objects must be deleted in the opposite order to which
192 // they're created.
193 //
194 // This method is thread safe.
bcwhiteb98e7852016-06-04 02:56:35 +0900195 static std::unique_ptr<StatisticsRecorder> CreateTemporaryForTesting()
196 WARN_UNUSED_RESULT;
197
Ira Burak14aeed02017-09-13 22:43:28 +0900198 // Sets the record checker for determining if a histogram should be recorded.
199 // Record checker doesn't affect any already recorded histograms, so this
200 // method must be called very early, before any threads have started.
201 // Record checker methods can be called on any thread, so they shouldn't
202 // mutate any state.
François Degrosbbe88cc2018-01-05 07:54:17 +0900203 //
Ira Burak14aeed02017-09-13 22:43:28 +0900204 // TODO(iburak): This is not yet hooked up to histogram recording
205 // infrastructure.
206 static void SetRecordChecker(
207 std::unique_ptr<RecordHistogramChecker> record_checker);
208
François Degrosbbe88cc2018-01-05 07:54:17 +0900209 // Checks if the given histogram should be recorded based on the
210 // ShouldRecord() method of the record checker. If the record checker is not
211 // set, returns true.
212 //
213 // This method is thread safe.
Ira Burak14aeed02017-09-13 22:43:28 +0900214 static bool ShouldRecordHistogram(uint64_t histogram_hash);
215
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +0900216 private:
François Degros2a5c8902017-12-19 10:58:49 +0900217 typedef std::vector<WeakPtr<HistogramProvider>> HistogramProviders;
218
219 typedef std::unordered_map<StringPiece, HistogramBase*, StringPieceHash>
220 HistogramMap;
221
simonhatch91fbd4d2015-07-16 07:22:57 +0900222 // We keep a map of callbacks to histograms, so that as histograms are
223 // created, we can set the callback properly.
François Degros2a5c8902017-12-19 10:58:49 +0900224 typedef std::unordered_map<std::string, OnSampleCallback> CallbackMap;
simonhatch91fbd4d2015-07-16 07:22:57 +0900225
François Degros2a5c8902017-12-19 10:58:49 +0900226 struct BucketRangesHash {
227 size_t operator()(const BucketRanges* a) const;
228 };
229
230 struct BucketRangesEqual {
231 bool operator()(const BucketRanges* a, const BucketRanges* b) const;
232 };
233
234 typedef std::
235 unordered_set<const BucketRanges*, BucketRangesHash, BucketRangesEqual>
236 RangesMap;
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +0900237
boriay826ae202016-07-05 17:15:29 +0900238 friend class StatisticsRecorderTest;
Alexei Svitkine16c27602017-07-25 03:31:31 +0900239 FRIEND_TEST_ALL_PREFIXES(StatisticsRecorderTest, IterationTest);
240
François Degrose9835932018-01-08 07:42:27 +0900241 // Initializes the global recorder if it doesn't already exist. Safe to call
242 // multiple times.
243 //
244 // Precondition: The global lock is already acquired.
245 static void EnsureGlobalRecorderWhileLocked();
246
François Degrosbbe88cc2018-01-05 07:54:17 +0900247 // Fetches set of existing histograms. Ownership of the individual histograms
Brian Whiteee1cd702017-08-18 04:43:56 +0900248 // remains with the StatisticsRecorder.
François Degrosbbe88cc2018-01-05 07:54:17 +0900249 //
250 // This method is thread safe.
François Degros2a5c8902017-12-19 10:58:49 +0900251 static Histograms GetKnownHistograms(bool include_persistent);
rtenneti@chromium.org00491d42012-07-20 04:17:32 +0900252
François Degrosbbe88cc2018-01-05 07:54:17 +0900253 // Gets histogram providers.
254 //
255 // This method is thread safe.
256 static HistogramProviders GetHistogramProviders();
257
258 // Imports histograms from global persistent memory.
259 //
260 // Precondition: The global lock must not be held during this call.
bcwhite2265a682016-04-14 01:09:54 +0900261 static void ImportGlobalPersistentHistograms();
262
François Degrosbbe88cc2018-01-05 07:54:17 +0900263 // Constructs a new StatisticsRecorder and sets it as the current global
264 // recorder.
265 //
266 // Precondition: The global lock is already acquired.
rtenneti@chromium.org00491d42012-07-20 04:17:32 +0900267 StatisticsRecorder();
rtenneti@chromium.org00491d42012-07-20 04:17:32 +0900268
boriay826ae202016-07-05 17:15:29 +0900269 // Initialize implementation but without lock. Caller should guard
270 // StatisticsRecorder by itself if needed (it isn't in unit tests).
François Degrosbbe88cc2018-01-05 07:54:17 +0900271 //
272 // Precondition: The global lock is already acquired.
273 static void InitLogOnShutdownWhileLocked();
boriay826ae202016-07-05 17:15:29 +0900274
François Degrosbbe88cc2018-01-05 07:54:17 +0900275 HistogramMap histograms_;
276 CallbackMap callbacks_;
277 RangesMap ranges_;
278 HistogramProviders providers_;
279 std::unique_ptr<RecordHistogramChecker> record_checker_;
bcwhiteb9b48bb2016-04-09 02:38:29 +0900280
François Degrosbbe88cc2018-01-05 07:54:17 +0900281 // Previous global recorder that existed when this one was created.
282 StatisticsRecorder* previous_ = nullptr;
boriay826ae202016-07-05 17:15:29 +0900283
François Degrosbbe88cc2018-01-05 07:54:17 +0900284 // Global lock for internal synchronization.
285 static LazyInstance<Lock>::Leaky lock_;
tonyg@chromium.org4af92962013-05-02 12:09:25 +0900286
François Degrosbbe88cc2018-01-05 07:54:17 +0900287 // Current global recorder. This recorder is used by static methods. When a
288 // new global recorder is created by CreateTemporaryForTesting(), then the
289 // previous global recorder is referenced by top_->previous_.
290 static StatisticsRecorder* top_;
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +0900291
François Degrosbbe88cc2018-01-05 07:54:17 +0900292 // Tracks whether InitLogOnShutdownWhileLocked() has registered a logging
293 // function that will be called when the program finishes.
294 static bool is_vlog_initialized_;
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +0900295
kaiwang@chromium.org3c57dc62012-07-14 06:48:29 +0900296 DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder);
297};
298
299} // namespace base
300
301#endif // BASE_METRICS_STATISTICS_RECORDER_H_