OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Histogram is an object that aggregates statistics, and can summarize them in | 5 // Histogram is an object that aggregates statistics, and can summarize them in |
6 // various forms, including ASCII graphical, HTML, and numerically (as a | 6 // various forms, including ASCII graphical, HTML, and numerically (as a |
7 // vector of numbers corresponding to each of the aggregating buckets). | 7 // vector of numbers corresponding to each of the aggregating buckets). |
8 // See header file for details and examples. | 8 // See header file for details and examples. |
9 | 9 |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
11 | 11 |
12 #include <math.h> | 12 #include <math.h> |
13 | 13 |
14 #include <algorithm> | 14 #include <algorithm> |
15 #include <string> | 15 #include <string> |
16 | 16 |
17 #include "base/logging.h" | 17 #include "base/logging.h" |
18 #include "base/pickle.h" | 18 #include "base/pickle.h" |
19 #include "base/stringprintf.h" | 19 #include "base/stringprintf.h" |
20 #include "base/synchronization/lock.h" | 20 #include "base/synchronization/lock.h" |
21 | 21 |
22 namespace base { | 22 namespace base { |
23 | 23 |
24 // Static table of checksums for all possible 8 bit bytes. | |
25 const uint32 Histogram::kCrcTable[256] = {0x0, 0x77073096L, 0xee0e612cL, | |
26 0x990951baL, 0x76dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0xedb8832L, | |
27 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x9b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, | |
28 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, | |
29 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, | |
30 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, | |
31 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, | |
32 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, | |
33 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L, | |
34 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, | |
35 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, | |
36 0xb6662d3dL, 0x76dc4190L, 0x1db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, | |
37 0x6b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0xf00f934L, 0x9609a88eL, | |
38 0xe10e9818L, 0x7f6a0dbbL, 0x86d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, | |
39 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, | |
40 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, | |
41 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, | |
42 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, | |
43 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, | |
44 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, | |
45 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, | |
46 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, | |
47 0x9abfb3b6L, 0x3b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x4db2615L, | |
48 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0xd6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, | |
49 0x9309ff9dL, 0xa00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, | |
50 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, | |
51 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, | |
52 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, | |
53 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, | |
54 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL, | |
55 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, | |
56 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, | |
57 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, | |
58 0x26d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x5005713L, 0x95bf4a82L, | |
59 0xe2b87a14L, 0x7bb12baeL, 0xcb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, | |
60 0xbdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, | |
61 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, | |
62 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, | |
63 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, | |
64 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, | |
65 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, | |
66 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, | |
67 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, | |
68 0x2d02ef8dL, | |
69 }; | |
70 | |
24 typedef Histogram::Count Count; | 71 typedef Histogram::Count Count; |
25 | 72 |
26 // static | 73 // static |
27 const size_t Histogram::kBucketCount_MAX = 10000u; | 74 const size_t Histogram::kBucketCount_MAX = 10000u; |
28 | 75 |
29 scoped_refptr<Histogram> Histogram::FactoryGet(const std::string& name, | 76 scoped_refptr<Histogram> Histogram::FactoryGet(const std::string& name, |
30 Sample minimum, Sample maximum, size_t bucket_count, Flags flags) { | 77 Sample minimum, Sample maximum, size_t bucket_count, Flags flags) { |
31 scoped_refptr<Histogram> histogram(NULL); | 78 scoped_refptr<Histogram> histogram(NULL); |
32 | 79 |
33 // Defensive code. | 80 // Defensive code. |
34 if (minimum < 1) | 81 if (minimum < 1) |
35 minimum = 1; | 82 minimum = 1; |
36 if (maximum > kSampleType_MAX - 1) | 83 if (maximum > kSampleType_MAX - 1) |
37 maximum = kSampleType_MAX - 1; | 84 maximum = kSampleType_MAX - 1; |
38 | 85 |
39 if (!StatisticsRecorder::FindHistogram(name, &histogram)) { | 86 if (!StatisticsRecorder::FindHistogram(name, &histogram)) { |
40 histogram = new Histogram(name, minimum, maximum, bucket_count); | 87 histogram = new Histogram(name, minimum, maximum, bucket_count); |
41 StatisticsRecorder::FindHistogram(name, &histogram); | 88 histogram->InitializeBucketRange(); |
89 StatisticsRecorder::Register(&histogram); | |
42 } | 90 } |
43 | 91 |
44 DCHECK_EQ(HISTOGRAM, histogram->histogram_type()); | 92 DCHECK_EQ(HISTOGRAM, histogram->histogram_type()); |
45 DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count)); | 93 DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count)); |
46 histogram->SetFlags(flags); | 94 histogram->SetFlags(flags); |
47 return histogram; | 95 return histogram; |
48 } | 96 } |
49 | 97 |
50 scoped_refptr<Histogram> Histogram::FactoryTimeGet(const std::string& name, | 98 scoped_refptr<Histogram> Histogram::FactoryTimeGet(const std::string& name, |
51 TimeDelta minimum, | 99 TimeDelta minimum, |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
154 // static | 202 // static |
155 std::string Histogram::SerializeHistogramInfo(const Histogram& histogram, | 203 std::string Histogram::SerializeHistogramInfo(const Histogram& histogram, |
156 const SampleSet& snapshot) { | 204 const SampleSet& snapshot) { |
157 DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type()); | 205 DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type()); |
158 | 206 |
159 Pickle pickle; | 207 Pickle pickle; |
160 pickle.WriteString(histogram.histogram_name()); | 208 pickle.WriteString(histogram.histogram_name()); |
161 pickle.WriteInt(histogram.declared_min()); | 209 pickle.WriteInt(histogram.declared_min()); |
162 pickle.WriteInt(histogram.declared_max()); | 210 pickle.WriteInt(histogram.declared_max()); |
163 pickle.WriteSize(histogram.bucket_count()); | 211 pickle.WriteSize(histogram.bucket_count()); |
164 pickle.WriteInt(histogram.range_checksum()); | 212 pickle.WriteUInt32(histogram.range_checksum()); |
165 pickle.WriteInt(histogram.histogram_type()); | 213 pickle.WriteInt(histogram.histogram_type()); |
166 pickle.WriteInt(histogram.flags()); | 214 pickle.WriteInt(histogram.flags()); |
167 | 215 |
168 snapshot.Serialize(&pickle); | 216 snapshot.Serialize(&pickle); |
169 return std::string(static_cast<const char*>(pickle.data()), pickle.size()); | 217 return std::string(static_cast<const char*>(pickle.data()), pickle.size()); |
170 } | 218 } |
171 | 219 |
172 // static | 220 // static |
173 bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) { | 221 bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) { |
174 if (histogram_info.empty()) { | 222 if (histogram_info.empty()) { |
175 return false; | 223 return false; |
176 } | 224 } |
177 | 225 |
178 Pickle pickle(histogram_info.data(), | 226 Pickle pickle(histogram_info.data(), |
179 static_cast<int>(histogram_info.size())); | 227 static_cast<int>(histogram_info.size())); |
180 std::string histogram_name; | 228 std::string histogram_name; |
181 int declared_min; | 229 int declared_min; |
182 int declared_max; | 230 int declared_max; |
183 size_t bucket_count; | 231 size_t bucket_count; |
184 int range_checksum; | 232 uint32 range_checksum; |
185 int histogram_type; | 233 int histogram_type; |
186 int pickle_flags; | 234 int pickle_flags; |
187 SampleSet sample; | 235 SampleSet sample; |
188 | 236 |
189 void* iter = NULL; | 237 void* iter = NULL; |
190 if (!pickle.ReadString(&iter, &histogram_name) || | 238 if (!pickle.ReadString(&iter, &histogram_name) || |
191 !pickle.ReadInt(&iter, &declared_min) || | 239 !pickle.ReadInt(&iter, &declared_min) || |
192 !pickle.ReadInt(&iter, &declared_max) || | 240 !pickle.ReadInt(&iter, &declared_max) || |
193 !pickle.ReadSize(&iter, &bucket_count) || | 241 !pickle.ReadSize(&iter, &bucket_count) || |
194 !pickle.ReadInt(&iter, &range_checksum) || | 242 !pickle.ReadUInt32(&iter, &range_checksum) || |
195 !pickle.ReadInt(&iter, &histogram_type) || | 243 !pickle.ReadInt(&iter, &histogram_type) || |
196 !pickle.ReadInt(&iter, &pickle_flags) || | 244 !pickle.ReadInt(&iter, &pickle_flags) || |
197 !sample.Histogram::SampleSet::Deserialize(&iter, pickle)) { | 245 !sample.Histogram::SampleSet::Deserialize(&iter, pickle)) { |
198 LOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name; | 246 LOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name; |
199 return false; | 247 return false; |
200 } | 248 } |
201 DCHECK(pickle_flags & kIPCSerializationSourceFlag); | 249 DCHECK(pickle_flags & kIPCSerializationSourceFlag); |
202 // Since these fields may have come from an untrusted renderer, do additional | 250 // Since these fields may have come from an untrusted renderer, do additional |
203 // checks above and beyond those in Histogram::Initialize() | 251 // checks above and beyond those in Histogram::Initialize() |
204 if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min || | 252 if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min || |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
245 } | 293 } |
246 | 294 |
247 //------------------------------------------------------------------------------ | 295 //------------------------------------------------------------------------------ |
248 // Methods for the validating a sample and a related histogram. | 296 // Methods for the validating a sample and a related histogram. |
249 //------------------------------------------------------------------------------ | 297 //------------------------------------------------------------------------------ |
250 | 298 |
251 Histogram::Inconsistencies Histogram::FindCorruption( | 299 Histogram::Inconsistencies Histogram::FindCorruption( |
252 const SampleSet& snapshot) const { | 300 const SampleSet& snapshot) const { |
253 int inconsistencies = NO_INCONSISTENCIES; | 301 int inconsistencies = NO_INCONSISTENCIES; |
254 Sample previous_range = -1; // Bottom range is always 0. | 302 Sample previous_range = -1; // Bottom range is always 0. |
255 Sample checksum = 0; | |
256 int64 count = 0; | 303 int64 count = 0; |
257 for (size_t index = 0; index < bucket_count(); ++index) { | 304 for (size_t index = 0; index < bucket_count(); ++index) { |
258 count += snapshot.counts(index); | 305 count += snapshot.counts(index); |
259 int new_range = ranges(index); | 306 int new_range = ranges(index); |
260 checksum += new_range; | |
261 if (previous_range >= new_range) | 307 if (previous_range >= new_range) |
262 inconsistencies |= BUCKET_ORDER_ERROR; | 308 inconsistencies |= BUCKET_ORDER_ERROR; |
263 previous_range = new_range; | 309 previous_range = new_range; |
264 } | 310 } |
265 | 311 |
266 if (checksum != range_checksum_) | 312 if (!HasValidRangeChecksum()) |
267 inconsistencies |= RANGE_CHECKSUM_ERROR; | 313 inconsistencies |= RANGE_CHECKSUM_ERROR; |
268 | 314 |
269 int64 delta64 = snapshot.redundant_count() - count; | 315 int64 delta64 = snapshot.redundant_count() - count; |
270 if (delta64 != 0) { | 316 if (delta64 != 0) { |
271 int delta = static_cast<int>(delta64); | 317 int delta = static_cast<int>(delta64); |
272 if (delta != delta64) | 318 if (delta != delta64) |
273 delta = INT_MAX; // Flag all giant errors as INT_MAX. | 319 delta = INT_MAX; // Flag all giant errors as INT_MAX. |
274 // Since snapshots of histograms are taken asynchronously relative to | 320 // Since snapshots of histograms are taken asynchronously relative to |
275 // sampling (and snapped from different threads), it is pretty likely that | 321 // sampling (and snapped from different threads), it is pretty likely that |
276 // we'll catch a redundant count that doesn't match the sample count. We | 322 // we'll catch a redundant count that doesn't match the sample count. We |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
321 } | 367 } |
322 | 368 |
323 bool Histogram::HasConstructorTimeDeltaArguments(TimeDelta minimum, | 369 bool Histogram::HasConstructorTimeDeltaArguments(TimeDelta minimum, |
324 TimeDelta maximum, | 370 TimeDelta maximum, |
325 size_t bucket_count) { | 371 size_t bucket_count) { |
326 return ((minimum.InMilliseconds() == declared_min_) && | 372 return ((minimum.InMilliseconds() == declared_min_) && |
327 (maximum.InMilliseconds() == declared_max_) && | 373 (maximum.InMilliseconds() == declared_max_) && |
328 (bucket_count == bucket_count_)); | 374 (bucket_count == bucket_count_)); |
329 } | 375 } |
330 | 376 |
377 bool Histogram::HasValidRangeChecksum() const { | |
378 return CalculateRangeChecksum() == range_checksum_; | |
379 } | |
380 | |
331 Histogram::Histogram(const std::string& name, Sample minimum, | 381 Histogram::Histogram(const std::string& name, Sample minimum, |
332 Sample maximum, size_t bucket_count) | 382 Sample maximum, size_t bucket_count) |
333 : histogram_name_(name), | 383 : histogram_name_(name), |
334 declared_min_(minimum), | 384 declared_min_(minimum), |
335 declared_max_(maximum), | 385 declared_max_(maximum), |
336 bucket_count_(bucket_count), | 386 bucket_count_(bucket_count), |
337 flags_(kNoFlags), | 387 flags_(kNoFlags), |
338 ranges_(bucket_count + 1, 0), | 388 ranges_(bucket_count + 1, 0), |
339 range_checksum_(0), | 389 range_checksum_(0), |
340 sample_() { | 390 sample_() { |
(...skipping 15 matching lines...) Expand all Loading... | |
356 | 406 |
357 Histogram::~Histogram() { | 407 Histogram::~Histogram() { |
358 if (StatisticsRecorder::dump_on_exit()) { | 408 if (StatisticsRecorder::dump_on_exit()) { |
359 std::string output; | 409 std::string output; |
360 WriteAscii(true, "\n", &output); | 410 WriteAscii(true, "\n", &output); |
361 LOG(INFO) << output; | 411 LOG(INFO) << output; |
362 } | 412 } |
363 | 413 |
364 // Just to make sure most derived class did this properly... | 414 // Just to make sure most derived class did this properly... |
365 DCHECK(ValidateBucketRanges()); | 415 DCHECK(ValidateBucketRanges()); |
366 DCHECK(HasValidRangeChecksum()); | |
367 } | 416 } |
368 | 417 |
369 bool Histogram::PrintEmptyBucket(size_t index) const { | 418 bool Histogram::PrintEmptyBucket(size_t index) const { |
370 return true; | 419 return true; |
371 } | 420 } |
372 | 421 |
373 // Calculate what range of values are held in each bucket. | 422 // Calculate what range of values are held in each bucket. |
374 // We have to be careful that we don't pick a ratio between starting points in | 423 // We have to be careful that we don't pick a ratio between starting points in |
375 // consecutive buckets that is sooo small, that the integer bounds are the same | 424 // consecutive buckets that is sooo small, that the integer bounds are the same |
376 // (effectively making one bucket get no values). We need to avoid: | 425 // (effectively making one bucket get no values). We need to avoid: |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
471 bool Histogram::ValidateBucketRanges() const { | 520 bool Histogram::ValidateBucketRanges() const { |
472 // Standard assertions that all bucket ranges should satisfy. | 521 // Standard assertions that all bucket ranges should satisfy. |
473 DCHECK_EQ(bucket_count_ + 1, ranges_.size()); | 522 DCHECK_EQ(bucket_count_ + 1, ranges_.size()); |
474 DCHECK_EQ(0, ranges_[0]); | 523 DCHECK_EQ(0, ranges_[0]); |
475 DCHECK_EQ(declared_min(), ranges_[1]); | 524 DCHECK_EQ(declared_min(), ranges_[1]); |
476 DCHECK_EQ(declared_max(), ranges_[bucket_count_ - 1]); | 525 DCHECK_EQ(declared_max(), ranges_[bucket_count_ - 1]); |
477 DCHECK_EQ(kSampleType_MAX, ranges_[bucket_count_]); | 526 DCHECK_EQ(kSampleType_MAX, ranges_[bucket_count_]); |
478 return true; | 527 return true; |
479 } | 528 } |
480 | 529 |
530 uint32 Histogram::CalculateRangeChecksum() const { | |
531 DCHECK_EQ(ranges_.size(), bucket_count() + 1); | |
532 uint32 checksum = static_cast<uint32>(ranges_.size()); // Seed checksum. | |
533 for (size_t index = 0; index < bucket_count(); ++index) | |
534 checksum = Crc32(checksum, ranges(index)); | |
535 return checksum; | |
536 } | |
537 | |
481 void Histogram::Initialize() { | 538 void Histogram::Initialize() { |
482 sample_.Resize(*this); | 539 sample_.Resize(*this); |
483 if (declared_min_ < 1) | 540 if (declared_min_ < 1) |
484 declared_min_ = 1; | 541 declared_min_ = 1; |
485 if (declared_max_ > kSampleType_MAX - 1) | 542 if (declared_max_ > kSampleType_MAX - 1) |
486 declared_max_ = kSampleType_MAX - 1; | 543 declared_max_ = kSampleType_MAX - 1; |
487 DCHECK_LE(declared_min_, declared_max_); | 544 DCHECK_LE(declared_min_, declared_max_); |
488 DCHECK_GT(bucket_count_, 1u); | 545 DCHECK_GT(bucket_count_, 1u); |
489 CHECK_LT(bucket_count_, kBucketCount_MAX); | 546 CHECK_LT(bucket_count_, kBucketCount_MAX); |
490 size_t maximal_bucket_count = declared_max_ - declared_min_ + 2; | 547 size_t maximal_bucket_count = declared_max_ - declared_min_ + 2; |
491 DCHECK_LE(bucket_count_, maximal_bucket_count); | 548 DCHECK_LE(bucket_count_, maximal_bucket_count); |
492 DCHECK_EQ(0, ranges_[0]); | 549 DCHECK_EQ(0, ranges_[0]); |
493 ranges_[bucket_count_] = kSampleType_MAX; | 550 ranges_[bucket_count_] = kSampleType_MAX; |
494 InitializeBucketRange(); | |
495 DCHECK(ValidateBucketRanges()); | |
496 StatisticsRecorder::Register(this); | |
497 } | 551 } |
498 | 552 |
499 bool Histogram::HasValidRangeChecksum() const { | 553 // We generate the CRC-32 using the low order bits to select whether to XOR in |
500 return CalculateRangeChecksum() == range_checksum_; | 554 // the reversed polynomial 0xedb88320L. This is nice and simple, and allows us |
501 } | 555 // to keep the quotient in a uint32. Since we're not concerned about the nature |
502 | 556 // of corruptions (i.e., we don't care about bit sequencing, since we are |
503 Histogram::Sample Histogram::CalculateRangeChecksum() const { | 557 // handling memory changes, which are more grotesque) so we don't bother to |
504 DCHECK_EQ(ranges_.size(), bucket_count() + 1); | 558 // get the CRC correct for big-endian vs little-ending calculations. All we |
505 Sample checksum = 0; | 559 // need is a nice hash, that tends to depend on all the bits of the sample, with |
506 for (size_t index = 0; index < bucket_count(); ++index) { | 560 // very little chance of changes in one place impacting changes in another |
507 checksum += ranges(index); | 561 // place. |
562 uint32 Histogram::Crc32(uint32 sum, Histogram::Sample range) { | |
563 const bool kUseRealCrc = true; // TODO(jar): Switch to false and watch stats. | |
564 if (kUseRealCrc) { | |
Mike Belshe
2011/02/28 17:19:13
nit: funky space
| |
565 union { | |
566 Histogram::Sample range; | |
567 unsigned char bytes[sizeof(Histogram::Sample)]; | |
568 } converter; | |
569 converter.range = range; | |
570 for (size_t i = 0; i < sizeof(converter); ++i) | |
571 sum = kCrcTable[(sum & 0xff) ^ converter.bytes[i]] ^ (sum >> 8); | |
572 } else { | |
573 // Use hash techniques provided in ReallyFastHash, except we don't care | |
574 // about "avalanching" (which would worsten the hash, and add collisions), | |
575 // and we don't care about edge cases since we have an even number of bytes. | |
576 union { | |
577 Histogram::Sample range; | |
578 uint16 ints[sizeof(Histogram::Sample) / 2]; | |
579 } converter; | |
580 DCHECK_EQ(sizeof(Histogram::Sample), sizeof(converter)); | |
581 converter.range = range; | |
582 sum += converter.ints[0]; | |
583 sum = (sum << 16) ^ sum ^ (static_cast<uint32>(converter.ints[1]) << 11); | |
584 sum += sum >> 11; | |
508 } | 585 } |
509 return checksum; | 586 return sum; |
510 } | 587 } |
511 | 588 |
512 //------------------------------------------------------------------------------ | 589 //------------------------------------------------------------------------------ |
513 // Private methods | 590 // Private methods |
514 | 591 |
515 double Histogram::GetPeakBucketSize(const SampleSet& snapshot) const { | 592 double Histogram::GetPeakBucketSize(const SampleSet& snapshot) const { |
516 double max = 0; | 593 double max = 0; |
517 for (size_t i = 0; i < bucket_count() ; ++i) { | 594 for (size_t i = 0; i < bucket_count() ; ++i) { |
518 double current_size = GetBucketSize(snapshot.counts(i), i); | 595 double current_size = GetBucketSize(snapshot.counts(i), i); |
519 if (current_size > max) | 596 if (current_size > max) |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
703 size_t bucket_count, | 780 size_t bucket_count, |
704 Flags flags) { | 781 Flags flags) { |
705 scoped_refptr<Histogram> histogram(NULL); | 782 scoped_refptr<Histogram> histogram(NULL); |
706 | 783 |
707 if (minimum < 1) | 784 if (minimum < 1) |
708 minimum = 1; | 785 minimum = 1; |
709 if (maximum > kSampleType_MAX - 1) | 786 if (maximum > kSampleType_MAX - 1) |
710 maximum = kSampleType_MAX - 1; | 787 maximum = kSampleType_MAX - 1; |
711 | 788 |
712 if (!StatisticsRecorder::FindHistogram(name, &histogram)) { | 789 if (!StatisticsRecorder::FindHistogram(name, &histogram)) { |
713 histogram = new LinearHistogram(name, minimum, maximum, bucket_count); | 790 LinearHistogram* linear_histogram = |
714 StatisticsRecorder::FindHistogram(name, &histogram); | 791 new LinearHistogram(name, minimum, maximum, bucket_count); |
792 linear_histogram->InitializeBucketRange(); | |
793 histogram = linear_histogram; | |
794 StatisticsRecorder::Register(&histogram); | |
715 } | 795 } |
716 | 796 |
717 DCHECK_EQ(LINEAR_HISTOGRAM, histogram->histogram_type()); | 797 DCHECK_EQ(LINEAR_HISTOGRAM, histogram->histogram_type()); |
718 DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count)); | 798 DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count)); |
719 histogram->SetFlags(flags); | 799 histogram->SetFlags(flags); |
720 return histogram; | 800 return histogram; |
721 } | 801 } |
722 | 802 |
723 scoped_refptr<Histogram> LinearHistogram::FactoryTimeGet( | 803 scoped_refptr<Histogram> LinearHistogram::FactoryTimeGet( |
724 const std::string& name, | 804 const std::string& name, |
(...skipping 14 matching lines...) Expand all Loading... | |
739 for (int i =0; descriptions[i].description; ++i) { | 819 for (int i =0; descriptions[i].description; ++i) { |
740 bucket_description_[descriptions[i].sample] = descriptions[i].description; | 820 bucket_description_[descriptions[i].sample] = descriptions[i].description; |
741 } | 821 } |
742 } | 822 } |
743 | 823 |
744 LinearHistogram::LinearHistogram(const std::string& name, | 824 LinearHistogram::LinearHistogram(const std::string& name, |
745 Sample minimum, | 825 Sample minimum, |
746 Sample maximum, | 826 Sample maximum, |
747 size_t bucket_count) | 827 size_t bucket_count) |
748 : Histogram(name, minimum >= 1 ? minimum : 1, maximum, bucket_count) { | 828 : Histogram(name, minimum >= 1 ? minimum : 1, maximum, bucket_count) { |
749 InitializeBucketRange(); | |
750 DCHECK(ValidateBucketRanges()); | |
751 } | 829 } |
752 | 830 |
753 LinearHistogram::LinearHistogram(const std::string& name, | 831 LinearHistogram::LinearHistogram(const std::string& name, |
754 TimeDelta minimum, | 832 TimeDelta minimum, |
755 TimeDelta maximum, | 833 TimeDelta maximum, |
756 size_t bucket_count) | 834 size_t bucket_count) |
757 : Histogram(name, minimum >= TimeDelta::FromMilliseconds(1) ? | 835 : Histogram(name, minimum >= TimeDelta::FromMilliseconds(1) ? |
758 minimum : TimeDelta::FromMilliseconds(1), | 836 minimum : TimeDelta::FromMilliseconds(1), |
759 maximum, bucket_count) { | 837 maximum, bucket_count) { |
760 // Do a "better" (different) job at init than a base classes did... | |
761 InitializeBucketRange(); | |
762 DCHECK(ValidateBucketRanges()); | |
763 } | 838 } |
764 | 839 |
765 void LinearHistogram::InitializeBucketRange() { | 840 void LinearHistogram::InitializeBucketRange() { |
766 DCHECK_GT(declared_min(), 0); // 0 is the underflow bucket here. | 841 DCHECK_GT(declared_min(), 0); // 0 is the underflow bucket here. |
767 double min = declared_min(); | 842 double min = declared_min(); |
768 double max = declared_max(); | 843 double max = declared_max(); |
769 size_t i; | 844 size_t i; |
770 for (i = 1; i < bucket_count(); ++i) { | 845 for (i = 1; i < bucket_count(); ++i) { |
771 double linear_range = (min * (bucket_count() -1 - i) + max * (i - 1)) / | 846 double linear_range = (min * (bucket_count() -1 - i) + max * (i - 1)) / |
772 (bucket_count() - 2); | 847 (bucket_count() - 2); |
(...skipping 25 matching lines...) Expand all Loading... | |
798 | 873 |
799 //------------------------------------------------------------------------------ | 874 //------------------------------------------------------------------------------ |
800 // This section provides implementation for BooleanHistogram. | 875 // This section provides implementation for BooleanHistogram. |
801 //------------------------------------------------------------------------------ | 876 //------------------------------------------------------------------------------ |
802 | 877 |
803 scoped_refptr<Histogram> BooleanHistogram::FactoryGet(const std::string& name, | 878 scoped_refptr<Histogram> BooleanHistogram::FactoryGet(const std::string& name, |
804 Flags flags) { | 879 Flags flags) { |
805 scoped_refptr<Histogram> histogram(NULL); | 880 scoped_refptr<Histogram> histogram(NULL); |
806 | 881 |
807 if (!StatisticsRecorder::FindHistogram(name, &histogram)) { | 882 if (!StatisticsRecorder::FindHistogram(name, &histogram)) { |
808 histogram = new BooleanHistogram(name); | 883 BooleanHistogram* boolean_histogram = new BooleanHistogram(name); |
809 StatisticsRecorder::FindHistogram(name, &histogram); | 884 boolean_histogram->InitializeBucketRange(); |
885 histogram = boolean_histogram; | |
886 StatisticsRecorder::Register(&histogram); | |
810 } | 887 } |
811 | 888 |
812 DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->histogram_type()); | 889 DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->histogram_type()); |
813 histogram->SetFlags(flags); | 890 histogram->SetFlags(flags); |
814 return histogram; | 891 return histogram; |
815 } | 892 } |
816 | 893 |
817 Histogram::ClassType BooleanHistogram::histogram_type() const { | 894 Histogram::ClassType BooleanHistogram::histogram_type() const { |
818 return BOOLEAN_HISTOGRAM; | 895 return BOOLEAN_HISTOGRAM; |
819 } | 896 } |
(...skipping 23 matching lines...) Expand all Loading... | |
843 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end()); | 920 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end()); |
844 if (ranges.size() <= 1) { | 921 if (ranges.size() <= 1) { |
845 DCHECK(false); | 922 DCHECK(false); |
846 // Note that we pushed a 0 in above, so for defensive code.... | 923 // Note that we pushed a 0 in above, so for defensive code.... |
847 ranges.push_back(1); // Put in some data so we can index to [1]. | 924 ranges.push_back(1); // Put in some data so we can index to [1]. |
848 } | 925 } |
849 | 926 |
850 DCHECK_LT(ranges.back(), kSampleType_MAX); | 927 DCHECK_LT(ranges.back(), kSampleType_MAX); |
851 | 928 |
852 if (!StatisticsRecorder::FindHistogram(name, &histogram)) { | 929 if (!StatisticsRecorder::FindHistogram(name, &histogram)) { |
853 histogram = new CustomHistogram(name, ranges); | 930 CustomHistogram* custom_histogram = new CustomHistogram(name, ranges); |
854 StatisticsRecorder::FindHistogram(name, &histogram); | 931 custom_histogram->InitializeBucketRange(ranges); |
932 histogram = custom_histogram; | |
933 StatisticsRecorder::Register(&histogram); | |
855 } | 934 } |
856 | 935 |
857 DCHECK_EQ(histogram->histogram_type(), CUSTOM_HISTOGRAM); | 936 DCHECK_EQ(histogram->histogram_type(), CUSTOM_HISTOGRAM); |
858 DCHECK(histogram->HasConstructorArguments(ranges[1], ranges.back(), | 937 DCHECK(histogram->HasConstructorArguments(ranges[1], ranges.back(), |
859 ranges.size())); | 938 ranges.size())); |
860 histogram->SetFlags(flags); | 939 histogram->SetFlags(flags); |
861 return histogram; | 940 return histogram; |
862 } | 941 } |
863 | 942 |
864 Histogram::ClassType CustomHistogram::histogram_type() const { | 943 Histogram::ClassType CustomHistogram::histogram_type() const { |
865 return CUSTOM_HISTOGRAM; | 944 return CUSTOM_HISTOGRAM; |
866 } | 945 } |
867 | 946 |
868 CustomHistogram::CustomHistogram(const std::string& name, | 947 CustomHistogram::CustomHistogram(const std::string& name, |
869 const std::vector<Sample>& custom_ranges) | 948 const std::vector<Sample>& custom_ranges) |
870 : Histogram(name, custom_ranges[1], custom_ranges.back(), | 949 : Histogram(name, custom_ranges[1], custom_ranges.back(), |
871 custom_ranges.size()) { | 950 custom_ranges.size()) { |
872 DCHECK_GT(custom_ranges.size(), 1u); | 951 DCHECK_GT(custom_ranges.size(), 1u); |
873 DCHECK_EQ(custom_ranges[0], 0); | 952 DCHECK_EQ(custom_ranges[0], 0); |
874 ranges_vector_ = &custom_ranges; | |
875 InitializeBucketRange(); | |
876 ranges_vector_ = NULL; | |
877 DCHECK(ValidateBucketRanges()); | |
878 } | 953 } |
879 | 954 |
880 void CustomHistogram::InitializeBucketRange() { | 955 void CustomHistogram::InitializeBucketRange( |
881 DCHECK_LE(ranges_vector_->size(), bucket_count()); | 956 const std::vector<Sample>& custom_ranges) { |
882 for (size_t index = 0; index < ranges_vector_->size(); ++index) | 957 DCHECK_GT(custom_ranges.size(), 1u); |
883 SetBucketRange(index, (*ranges_vector_)[index]); | 958 DCHECK_EQ(custom_ranges[0], 0); |
959 DCHECK_LE(custom_ranges.size(), bucket_count()); | |
960 for (size_t index = 0; index < custom_ranges.size(); ++index) | |
961 SetBucketRange(index, custom_ranges[index]); | |
884 ResetRangeChecksum(); | 962 ResetRangeChecksum(); |
885 } | 963 } |
886 | 964 |
887 double CustomHistogram::GetBucketSize(Count current, size_t i) const { | 965 double CustomHistogram::GetBucketSize(Count current, size_t i) const { |
888 return 1; | 966 return 1; |
889 } | 967 } |
890 | 968 |
891 //------------------------------------------------------------------------------ | 969 //------------------------------------------------------------------------------ |
892 // The next section handles global (central) support for all histograms, as well | 970 // The next section handles global (central) support for all histograms, as well |
893 // as startup/teardown of this service. | 971 // as startup/teardown of this service. |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
938 base::AutoLock auto_lock(*lock_); | 1016 base::AutoLock auto_lock(*lock_); |
939 return NULL != histograms_; | 1017 return NULL != histograms_; |
940 } | 1018 } |
941 | 1019 |
942 // Note: We can't accept a ref_ptr to |histogram| because we *might* not keep a | 1020 // Note: We can't accept a ref_ptr to |histogram| because we *might* not keep a |
943 // reference, and we are called while in the Histogram constructor. In that | 1021 // reference, and we are called while in the Histogram constructor. In that |
944 // scenario, a ref_ptr would have incremented the ref count when the histogram | 1022 // scenario, a ref_ptr would have incremented the ref count when the histogram |
945 // was passed to us, decremented it when we returned, and the instance would be | 1023 // was passed to us, decremented it when we returned, and the instance would be |
946 // destroyed before assignment (when value was returned by new). | 1024 // destroyed before assignment (when value was returned by new). |
947 // static | 1025 // static |
948 void StatisticsRecorder::Register(Histogram* histogram) { | 1026 void StatisticsRecorder::Register(scoped_refptr<Histogram>* histogram) { |
1027 DCHECK((*histogram)->HasValidRangeChecksum()); | |
949 if (lock_ == NULL) | 1028 if (lock_ == NULL) |
950 return; | 1029 return; |
951 base::AutoLock auto_lock(*lock_); | 1030 base::AutoLock auto_lock(*lock_); |
952 if (!histograms_) | 1031 if (!histograms_) |
953 return; | 1032 return; |
954 const std::string name = histogram->histogram_name(); | 1033 const std::string name = (*histogram)->histogram_name(); |
1034 HistogramMap::iterator it = histograms_->find(name); | |
955 // Avoid overwriting a previous registration. | 1035 // Avoid overwriting a previous registration. |
956 if (histograms_->end() == histograms_->find(name)) | 1036 if (histograms_->end() == it) |
957 (*histograms_)[name] = histogram; | 1037 (*histograms_)[name] = *histogram; |
1038 else | |
1039 *histogram = it->second; | |
958 } | 1040 } |
959 | 1041 |
960 // static | 1042 // static |
961 void StatisticsRecorder::WriteHTMLGraph(const std::string& query, | 1043 void StatisticsRecorder::WriteHTMLGraph(const std::string& query, |
962 std::string* output) { | 1044 std::string* output) { |
963 if (!IsActive()) | 1045 if (!IsActive()) |
964 return; | 1046 return; |
965 output->append("<html><head><title>About Histograms"); | 1047 output->append("<html><head><title>About Histograms"); |
966 if (!query.empty()) | 1048 if (!query.empty()) |
967 output->append(" - " + query); | 1049 output->append(" - " + query); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1047 } | 1129 } |
1048 | 1130 |
1049 // static | 1131 // static |
1050 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL; | 1132 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL; |
1051 // static | 1133 // static |
1052 base::Lock* StatisticsRecorder::lock_ = NULL; | 1134 base::Lock* StatisticsRecorder::lock_ = NULL; |
1053 // static | 1135 // static |
1054 bool StatisticsRecorder::dump_on_exit_ = false; | 1136 bool StatisticsRecorder::dump_on_exit_ = false; |
1055 | 1137 |
1056 } // namespace base | 1138 } // namespace base |
OLD | NEW |