|
1 // Copyright (c) 2011 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 // Histogram is an object that aggregates statistics, and can summarize them in |
|
6 // various forms, including ASCII graphical, HTML, and numerically (as a |
|
7 // vector of numbers corresponding to each of the aggregating buckets). |
|
8 |
|
9 // It supports calls to accumulate either time intervals (which are processed |
|
10 // as integral number of milliseconds), or arbitrary integral units. |
|
11 |
|
12 // The default layout of buckets is exponential. For example, buckets might |
|
13 // contain (sequentially) the count of values in the following intervals: |
|
14 // [0,1), [1,2), [2,4), [4,8), [8,16), [16,32), [32,64), [64,infinity) |
|
15 // That bucket allocation would actually result from construction of a histogram |
|
16 // for values between 1 and 64, with 8 buckets, such as: |
|
17 // Histogram count(L"some name", 1, 64, 8); |
|
18 // Note that the underflow bucket [0,1) and the overflow bucket [64,infinity) |
|
19 // are not counted by the constructor in the user supplied "bucket_count" |
|
20 // argument. |
|
21 // The above example has an exponential ratio of 2 (doubling the bucket width |
|
22 // in each consecutive bucket. The Histogram class automatically calculates |
|
23 // the smallest ratio that it can use to construct the number of buckets |
|
24 // selected in the constructor. An another example, if you had 50 buckets, |
|
25 // and millisecond time values from 1 to 10000, then the ratio between |
|
26 // consecutive bucket widths will be approximately somewhere around the 50th |
|
27 // root of 10000. This approach provides very fine grain (narrow) buckets |
|
28 // at the low end of the histogram scale, but allows the histogram to cover a |
|
29 // gigantic range with the addition of very few buckets. |
|
30 |
|
31 // Histograms use a pattern involving a function static variable, that is a |
|
32 // pointer to a histogram. This static is explicitly initialized on any thread |
|
33 // that detects a uninitialized (NULL) pointer. The potentially racy |
|
34 // initialization is not a problem as it is always set to point to the same |
|
35 // value (i.e., the FactoryGet always returns the same value). FactoryGet |
|
36 // is also completely thread safe, which results in a completely thread safe, |
|
37 // and relatively fast, set of counters. To avoid races at shutdown, the static |
|
38 // pointer is NOT deleted, and we leak the histograms at process termination. |
|
39 |
|
40 #ifndef BASE_METRICS_HISTOGRAM_H_ |
|
41 #define BASE_METRICS_HISTOGRAM_H_ |
|
42 #pragma once |
|
43 |
|
44 #include "mozilla/MemoryReporting.h" |
|
45 |
|
46 #include <map> |
|
47 #include <string> |
|
48 #include <vector> |
|
49 |
|
50 #include "base/time.h" |
|
51 #include "base/lock.h" |
|
52 |
|
53 class Pickle; |
|
54 |
|
55 namespace base { |
|
56 //------------------------------------------------------------------------------ |
|
57 // Provide easy general purpose histogram in a macro, just like stats counters. |
|
58 // The first four macros use 50 buckets. |
|
59 |
|
60 #define HISTOGRAM_TIMES(name, sample) HISTOGRAM_CUSTOM_TIMES( \ |
|
61 name, sample, base::TimeDelta::FromMilliseconds(1), \ |
|
62 base::TimeDelta::FromSeconds(10), 50) |
|
63 |
|
64 #define HISTOGRAM_COUNTS(name, sample) HISTOGRAM_CUSTOM_COUNTS( \ |
|
65 name, sample, 1, 1000000, 50) |
|
66 |
|
67 #define HISTOGRAM_COUNTS_100(name, sample) HISTOGRAM_CUSTOM_COUNTS( \ |
|
68 name, sample, 1, 100, 50) |
|
69 |
|
70 #define HISTOGRAM_COUNTS_10000(name, sample) HISTOGRAM_CUSTOM_COUNTS( \ |
|
71 name, sample, 1, 10000, 50) |
|
72 |
|
73 #define HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \ |
|
74 static base::Histogram* counter(NULL); \ |
|
75 if (!counter) \ |
|
76 counter = base::Histogram::FactoryGet(name, min, max, bucket_count, \ |
|
77 base::Histogram::kNoFlags); \ |
|
78 DCHECK_EQ(name, counter->histogram_name()); \ |
|
79 counter->Add(sample); \ |
|
80 } while (0) |
|
81 |
|
82 #define HISTOGRAM_PERCENTAGE(name, under_one_hundred) \ |
|
83 HISTOGRAM_ENUMERATION(name, under_one_hundred, 101) |
|
84 |
|
85 // For folks that need real specific times, use this to select a precise range |
|
86 // of times you want plotted, and the number of buckets you want used. |
|
87 #define HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \ |
|
88 static base::Histogram* counter(NULL); \ |
|
89 if (!counter) \ |
|
90 counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ |
|
91 base::Histogram::kNoFlags); \ |
|
92 DCHECK_EQ(name, counter->histogram_name()); \ |
|
93 counter->AddTime(sample); \ |
|
94 } while (0) |
|
95 |
|
96 // DO NOT USE THIS. It is being phased out, in favor of HISTOGRAM_CUSTOM_TIMES. |
|
97 #define HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \ |
|
98 static base::Histogram* counter(NULL); \ |
|
99 if (!counter) \ |
|
100 counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ |
|
101 base::Histogram::kNoFlags); \ |
|
102 DCHECK_EQ(name, counter->histogram_name()); \ |
|
103 if ((sample) < (max)) counter->AddTime(sample); \ |
|
104 } while (0) |
|
105 |
|
106 // Support histograming of an enumerated value. The samples should always be |
|
107 // less than boundary_value. |
|
108 |
|
109 #define HISTOGRAM_ENUMERATION(name, sample, boundary_value) do { \ |
|
110 static base::Histogram* counter(NULL); \ |
|
111 if (!counter) \ |
|
112 counter = base::LinearHistogram::FactoryGet(name, 1, boundary_value, \ |
|
113 boundary_value + 1, base::Histogram::kNoFlags); \ |
|
114 DCHECK_EQ(name, counter->histogram_name()); \ |
|
115 counter->Add(sample); \ |
|
116 } while (0) |
|
117 |
|
118 #define HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) do { \ |
|
119 static base::Histogram* counter(NULL); \ |
|
120 if (!counter) \ |
|
121 counter = base::CustomHistogram::FactoryGet(name, custom_ranges, \ |
|
122 base::Histogram::kNoFlags); \ |
|
123 DCHECK_EQ(name, counter->histogram_name()); \ |
|
124 counter->Add(sample); \ |
|
125 } while (0) |
|
126 |
|
127 |
|
128 //------------------------------------------------------------------------------ |
|
129 // Define Debug vs non-debug flavors of macros. |
|
130 #ifndef NDEBUG |
|
131 |
|
132 #define DHISTOGRAM_TIMES(name, sample) HISTOGRAM_TIMES(name, sample) |
|
133 #define DHISTOGRAM_COUNTS(name, sample) HISTOGRAM_COUNTS(name, sample) |
|
134 #define DHISTOGRAM_PERCENTAGE(name, under_one_hundred) HISTOGRAM_PERCENTAGE(\ |
|
135 name, under_one_hundred) |
|
136 #define DHISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \ |
|
137 HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) |
|
138 #define DHISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) \ |
|
139 HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) |
|
140 #define DHISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \ |
|
141 HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) |
|
142 #define DHISTOGRAM_ENUMERATION(name, sample, boundary_value) \ |
|
143 HISTOGRAM_ENUMERATION(name, sample, boundary_value) |
|
144 #define DHISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \ |
|
145 HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) |
|
146 |
|
147 #else // NDEBUG |
|
148 |
|
149 #define DHISTOGRAM_TIMES(name, sample) do {} while (0) |
|
150 #define DHISTOGRAM_COUNTS(name, sample) do {} while (0) |
|
151 #define DHISTOGRAM_PERCENTAGE(name, under_one_hundred) do {} while (0) |
|
152 #define DHISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \ |
|
153 do {} while (0) |
|
154 #define DHISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) \ |
|
155 do {} while (0) |
|
156 #define DHISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \ |
|
157 do {} while (0) |
|
158 #define DHISTOGRAM_ENUMERATION(name, sample, boundary_value) do {} while (0) |
|
159 #define DHISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \ |
|
160 do {} while (0) |
|
161 |
|
162 #endif // NDEBUG |
|
163 |
|
164 //------------------------------------------------------------------------------ |
|
165 // The following macros provide typical usage scenarios for callers that wish |
|
166 // to record histogram data, and have the data submitted/uploaded via UMA. |
|
167 // Not all systems support such UMA, but if they do, the following macros |
|
168 // should work with the service. |
|
169 |
|
170 #define UMA_HISTOGRAM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \ |
|
171 name, sample, base::TimeDelta::FromMilliseconds(1), \ |
|
172 base::TimeDelta::FromSeconds(10), 50) |
|
173 |
|
174 #define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \ |
|
175 name, sample, base::TimeDelta::FromMilliseconds(10), \ |
|
176 base::TimeDelta::FromMinutes(3), 50) |
|
177 |
|
178 // Use this macro when times can routinely be much longer than 10 seconds. |
|
179 #define UMA_HISTOGRAM_LONG_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \ |
|
180 name, sample, base::TimeDelta::FromMilliseconds(1), \ |
|
181 base::TimeDelta::FromHours(1), 50) |
|
182 |
|
183 #define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \ |
|
184 static base::Histogram* counter(NULL); \ |
|
185 if (!counter) \ |
|
186 counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ |
|
187 base::Histogram::kUmaTargetedHistogramFlag); \ |
|
188 DCHECK_EQ(name, counter->histogram_name()); \ |
|
189 counter->AddTime(sample); \ |
|
190 } while (0) |
|
191 |
|
192 // DO NOT USE THIS. It is being phased out, in favor of HISTOGRAM_CUSTOM_TIMES. |
|
193 #define UMA_HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \ |
|
194 static base::Histogram* counter(NULL); \ |
|
195 if (!counter) \ |
|
196 counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ |
|
197 base::Histogram::kUmaTargetedHistogramFlag); \ |
|
198 DCHECK_EQ(name, counter->histogram_name()); \ |
|
199 if ((sample) < (max)) counter->AddTime(sample); \ |
|
200 } while (0) |
|
201 |
|
202 #define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
|
203 name, sample, 1, 1000000, 50) |
|
204 |
|
205 #define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
|
206 name, sample, 1, 100, 50) |
|
207 |
|
208 #define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
|
209 name, sample, 1, 10000, 50) |
|
210 |
|
211 #define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \ |
|
212 static base::Histogram* counter(NULL); \ |
|
213 if (!counter) \ |
|
214 counter = base::Histogram::FactoryGet(name, min, max, bucket_count, \ |
|
215 base::Histogram::kUmaTargetedHistogramFlag); \ |
|
216 DCHECK_EQ(name, counter->histogram_name()); \ |
|
217 counter->Add(sample); \ |
|
218 } while (0) |
|
219 |
|
220 #define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
|
221 name, sample, 1000, 500000, 50) |
|
222 |
|
223 #define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
|
224 name, sample, 1, 1000, 50) |
|
225 |
|
226 #define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \ |
|
227 UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101) |
|
228 |
|
229 #define UMA_HISTOGRAM_BOOLEAN(name, sample) do { \ |
|
230 static base::Histogram* counter(NULL); \ |
|
231 if (!counter) \ |
|
232 counter = base::BooleanHistogram::FactoryGet(name, \ |
|
233 base::Histogram::kUmaTargetedHistogramFlag); \ |
|
234 DCHECK_EQ(name, counter->histogram_name()); \ |
|
235 counter->AddBoolean(sample); \ |
|
236 } while (0) |
|
237 |
|
238 #define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) do { \ |
|
239 static base::Histogram* counter(NULL); \ |
|
240 if (!counter) \ |
|
241 counter = base::LinearHistogram::FactoryGet(name, 1, boundary_value, \ |
|
242 boundary_value + 1, base::Histogram::kUmaTargetedHistogramFlag); \ |
|
243 DCHECK_EQ(name, counter->histogram_name()); \ |
|
244 counter->Add(sample); \ |
|
245 } while (0) |
|
246 |
|
247 #define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) do { \ |
|
248 static base::Histogram* counter(NULL); \ |
|
249 if (!counter) \ |
|
250 counter = base::CustomHistogram::FactoryGet(name, custom_ranges, \ |
|
251 base::Histogram::kUmaTargetedHistogramFlag); \ |
|
252 DCHECK_EQ(name, counter->histogram_name()); \ |
|
253 counter->Add(sample); \ |
|
254 } while (0) |
|
255 |
|
256 //------------------------------------------------------------------------------ |
|
257 |
|
258 class BooleanHistogram; |
|
259 class CustomHistogram; |
|
260 class Histogram; |
|
261 class LinearHistogram; |
|
262 |
|
263 class Histogram { |
|
264 public: |
|
265 typedef int Sample; // Used for samples (and ranges of samples). |
|
266 typedef int Count; // Used to count samples in a bucket. |
|
267 static const Sample kSampleType_MAX = INT_MAX; |
|
268 // Initialize maximum number of buckets in histograms as 16,384. |
|
269 static const size_t kBucketCount_MAX; |
|
270 |
|
271 typedef std::vector<Count> Counts; |
|
272 typedef std::vector<Sample> Ranges; |
|
273 |
|
274 // These enums are used to facilitate deserialization of renderer histograms |
|
275 // into the browser. |
|
276 enum ClassType { |
|
277 HISTOGRAM, |
|
278 LINEAR_HISTOGRAM, |
|
279 BOOLEAN_HISTOGRAM, |
|
280 FLAG_HISTOGRAM, |
|
281 CUSTOM_HISTOGRAM, |
|
282 NOT_VALID_IN_RENDERER |
|
283 }; |
|
284 |
|
285 enum BucketLayout { |
|
286 EXPONENTIAL, |
|
287 LINEAR, |
|
288 CUSTOM |
|
289 }; |
|
290 |
|
291 enum Flags { |
|
292 kNoFlags = 0, |
|
293 kUmaTargetedHistogramFlag = 0x1, // Histogram should be UMA uploaded. |
|
294 kExtendedStatisticsFlag = 0x2, // OK to gather extended statistics on histograms. |
|
295 |
|
296 // Indicate that the histogram was pickled to be sent across an IPC Channel. |
|
297 // If we observe this flag on a histogram being aggregated into after IPC, |
|
298 // then we are running in a single process mode, and the aggregation should |
|
299 // not take place (as we would be aggregating back into the source |
|
300 // histogram!). |
|
301 kIPCSerializationSourceFlag = 0x10, |
|
302 |
|
303 kHexRangePrintingFlag = 0x8000 // Fancy bucket-naming supported. |
|
304 }; |
|
305 |
|
306 enum Inconsistencies { |
|
307 NO_INCONSISTENCIES = 0x0, |
|
308 RANGE_CHECKSUM_ERROR = 0x1, |
|
309 BUCKET_ORDER_ERROR = 0x2, |
|
310 COUNT_HIGH_ERROR = 0x4, |
|
311 COUNT_LOW_ERROR = 0x8, |
|
312 |
|
313 NEVER_EXCEEDED_VALUE = 0x10 |
|
314 }; |
|
315 |
|
316 struct DescriptionPair { |
|
317 Sample sample; |
|
318 const char* description; // Null means end of a list of pairs. |
|
319 }; |
|
320 |
|
321 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf); |
|
322 |
|
323 //---------------------------------------------------------------------------- |
|
324 // Statistic values, developed over the life of the histogram. |
|
325 |
|
326 class SampleSet { |
|
327 public: |
|
328 explicit SampleSet(); |
|
329 ~SampleSet(); |
|
330 |
|
331 // Adjust size of counts_ for use with given histogram. |
|
332 void Resize(const Histogram& histogram); |
|
333 void CheckSize(const Histogram& histogram) const; |
|
334 |
|
335 // Accessor for histogram to make routine additions. |
|
336 void AccumulateWithLinearStats(Sample value, Count count, size_t index); |
|
337 // Alternate routine for exponential histograms. |
|
338 // computeExpensiveStatistics should be true if we want to compute log sums. |
|
339 void AccumulateWithExponentialStats(Sample value, Count count, size_t index, |
|
340 bool computeExtendedStatistics); |
|
341 |
|
342 // Accessor methods. |
|
343 Count counts(size_t i) const { return counts_[i]; } |
|
344 Count TotalCount() const; |
|
345 int64_t sum() const { return sum_; } |
|
346 uint64_t sum_squares() const { return sum_squares_; } |
|
347 double log_sum() const { return log_sum_; } |
|
348 double log_sum_squares() const { return log_sum_squares_; } |
|
349 int64_t redundant_count() const { return redundant_count_; } |
|
350 size_t size() const { return counts_.size(); } |
|
351 |
|
352 // Arithmetic manipulation of corresponding elements of the set. |
|
353 void Add(const SampleSet& other); |
|
354 void Subtract(const SampleSet& other); |
|
355 |
|
356 bool Serialize(Pickle* pickle) const; |
|
357 bool Deserialize(void** iter, const Pickle& pickle); |
|
358 |
|
359 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf); |
|
360 |
|
361 protected: |
|
362 // Actual histogram data is stored in buckets, showing the count of values |
|
363 // that fit into each bucket. |
|
364 Counts counts_; |
|
365 |
|
366 // Save simple stats locally. Note that this MIGHT get done in base class |
|
367 // without shared memory at some point. |
|
368 int64_t sum_; // sum of samples. |
|
369 uint64_t sum_squares_; // sum of squares of samples. |
|
370 |
|
371 // These fields may or may not be updated at the discretion of the |
|
372 // histogram. We use the natural log and compute ln(sample+1) so that |
|
373 // zeros are handled sanely. |
|
374 double log_sum_; // sum of logs of samples. |
|
375 double log_sum_squares_; // sum of squares of logs of samples |
|
376 |
|
377 private: |
|
378 void Accumulate(Sample value, Count count, size_t index); |
|
379 |
|
380 // To help identify memory corruption, we reduntantly save the number of |
|
381 // samples we've accumulated into all of our buckets. We can compare this |
|
382 // count to the sum of the counts in all buckets, and detect problems. Note |
|
383 // that due to races in histogram accumulation (if a histogram is indeed |
|
384 // updated on several threads simultaneously), the tallies might mismatch, |
|
385 // and also the snapshotting code may asynchronously get a mismatch (though |
|
386 // generally either race based mismatch cause is VERY rare). |
|
387 int64_t redundant_count_; |
|
388 }; |
|
389 |
|
390 //---------------------------------------------------------------------------- |
|
391 // minimum should start from 1. 0 is invalid as a minimum. 0 is an implicit |
|
392 // default underflow bucket. |
|
393 static Histogram* FactoryGet(const std::string& name, |
|
394 Sample minimum, |
|
395 Sample maximum, |
|
396 size_t bucket_count, |
|
397 Flags flags); |
|
398 static Histogram* FactoryTimeGet(const std::string& name, |
|
399 base::TimeDelta minimum, |
|
400 base::TimeDelta maximum, |
|
401 size_t bucket_count, |
|
402 Flags flags); |
|
403 |
|
404 void Add(int value); |
|
405 void Subtract(int value); |
|
406 |
|
407 // This method is an interface, used only by BooleanHistogram. |
|
408 virtual void AddBoolean(bool value); |
|
409 |
|
410 // Accept a TimeDelta to increment. |
|
411 void AddTime(TimeDelta time) { |
|
412 Add(static_cast<int>(time.InMilliseconds())); |
|
413 } |
|
414 |
|
415 virtual void AddSampleSet(const SampleSet& sample); |
|
416 |
|
417 void Clear(); |
|
418 |
|
419 // This method is an interface, used only by LinearHistogram. |
|
420 virtual void SetRangeDescriptions(const DescriptionPair descriptions[]); |
|
421 |
|
422 // The following methods provide graphical histogram displays. |
|
423 void WriteHTMLGraph(std::string* output) const; |
|
424 void WriteAscii(bool graph_it, const std::string& newline, |
|
425 std::string* output) const; |
|
426 |
|
427 // Support generic flagging of Histograms. |
|
428 // 0x1 Currently used to mark this histogram to be recorded by UMA.. |
|
429 // 0x8000 means print ranges in hex. |
|
430 void SetFlags(Flags flags) { flags_ = static_cast<Flags> (flags_ | flags); } |
|
431 void ClearFlags(Flags flags) { flags_ = static_cast<Flags>(flags_ & ~flags); } |
|
432 int flags() const { return flags_; } |
|
433 |
|
434 // Convenience methods for serializing/deserializing the histograms. |
|
435 // Histograms from Renderer process are serialized and sent to the browser. |
|
436 // Browser process reconstructs the histogram from the pickled version |
|
437 // accumulates the browser-side shadow copy of histograms (that mirror |
|
438 // histograms created in the renderer). |
|
439 |
|
440 // Serialize the given snapshot of a Histogram into a String. Uses |
|
441 // Pickle class to flatten the object. |
|
442 static std::string SerializeHistogramInfo(const Histogram& histogram, |
|
443 const SampleSet& snapshot); |
|
444 // The following method accepts a list of pickled histograms and |
|
445 // builds a histogram and updates shadow copy of histogram data in the |
|
446 // browser process. |
|
447 static bool DeserializeHistogramInfo(const std::string& histogram_info); |
|
448 |
|
449 // Check to see if bucket ranges, counts and tallies in the snapshot are |
|
450 // consistent with the bucket ranges and checksums in our histogram. This can |
|
451 // produce a false-alarm if a race occurred in the reading of the data during |
|
452 // a SnapShot process, but should otherwise be false at all times (unless we |
|
453 // have memory over-writes, or DRAM failures). |
|
454 virtual Inconsistencies FindCorruption(const SampleSet& snapshot) const; |
|
455 |
|
456 //---------------------------------------------------------------------------- |
|
457 // Accessors for factory constuction, serialization and testing. |
|
458 //---------------------------------------------------------------------------- |
|
459 virtual ClassType histogram_type() const; |
|
460 const std::string& histogram_name() const { return histogram_name_; } |
|
461 Sample declared_min() const { return declared_min_; } |
|
462 Sample declared_max() const { return declared_max_; } |
|
463 virtual Sample ranges(size_t i) const; |
|
464 uint32_t range_checksum() const { return range_checksum_; } |
|
465 virtual size_t bucket_count() const; |
|
466 // Snapshot the current complete set of sample data. |
|
467 // Override with atomic/locked snapshot if needed. |
|
468 virtual void SnapshotSample(SampleSet* sample) const; |
|
469 |
|
470 virtual bool HasConstructorArguments(Sample minimum, Sample maximum, |
|
471 size_t bucket_count); |
|
472 |
|
473 virtual bool HasConstructorTimeDeltaArguments(TimeDelta minimum, |
|
474 TimeDelta maximum, |
|
475 size_t bucket_count); |
|
476 // Return true iff the range_checksum_ matches current ranges_ vector. |
|
477 bool HasValidRangeChecksum() const; |
|
478 |
|
479 protected: |
|
480 Histogram(const std::string& name, Sample minimum, |
|
481 Sample maximum, size_t bucket_count); |
|
482 Histogram(const std::string& name, TimeDelta minimum, |
|
483 TimeDelta maximum, size_t bucket_count); |
|
484 |
|
485 virtual ~Histogram(); |
|
486 |
|
487 // Initialize ranges_ mapping. |
|
488 void InitializeBucketRange(); |
|
489 |
|
490 // Method to override to skip the display of the i'th bucket if it's empty. |
|
491 virtual bool PrintEmptyBucket(size_t index) const; |
|
492 |
|
493 //---------------------------------------------------------------------------- |
|
494 // Methods to override to create histogram with different bucket widths. |
|
495 //---------------------------------------------------------------------------- |
|
496 // Find bucket to increment for sample value. |
|
497 virtual size_t BucketIndex(Sample value) const; |
|
498 // Get normalized size, relative to the ranges_[i]. |
|
499 virtual double GetBucketSize(Count current, size_t i) const; |
|
500 |
|
501 // Recalculate range_checksum_. |
|
502 void ResetRangeChecksum(); |
|
503 |
|
504 // Return a string description of what goes in a given bucket. |
|
505 // Most commonly this is the numeric value, but in derived classes it may |
|
506 // be a name (or string description) given to the bucket. |
|
507 virtual const std::string GetAsciiBucketRange(size_t it) const; |
|
508 |
|
509 //---------------------------------------------------------------------------- |
|
510 // Methods to override to create thread safe histogram. |
|
511 //---------------------------------------------------------------------------- |
|
512 // Update all our internal data, including histogram |
|
513 virtual void Accumulate(Sample value, Count count, size_t index); |
|
514 |
|
515 //---------------------------------------------------------------------------- |
|
516 // Accessors for derived classes. |
|
517 //---------------------------------------------------------------------------- |
|
518 void SetBucketRange(size_t i, Sample value); |
|
519 |
|
520 // Validate that ranges_ was created sensibly (top and bottom range |
|
521 // values relate properly to the declared_min_ and declared_max_).. |
|
522 bool ValidateBucketRanges() const; |
|
523 |
|
524 virtual uint32_t CalculateRangeChecksum() const; |
|
525 |
|
526 // Finally, provide the state that changes with the addition of each new |
|
527 // sample. |
|
528 SampleSet sample_; |
|
529 |
|
530 private: |
|
531 friend class StatisticsRecorder; // To allow it to delete duplicates. |
|
532 |
|
533 // Post constructor initialization. |
|
534 void Initialize(); |
|
535 |
|
536 // Checksum function for accumulating range values into a checksum. |
|
537 static uint32_t Crc32(uint32_t sum, Sample range); |
|
538 |
|
539 //---------------------------------------------------------------------------- |
|
540 // Helpers for emitting Ascii graphic. Each method appends data to output. |
|
541 |
|
542 // Find out how large the (graphically) the largest bucket will appear to be. |
|
543 double GetPeakBucketSize(const SampleSet& snapshot) const; |
|
544 |
|
545 // Write a common header message describing this histogram. |
|
546 void WriteAsciiHeader(const SampleSet& snapshot, |
|
547 Count sample_count, std::string* output) const; |
|
548 |
|
549 // Write information about previous, current, and next buckets. |
|
550 // Information such as cumulative percentage, etc. |
|
551 void WriteAsciiBucketContext(const int64_t past, const Count current, |
|
552 const int64_t remaining, const size_t i, |
|
553 std::string* output) const; |
|
554 |
|
555 // Write textual description of the bucket contents (relative to histogram). |
|
556 // Output is the count in the buckets, as well as the percentage. |
|
557 void WriteAsciiBucketValue(Count current, double scaled_sum, |
|
558 std::string* output) const; |
|
559 |
|
560 // Produce actual graph (set of blank vs non blank char's) for a bucket. |
|
561 void WriteAsciiBucketGraph(double current_size, double max_size, |
|
562 std::string* output) const; |
|
563 |
|
564 //---------------------------------------------------------------------------- |
|
565 // Table for generating Crc32 values. |
|
566 static const uint32_t kCrcTable[256]; |
|
567 //---------------------------------------------------------------------------- |
|
568 // Invariant values set at/near construction time |
|
569 |
|
570 // ASCII version of original name given to the constructor. All identically |
|
571 // named instances will be coalesced cross-project. |
|
572 const std::string histogram_name_; |
|
573 Sample declared_min_; // Less than this goes into counts_[0] |
|
574 Sample declared_max_; // Over this goes into counts_[bucket_count_ - 1]. |
|
575 size_t bucket_count_; // Dimension of counts_[]. |
|
576 |
|
577 // Flag the histogram for recording by UMA via metric_services.h. |
|
578 Flags flags_; |
|
579 |
|
580 // For each index, show the least value that can be stored in the |
|
581 // corresponding bucket. We also append one extra element in this array, |
|
582 // containing kSampleType_MAX, to make calculations easy. |
|
583 // The dimension of ranges_ is bucket_count + 1. |
|
584 Ranges ranges_; |
|
585 |
|
586 // For redundancy, we store a checksum of all the sample ranges when ranges |
|
587 // are generated. If ever there is ever a difference, then the histogram must |
|
588 // have been corrupted. |
|
589 uint32_t range_checksum_; |
|
590 |
|
591 DISALLOW_COPY_AND_ASSIGN(Histogram); |
|
592 }; |
|
593 |
|
594 //------------------------------------------------------------------------------ |
|
595 |
|
596 // LinearHistogram is a more traditional histogram, with evenly spaced |
|
597 // buckets. |
|
598 class LinearHistogram : public Histogram { |
|
599 public: |
|
600 virtual ~LinearHistogram(); |
|
601 |
|
602 /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit |
|
603 default underflow bucket. */ |
|
604 static Histogram* FactoryGet(const std::string& name, |
|
605 Sample minimum, |
|
606 Sample maximum, |
|
607 size_t bucket_count, |
|
608 Flags flags); |
|
609 static Histogram* FactoryTimeGet(const std::string& name, |
|
610 TimeDelta minimum, |
|
611 TimeDelta maximum, |
|
612 size_t bucket_count, |
|
613 Flags flags); |
|
614 |
|
615 // Overridden from Histogram: |
|
616 virtual ClassType histogram_type() const; |
|
617 |
|
618 virtual void Accumulate(Sample value, Count count, size_t index); |
|
619 |
|
620 // Store a list of number/text values for use in rendering the histogram. |
|
621 // The last element in the array has a null in its "description" slot. |
|
622 virtual void SetRangeDescriptions(const DescriptionPair descriptions[]); |
|
623 |
|
624 protected: |
|
625 LinearHistogram(const std::string& name, Sample minimum, |
|
626 Sample maximum, size_t bucket_count); |
|
627 |
|
628 LinearHistogram(const std::string& name, TimeDelta minimum, |
|
629 TimeDelta maximum, size_t bucket_count); |
|
630 |
|
631 // Initialize ranges_ mapping. |
|
632 void InitializeBucketRange(); |
|
633 virtual double GetBucketSize(Count current, size_t i) const; |
|
634 |
|
635 // If we have a description for a bucket, then return that. Otherwise |
|
636 // let parent class provide a (numeric) description. |
|
637 virtual const std::string GetAsciiBucketRange(size_t i) const; |
|
638 |
|
639 // Skip printing of name for numeric range if we have a name (and if this is |
|
640 // an empty bucket). |
|
641 virtual bool PrintEmptyBucket(size_t index) const; |
|
642 |
|
643 private: |
|
644 // For some ranges, we store a printable description of a bucket range. |
|
645 // If there is no desciption, then GetAsciiBucketRange() uses parent class |
|
646 // to provide a description. |
|
647 typedef std::map<Sample, std::string> BucketDescriptionMap; |
|
648 BucketDescriptionMap bucket_description_; |
|
649 |
|
650 DISALLOW_COPY_AND_ASSIGN(LinearHistogram); |
|
651 }; |
|
652 |
|
653 //------------------------------------------------------------------------------ |
|
654 |
|
655 // BooleanHistogram is a histogram for booleans. |
|
656 class BooleanHistogram : public LinearHistogram { |
|
657 public: |
|
658 static Histogram* FactoryGet(const std::string& name, Flags flags); |
|
659 |
|
660 virtual ClassType histogram_type() const; |
|
661 |
|
662 virtual void AddBoolean(bool value); |
|
663 |
|
664 virtual void Accumulate(Sample value, Count count, size_t index); |
|
665 |
|
666 protected: |
|
667 explicit BooleanHistogram(const std::string& name); |
|
668 |
|
669 DISALLOW_COPY_AND_ASSIGN(BooleanHistogram); |
|
670 }; |
|
671 |
|
672 //------------------------------------------------------------------------------ |
|
673 |
|
674 // FlagHistogram is like boolean histogram, but only allows a single off/on value. |
|
675 class FlagHistogram : public BooleanHistogram |
|
676 { |
|
677 public: |
|
678 static Histogram *FactoryGet(const std::string &name, Flags flags); |
|
679 |
|
680 virtual ClassType histogram_type() const; |
|
681 |
|
682 virtual void Accumulate(Sample value, Count count, size_t index); |
|
683 |
|
684 virtual void AddSampleSet(const SampleSet& sample); |
|
685 |
|
686 private: |
|
687 explicit FlagHistogram(const std::string &name); |
|
688 bool mSwitched; |
|
689 |
|
690 DISALLOW_COPY_AND_ASSIGN(FlagHistogram); |
|
691 }; |
|
692 |
|
693 //------------------------------------------------------------------------------ |
|
694 |
|
695 // CustomHistogram is a histogram for a set of custom integers. |
|
696 class CustomHistogram : public Histogram { |
|
697 public: |
|
698 |
|
699 static Histogram* FactoryGet(const std::string& name, |
|
700 const std::vector<Sample>& custom_ranges, |
|
701 Flags flags); |
|
702 |
|
703 // Overridden from Histogram: |
|
704 virtual ClassType histogram_type() const; |
|
705 |
|
706 protected: |
|
707 CustomHistogram(const std::string& name, |
|
708 const std::vector<Sample>& custom_ranges); |
|
709 |
|
710 // Initialize ranges_ mapping. |
|
711 void InitializedCustomBucketRange(const std::vector<Sample>& custom_ranges); |
|
712 virtual double GetBucketSize(Count current, size_t i) const; |
|
713 |
|
714 DISALLOW_COPY_AND_ASSIGN(CustomHistogram); |
|
715 }; |
|
716 |
|
717 //------------------------------------------------------------------------------ |
|
718 // StatisticsRecorder handles all histograms in the system. It provides a |
|
719 // general place for histograms to register, and supports a global API for |
|
720 // accessing (i.e., dumping, or graphing) the data in all the histograms. |
|
721 |
|
722 class StatisticsRecorder { |
|
723 public: |
|
724 typedef std::vector<Histogram*> Histograms; |
|
725 |
|
726 StatisticsRecorder(); |
|
727 |
|
728 ~StatisticsRecorder(); |
|
729 |
|
730 // Find out if histograms can now be registered into our list. |
|
731 static bool IsActive(); |
|
732 |
|
733 // Register, or add a new histogram to the collection of statistics. If an |
|
734 // identically named histogram is already registered, then the argument |
|
735 // |histogram| will deleted. The returned value is always the registered |
|
736 // histogram (either the argument, or the pre-existing registered histogram). |
|
737 static Histogram* RegisterOrDeleteDuplicate(Histogram* histogram); |
|
738 |
|
739 // Methods for printing histograms. Only histograms which have query as |
|
740 // a substring are written to output (an empty string will process all |
|
741 // registered histograms). |
|
742 static void WriteHTMLGraph(const std::string& query, std::string* output); |
|
743 static void WriteGraph(const std::string& query, std::string* output); |
|
744 |
|
745 // Method for extracting histograms which were marked for use by UMA. |
|
746 static void GetHistograms(Histograms* output); |
|
747 |
|
748 // Find a histogram by name. It matches the exact name. This method is thread |
|
749 // safe. If a matching histogram is not found, then the |histogram| is |
|
750 // not changed. |
|
751 static bool FindHistogram(const std::string& query, Histogram** histogram); |
|
752 |
|
753 static bool dump_on_exit() { return dump_on_exit_; } |
|
754 |
|
755 static void set_dump_on_exit(bool enable) { dump_on_exit_ = enable; } |
|
756 |
|
757 // GetSnapshot copies some of the pointers to registered histograms into the |
|
758 // caller supplied vector (Histograms). Only histograms with names matching |
|
759 // query are returned. The query must be a substring of histogram name for its |
|
760 // pointer to be copied. |
|
761 static void GetSnapshot(const std::string& query, Histograms* snapshot); |
|
762 |
|
763 |
|
764 private: |
|
765 // We keep all registered histograms in a map, from name to histogram. |
|
766 typedef std::map<std::string, Histogram*> HistogramMap; |
|
767 |
|
768 static HistogramMap* histograms_; |
|
769 |
|
770 // lock protects access to the above map. |
|
771 static Lock* lock_; |
|
772 |
|
773 // Dump all known histograms to log. |
|
774 static bool dump_on_exit_; |
|
775 |
|
776 DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder); |
|
777 }; |
|
778 |
|
779 } // namespace base |
|
780 |
|
781 #endif // BASE_METRICS_HISTOGRAM_H_ |