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, | |
| 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 |