Chromium Code Reviews| 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, | |
|
Mike Belshe
2011/02/25 01:21:18
this table is duplicated in src/third_party/zlib/c
jar (doing other things)
2011/02/26 17:19:55
Reaching from base into the third party libraries
| |
| 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. |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 154 // static | 201 // static |
| 155 std::string Histogram::SerializeHistogramInfo(const Histogram& histogram, | 202 std::string Histogram::SerializeHistogramInfo(const Histogram& histogram, |
| 156 const SampleSet& snapshot) { | 203 const SampleSet& snapshot) { |
| 157 DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type()); | 204 DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type()); |
| 158 | 205 |
| 159 Pickle pickle; | 206 Pickle pickle; |
| 160 pickle.WriteString(histogram.histogram_name()); | 207 pickle.WriteString(histogram.histogram_name()); |
| 161 pickle.WriteInt(histogram.declared_min()); | 208 pickle.WriteInt(histogram.declared_min()); |
| 162 pickle.WriteInt(histogram.declared_max()); | 209 pickle.WriteInt(histogram.declared_max()); |
| 163 pickle.WriteSize(histogram.bucket_count()); | 210 pickle.WriteSize(histogram.bucket_count()); |
| 164 pickle.WriteInt(histogram.range_checksum()); | 211 pickle.WriteUInt32(histogram.range_checksum()); |
| 165 pickle.WriteInt(histogram.histogram_type()); | 212 pickle.WriteInt(histogram.histogram_type()); |
| 166 pickle.WriteInt(histogram.flags()); | 213 pickle.WriteInt(histogram.flags()); |
| 167 | 214 |
| 168 snapshot.Serialize(&pickle); | 215 snapshot.Serialize(&pickle); |
| 169 return std::string(static_cast<const char*>(pickle.data()), pickle.size()); | 216 return std::string(static_cast<const char*>(pickle.data()), pickle.size()); |
| 170 } | 217 } |
| 171 | 218 |
| 172 // static | 219 // static |
| 173 bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) { | 220 bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) { |
| 174 if (histogram_info.empty()) { | 221 if (histogram_info.empty()) { |
| 175 return false; | 222 return false; |
| 176 } | 223 } |
| 177 | 224 |
| 178 Pickle pickle(histogram_info.data(), | 225 Pickle pickle(histogram_info.data(), |
| 179 static_cast<int>(histogram_info.size())); | 226 static_cast<int>(histogram_info.size())); |
| 180 std::string histogram_name; | 227 std::string histogram_name; |
| 181 int declared_min; | 228 int declared_min; |
| 182 int declared_max; | 229 int declared_max; |
| 183 size_t bucket_count; | 230 size_t bucket_count; |
| 184 int range_checksum; | 231 uint32 range_checksum; |
| 185 int histogram_type; | 232 int histogram_type; |
| 186 int pickle_flags; | 233 int pickle_flags; |
| 187 SampleSet sample; | 234 SampleSet sample; |
| 188 | 235 |
| 189 void* iter = NULL; | 236 void* iter = NULL; |
| 190 if (!pickle.ReadString(&iter, &histogram_name) || | 237 if (!pickle.ReadString(&iter, &histogram_name) || |
| 191 !pickle.ReadInt(&iter, &declared_min) || | 238 !pickle.ReadInt(&iter, &declared_min) || |
| 192 !pickle.ReadInt(&iter, &declared_max) || | 239 !pickle.ReadInt(&iter, &declared_max) || |
| 193 !pickle.ReadSize(&iter, &bucket_count) || | 240 !pickle.ReadSize(&iter, &bucket_count) || |
| 194 !pickle.ReadInt(&iter, &range_checksum) || | 241 !pickle.ReadUInt32(&iter, &range_checksum) || |
| 195 !pickle.ReadInt(&iter, &histogram_type) || | 242 !pickle.ReadInt(&iter, &histogram_type) || |
| 196 !pickle.ReadInt(&iter, &pickle_flags) || | 243 !pickle.ReadInt(&iter, &pickle_flags) || |
| 197 !sample.Histogram::SampleSet::Deserialize(&iter, pickle)) { | 244 !sample.Histogram::SampleSet::Deserialize(&iter, pickle)) { |
| 198 LOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name; | 245 LOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name; |
| 199 return false; | 246 return false; |
| 200 } | 247 } |
| 201 DCHECK(pickle_flags & kIPCSerializationSourceFlag); | 248 DCHECK(pickle_flags & kIPCSerializationSourceFlag); |
| 202 // Since these fields may have come from an untrusted renderer, do additional | 249 // Since these fields may have come from an untrusted renderer, do additional |
| 203 // checks above and beyond those in Histogram::Initialize() | 250 // checks above and beyond those in Histogram::Initialize() |
| 204 if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min || | 251 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 } | 292 } |
| 246 | 293 |
| 247 //------------------------------------------------------------------------------ | 294 //------------------------------------------------------------------------------ |
| 248 // Methods for the validating a sample and a related histogram. | 295 // Methods for the validating a sample and a related histogram. |
| 249 //------------------------------------------------------------------------------ | 296 //------------------------------------------------------------------------------ |
| 250 | 297 |
| 251 Histogram::Inconsistencies Histogram::FindCorruption( | 298 Histogram::Inconsistencies Histogram::FindCorruption( |
| 252 const SampleSet& snapshot) const { | 299 const SampleSet& snapshot) const { |
| 253 int inconsistencies = NO_INCONSISTENCIES; | 300 int inconsistencies = NO_INCONSISTENCIES; |
| 254 Sample previous_range = -1; // Bottom range is always 0. | 301 Sample previous_range = -1; // Bottom range is always 0. |
| 255 Sample checksum = 0; | |
| 256 int64 count = 0; | 302 int64 count = 0; |
| 257 for (size_t index = 0; index < bucket_count(); ++index) { | 303 for (size_t index = 0; index < bucket_count(); ++index) { |
| 258 count += snapshot.counts(index); | 304 count += snapshot.counts(index); |
| 259 int new_range = ranges(index); | 305 int new_range = ranges(index); |
| 260 checksum += new_range; | |
| 261 if (previous_range >= new_range) | 306 if (previous_range >= new_range) |
| 262 inconsistencies |= BUCKET_ORDER_ERROR; | 307 inconsistencies |= BUCKET_ORDER_ERROR; |
| 263 previous_range = new_range; | 308 previous_range = new_range; |
| 264 } | 309 } |
| 265 | 310 |
| 266 if (checksum != range_checksum_) | 311 if (CalculateRangeChecksum() != range_checksum_) |
| 267 inconsistencies |= RANGE_CHECKSUM_ERROR; | 312 inconsistencies |= RANGE_CHECKSUM_ERROR; |
| 268 | 313 |
| 269 int64 delta64 = snapshot.redundant_count() - count; | 314 int64 delta64 = snapshot.redundant_count() - count; |
| 270 if (delta64 != 0) { | 315 if (delta64 != 0) { |
| 271 int delta = static_cast<int>(delta64); | 316 int delta = static_cast<int>(delta64); |
| 272 if (delta != delta64) | 317 if (delta != delta64) |
| 273 delta = INT_MAX; // Flag all giant errors as INT_MAX. | 318 delta = INT_MAX; // Flag all giant errors as INT_MAX. |
| 274 // Since snapshots of histograms are taken asynchronously relative to | 319 // Since snapshots of histograms are taken asynchronously relative to |
| 275 // sampling (and snapped from different threads), it is pretty likely that | 320 // 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 | 321 // we'll catch a redundant count that doesn't match the sample count. We |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 493 ranges_[bucket_count_] = kSampleType_MAX; | 538 ranges_[bucket_count_] = kSampleType_MAX; |
| 494 InitializeBucketRange(); | 539 InitializeBucketRange(); |
| 495 DCHECK(ValidateBucketRanges()); | 540 DCHECK(ValidateBucketRanges()); |
| 496 StatisticsRecorder::Register(this); | 541 StatisticsRecorder::Register(this); |
| 497 } | 542 } |
| 498 | 543 |
| 499 bool Histogram::HasValidRangeChecksum() const { | 544 bool Histogram::HasValidRangeChecksum() const { |
| 500 return CalculateRangeChecksum() == range_checksum_; | 545 return CalculateRangeChecksum() == range_checksum_; |
| 501 } | 546 } |
| 502 | 547 |
| 503 Histogram::Sample Histogram::CalculateRangeChecksum() const { | 548 uint32 Histogram::CalculateRangeChecksum() const { |
| 504 DCHECK_EQ(ranges_.size(), bucket_count() + 1); | 549 DCHECK_EQ(ranges_.size(), bucket_count() + 1); |
| 505 Sample checksum = 0; | 550 uint32 checksum = static_cast<uint32>(ranges_.size()); // Seed checksum. |
| 506 for (size_t index = 0; index < bucket_count(); ++index) { | 551 for (size_t index = 0; index < bucket_count(); ++index) |
| 507 checksum += ranges(index); | 552 checksum = Crc32(checksum, ranges(index)); |
| 508 } | |
| 509 return checksum; | 553 return checksum; |
| 510 } | 554 } |
| 511 | 555 |
| 556 // We generate the CRC-32 using the low order bits to select whether to XOR in | |
| 557 // the reversed polynomial 0xedb88320L. This is nice and simple, and allows us | |
| 558 // to keep the quotient in a uint32. Since we're not concerned about the nature | |
| 559 // of corruptions (i.e., we don't care about bit sequencing, since we are | |
| 560 // handling memory changes, which are more grotesque) so we don't bother to | |
| 561 // get the CRC correct for big-endian vs little-ending calculations. All we | |
| 562 // need is a nice hash, that tends to depend on all the bits of the sample, with | |
| 563 // very little chance of changes in one place impacting changes in another | |
| 564 // place. | |
| 565 uint32 Histogram::Crc32(uint32 sum, Histogram::Sample range) { | |
| 566 union { | |
| 567 Histogram::Sample range; | |
| 568 char bytes[sizeof(Histogram::Sample)]; | |
| 569 } converter; | |
| 570 converter.range = range; | |
| 571 for (size_t i = 0; i < sizeof(converter); ++i) | |
| 572 sum = kCrcTable[(sum & 0xff) ^ converter.bytes[i]] ^ (sum >> 8); | |
|
Mike Belshe
2011/02/25 01:21:18
I think this line must be wrong.
kCrcTable is onl
jar (doing other things)
2011/02/26 17:19:55
Added "unsigned" to declaration of bytes per our d
| |
| 573 return sum; | |
| 574 | |
|
Mike Belshe
2011/02/25 01:21:18
nit: blank line
jar (doing other things)
2011/02/26 17:19:55
Done.
| |
| 575 } | |
| 576 | |
| 512 //------------------------------------------------------------------------------ | 577 //------------------------------------------------------------------------------ |
| 513 // Private methods | 578 // Private methods |
| 514 | 579 |
| 515 double Histogram::GetPeakBucketSize(const SampleSet& snapshot) const { | 580 double Histogram::GetPeakBucketSize(const SampleSet& snapshot) const { |
| 516 double max = 0; | 581 double max = 0; |
| 517 for (size_t i = 0; i < bucket_count() ; ++i) { | 582 for (size_t i = 0; i < bucket_count() ; ++i) { |
| 518 double current_size = GetBucketSize(snapshot.counts(i), i); | 583 double current_size = GetBucketSize(snapshot.counts(i), i); |
| 519 if (current_size > max) | 584 if (current_size > max) |
| 520 max = current_size; | 585 max = current_size; |
| 521 } | 586 } |
| (...skipping 525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1047 } | 1112 } |
| 1048 | 1113 |
| 1049 // static | 1114 // static |
| 1050 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL; | 1115 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL; |
| 1051 // static | 1116 // static |
| 1052 base::Lock* StatisticsRecorder::lock_ = NULL; | 1117 base::Lock* StatisticsRecorder::lock_ = NULL; |
| 1053 // static | 1118 // static |
| 1054 bool StatisticsRecorder::dump_on_exit_ = false; | 1119 bool StatisticsRecorder::dump_on_exit_ = false; |
| 1055 | 1120 |
| 1056 } // namespace base | 1121 } // namespace base |
| OLD | NEW |