| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 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/compiler_specific.h" | 17 #include "base/compiler_specific.h" |
| 18 #include "base/debug/alias.h" | 18 #include "base/debug/alias.h" |
| 19 #include "base/logging.h" | 19 #include "base/logging.h" |
| 20 #include "base/metrics/sample_vector.h" | 20 #include "base/metrics/sample_vector.h" |
| 21 #include "base/metrics/statistics_recorder.h" | 21 #include "base/metrics/statistics_recorder.h" |
| 22 #include "base/pickle.h" | 22 #include "base/pickle.h" |
| 23 #include "base/strings/string_util.h" | 23 #include "base/strings/string_util.h" |
| 24 #include "base/strings/stringprintf.h" | 24 #include "base/strings/stringprintf.h" |
| 25 #include "base/synchronization/lock.h" | 25 #include "base/synchronization/lock.h" |
| 26 #include "base/values.h" | 26 #include "base/values.h" |
| 27 | 27 |
| 28 using std::string; | |
| 29 using std::vector; | |
| 30 | |
| 31 namespace base { | 28 namespace base { |
| 32 | 29 |
| 33 namespace { | 30 namespace { |
| 34 | 31 |
| 35 bool ReadHistogramArguments(PickleIterator* iter, | 32 bool ReadHistogramArguments(PickleIterator* iter, |
| 36 string* histogram_name, | 33 std::string* histogram_name, |
| 37 int* flags, | 34 int* flags, |
| 38 int* declared_min, | 35 int* declared_min, |
| 39 int* declared_max, | 36 int* declared_max, |
| 40 size_t* bucket_count, | 37 size_t* bucket_count, |
| 41 uint32* range_checksum) { | 38 uint32* range_checksum) { |
| 42 if (!iter->ReadString(histogram_name) || | 39 if (!iter->ReadString(histogram_name) || |
| 43 !iter->ReadInt(flags) || | 40 !iter->ReadInt(flags) || |
| 44 !iter->ReadInt(declared_min) || | 41 !iter->ReadInt(declared_min) || |
| 45 !iter->ReadInt(declared_max) || | 42 !iter->ReadInt(declared_max) || |
| 46 !iter->ReadSizeT(bucket_count) || | 43 !iter->ReadSizeT(bucket_count) || |
| (...skipping 30 matching lines...) Expand all Loading... |
| 77 } | 74 } |
| 78 | 75 |
| 79 } // namespace | 76 } // namespace |
| 80 | 77 |
| 81 typedef HistogramBase::Count Count; | 78 typedef HistogramBase::Count Count; |
| 82 typedef HistogramBase::Sample Sample; | 79 typedef HistogramBase::Sample Sample; |
| 83 | 80 |
| 84 // static | 81 // static |
| 85 const size_t Histogram::kBucketCount_MAX = 16384u; | 82 const size_t Histogram::kBucketCount_MAX = 16384u; |
| 86 | 83 |
| 87 HistogramBase* Histogram::FactoryGet(const string& name, | 84 HistogramBase* Histogram::FactoryGet(const std::string& name, |
| 88 Sample minimum, | 85 Sample minimum, |
| 89 Sample maximum, | 86 Sample maximum, |
| 90 size_t bucket_count, | 87 size_t bucket_count, |
| 91 int32 flags) { | 88 int32 flags) { |
| 92 bool valid_arguments = | 89 bool valid_arguments = |
| 93 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); | 90 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); |
| 94 DCHECK(valid_arguments); | 91 DCHECK(valid_arguments); |
| 95 | 92 |
| 96 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 93 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); |
| 97 if (!histogram) { | 94 if (!histogram) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 116 // changed one of them, or simply by bad code within Chrome itself. We | 113 // changed one of them, or simply by bad code within Chrome itself. We |
| 117 // return NULL here with the expectation that bad code in Chrome will crash | 114 // return NULL here with the expectation that bad code in Chrome will crash |
| 118 // on dereference, but extension/Pepper APIs will guard against NULL and not | 115 // on dereference, but extension/Pepper APIs will guard against NULL and not |
| 119 // crash. | 116 // crash. |
| 120 DLOG(ERROR) << "Histogram " << name << " has bad construction arguments"; | 117 DLOG(ERROR) << "Histogram " << name << " has bad construction arguments"; |
| 121 return NULL; | 118 return NULL; |
| 122 } | 119 } |
| 123 return histogram; | 120 return histogram; |
| 124 } | 121 } |
| 125 | 122 |
| 126 HistogramBase* Histogram::FactoryTimeGet(const string& name, | 123 HistogramBase* Histogram::FactoryTimeGet(const std::string& name, |
| 127 TimeDelta minimum, | 124 TimeDelta minimum, |
| 128 TimeDelta maximum, | 125 TimeDelta maximum, |
| 129 size_t bucket_count, | 126 size_t bucket_count, |
| 130 int32 flags) { | 127 int32 flags) { |
| 131 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()), | 128 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()), |
| 132 static_cast<Sample>(maximum.InMilliseconds()), bucket_count, | 129 static_cast<Sample>(maximum.InMilliseconds()), bucket_count, |
| 133 flags); | 130 flags); |
| 134 } | 131 } |
| 135 | 132 |
| 136 // Calculate what range of values are held in each bucket. | 133 // Calculate what range of values are held in each bucket. |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 | 206 |
| 210 Sample Histogram::ranges(size_t i) const { | 207 Sample Histogram::ranges(size_t i) const { |
| 211 return bucket_ranges_->range(i); | 208 return bucket_ranges_->range(i); |
| 212 } | 209 } |
| 213 | 210 |
| 214 size_t Histogram::bucket_count() const { | 211 size_t Histogram::bucket_count() const { |
| 215 return bucket_ranges_->bucket_count(); | 212 return bucket_ranges_->bucket_count(); |
| 216 } | 213 } |
| 217 | 214 |
| 218 // static | 215 // static |
| 219 bool Histogram::InspectConstructionArguments(const string& name, | 216 bool Histogram::InspectConstructionArguments(const std::string& name, |
| 220 Sample* minimum, | 217 Sample* minimum, |
| 221 Sample* maximum, | 218 Sample* maximum, |
| 222 size_t* bucket_count) { | 219 size_t* bucket_count) { |
| 223 // Defensive code for backward compatibility. | 220 // Defensive code for backward compatibility. |
| 224 if (*minimum < 1) { | 221 if (*minimum < 1) { |
| 225 DVLOG(1) << "Histogram: " << name << " has bad minimum: " << *minimum; | 222 DVLOG(1) << "Histogram: " << name << " has bad minimum: " << *minimum; |
| 226 *minimum = 1; | 223 *minimum = 1; |
| 227 } | 224 } |
| 228 if (*maximum >= kSampleType_MAX) { | 225 if (*maximum >= kSampleType_MAX) { |
| 229 DVLOG(1) << "Histogram: " << name << " has bad maximum: " << *maximum; | 226 DVLOG(1) << "Histogram: " << name << " has bad maximum: " << *maximum; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 273 | 270 |
| 274 void Histogram::AddSamples(const HistogramSamples& samples) { | 271 void Histogram::AddSamples(const HistogramSamples& samples) { |
| 275 samples_->Add(samples); | 272 samples_->Add(samples); |
| 276 } | 273 } |
| 277 | 274 |
| 278 bool Histogram::AddSamplesFromPickle(PickleIterator* iter) { | 275 bool Histogram::AddSamplesFromPickle(PickleIterator* iter) { |
| 279 return samples_->AddFromPickle(iter); | 276 return samples_->AddFromPickle(iter); |
| 280 } | 277 } |
| 281 | 278 |
| 282 // The following methods provide a graphical histogram display. | 279 // The following methods provide a graphical histogram display. |
| 283 void Histogram::WriteHTMLGraph(string* output) const { | 280 void Histogram::WriteHTMLGraph(std::string* output) const { |
| 284 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc. | 281 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc. |
| 285 output->append("<PRE>"); | 282 output->append("<PRE>"); |
| 286 WriteAsciiImpl(true, "<br>", output); | 283 WriteAsciiImpl(true, "<br>", output); |
| 287 output->append("</PRE>"); | 284 output->append("</PRE>"); |
| 288 } | 285 } |
| 289 | 286 |
| 290 void Histogram::WriteAscii(string* output) const { | 287 void Histogram::WriteAscii(std::string* output) const { |
| 291 WriteAsciiImpl(true, "\n", output); | 288 WriteAsciiImpl(true, "\n", output); |
| 292 } | 289 } |
| 293 | 290 |
| 294 bool Histogram::SerializeInfoImpl(Pickle* pickle) const { | 291 bool Histogram::SerializeInfoImpl(Pickle* pickle) const { |
| 295 DCHECK(bucket_ranges()->HasValidChecksum()); | 292 DCHECK(bucket_ranges()->HasValidChecksum()); |
| 296 return pickle->WriteString(histogram_name()) && | 293 return pickle->WriteString(histogram_name()) && |
| 297 pickle->WriteInt(flags()) && | 294 pickle->WriteInt(flags()) && |
| 298 pickle->WriteInt(declared_min()) && | 295 pickle->WriteInt(declared_min()) && |
| 299 pickle->WriteInt(declared_max()) && | 296 pickle->WriteInt(declared_max()) && |
| 300 pickle->WriteSizeT(bucket_count()) && | 297 pickle->WriteSizeT(bucket_count()) && |
| 301 pickle->WriteUInt32(bucket_ranges()->checksum()); | 298 pickle->WriteUInt32(bucket_ranges()->checksum()); |
| 302 } | 299 } |
| 303 | 300 |
| 304 Histogram::Histogram(const string& name, | 301 Histogram::Histogram(const std::string& name, |
| 305 Sample minimum, | 302 Sample minimum, |
| 306 Sample maximum, | 303 Sample maximum, |
| 307 const BucketRanges* ranges) | 304 const BucketRanges* ranges) |
| 308 : HistogramBase(name), | 305 : HistogramBase(name), |
| 309 bucket_ranges_(ranges), | 306 bucket_ranges_(ranges), |
| 310 declared_min_(minimum), | 307 declared_min_(minimum), |
| 311 declared_max_(maximum) { | 308 declared_max_(maximum) { |
| 312 if (ranges) | 309 if (ranges) |
| 313 samples_.reset(new SampleVector(ranges)); | 310 samples_.reset(new SampleVector(ranges)); |
| 314 } | 311 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 327 // not have 0-graphical-height buckets. | 324 // not have 0-graphical-height buckets. |
| 328 double Histogram::GetBucketSize(Count current, size_t i) const { | 325 double Histogram::GetBucketSize(Count current, size_t i) const { |
| 329 DCHECK_GT(ranges(i + 1), ranges(i)); | 326 DCHECK_GT(ranges(i + 1), ranges(i)); |
| 330 static const double kTransitionWidth = 5; | 327 static const double kTransitionWidth = 5; |
| 331 double denominator = ranges(i + 1) - ranges(i); | 328 double denominator = ranges(i + 1) - ranges(i); |
| 332 if (denominator > kTransitionWidth) | 329 if (denominator > kTransitionWidth) |
| 333 denominator = kTransitionWidth; // Stop trying to normalize. | 330 denominator = kTransitionWidth; // Stop trying to normalize. |
| 334 return current/denominator; | 331 return current/denominator; |
| 335 } | 332 } |
| 336 | 333 |
| 337 const string Histogram::GetAsciiBucketRange(size_t i) const { | 334 const std::string Histogram::GetAsciiBucketRange(size_t i) const { |
| 338 return GetSimpleAsciiBucketRange(ranges(i)); | 335 return GetSimpleAsciiBucketRange(ranges(i)); |
| 339 } | 336 } |
| 340 | 337 |
| 341 //------------------------------------------------------------------------------ | 338 //------------------------------------------------------------------------------ |
| 342 // Private methods | 339 // Private methods |
| 343 | 340 |
| 344 // static | 341 // static |
| 345 HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) { | 342 HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) { |
| 346 string histogram_name; | 343 std::string histogram_name; |
| 347 int flags; | 344 int flags; |
| 348 int declared_min; | 345 int declared_min; |
| 349 int declared_max; | 346 int declared_max; |
| 350 size_t bucket_count; | 347 size_t bucket_count; |
| 351 uint32 range_checksum; | 348 uint32 range_checksum; |
| 352 | 349 |
| 353 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, | 350 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, |
| 354 &declared_max, &bucket_count, &range_checksum)) { | 351 &declared_max, &bucket_count, &range_checksum)) { |
| 355 return NULL; | 352 return NULL; |
| 356 } | 353 } |
| 357 | 354 |
| 358 // Find or create the local version of the histogram in this process. | 355 // Find or create the local version of the histogram in this process. |
| 359 HistogramBase* histogram = Histogram::FactoryGet( | 356 HistogramBase* histogram = Histogram::FactoryGet( |
| 360 histogram_name, declared_min, declared_max, bucket_count, flags); | 357 histogram_name, declared_min, declared_max, bucket_count, flags); |
| 361 | 358 |
| 362 if (!ValidateRangeChecksum(*histogram, range_checksum)) { | 359 if (!ValidateRangeChecksum(*histogram, range_checksum)) { |
| 363 // The serialized histogram might be corrupted. | 360 // The serialized histogram might be corrupted. |
| 364 return NULL; | 361 return NULL; |
| 365 } | 362 } |
| 366 return histogram; | 363 return histogram; |
| 367 } | 364 } |
| 368 | 365 |
| 369 scoped_ptr<SampleVector> Histogram::SnapshotSampleVector() const { | 366 scoped_ptr<SampleVector> Histogram::SnapshotSampleVector() const { |
| 370 scoped_ptr<SampleVector> samples(new SampleVector(bucket_ranges())); | 367 scoped_ptr<SampleVector> samples(new SampleVector(bucket_ranges())); |
| 371 samples->Add(*samples_); | 368 samples->Add(*samples_); |
| 372 return samples.Pass(); | 369 return samples.Pass(); |
| 373 } | 370 } |
| 374 | 371 |
| 375 void Histogram::WriteAsciiImpl(bool graph_it, | 372 void Histogram::WriteAsciiImpl(bool graph_it, |
| 376 const string& newline, | 373 const std::string& newline, |
| 377 string* output) const { | 374 std::string* output) const { |
| 378 // Get local (stack) copies of all effectively volatile class data so that we | 375 // Get local (stack) copies of all effectively volatile class data so that we |
| 379 // are consistent across our output activities. | 376 // are consistent across our output activities. |
| 380 scoped_ptr<SampleVector> snapshot = SnapshotSampleVector(); | 377 scoped_ptr<SampleVector> snapshot = SnapshotSampleVector(); |
| 381 Count sample_count = snapshot->TotalCount(); | 378 Count sample_count = snapshot->TotalCount(); |
| 382 | 379 |
| 383 WriteAsciiHeader(*snapshot, sample_count, output); | 380 WriteAsciiHeader(*snapshot, sample_count, output); |
| 384 output->append(newline); | 381 output->append(newline); |
| 385 | 382 |
| 386 // Prepare to normalize graphical rendering of bucket contents. | 383 // Prepare to normalize graphical rendering of bucket contents. |
| 387 double max_size = 0; | 384 double max_size = 0; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 408 } | 405 } |
| 409 | 406 |
| 410 int64 remaining = sample_count; | 407 int64 remaining = sample_count; |
| 411 int64 past = 0; | 408 int64 past = 0; |
| 412 // Output the actual histogram graph. | 409 // Output the actual histogram graph. |
| 413 for (size_t i = 0; i < bucket_count(); ++i) { | 410 for (size_t i = 0; i < bucket_count(); ++i) { |
| 414 Count current = snapshot->GetCountAtIndex(i); | 411 Count current = snapshot->GetCountAtIndex(i); |
| 415 if (!current && !PrintEmptyBucket(i)) | 412 if (!current && !PrintEmptyBucket(i)) |
| 416 continue; | 413 continue; |
| 417 remaining -= current; | 414 remaining -= current; |
| 418 string range = GetAsciiBucketRange(i); | 415 std::string range = GetAsciiBucketRange(i); |
| 419 output->append(range); | 416 output->append(range); |
| 420 for (size_t j = 0; range.size() + j < print_width + 1; ++j) | 417 for (size_t j = 0; range.size() + j < print_width + 1; ++j) |
| 421 output->push_back(' '); | 418 output->push_back(' '); |
| 422 if (0 == current && i < bucket_count() - 1 && | 419 if (0 == current && i < bucket_count() - 1 && |
| 423 0 == snapshot->GetCountAtIndex(i + 1)) { | 420 0 == snapshot->GetCountAtIndex(i + 1)) { |
| 424 while (i < bucket_count() - 1 && | 421 while (i < bucket_count() - 1 && |
| 425 0 == snapshot->GetCountAtIndex(i + 1)) { | 422 0 == snapshot->GetCountAtIndex(i + 1)) { |
| 426 ++i; | 423 ++i; |
| 427 } | 424 } |
| 428 output->append("... "); | 425 output->append("... "); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 444 for (size_t i = 0; i < bucket_count() ; ++i) { | 441 for (size_t i = 0; i < bucket_count() ; ++i) { |
| 445 double current_size = GetBucketSize(samples.GetCountAtIndex(i), i); | 442 double current_size = GetBucketSize(samples.GetCountAtIndex(i), i); |
| 446 if (current_size > max) | 443 if (current_size > max) |
| 447 max = current_size; | 444 max = current_size; |
| 448 } | 445 } |
| 449 return max; | 446 return max; |
| 450 } | 447 } |
| 451 | 448 |
| 452 void Histogram::WriteAsciiHeader(const SampleVector& samples, | 449 void Histogram::WriteAsciiHeader(const SampleVector& samples, |
| 453 Count sample_count, | 450 Count sample_count, |
| 454 string* output) const { | 451 std::string* output) const { |
| 455 StringAppendF(output, | 452 StringAppendF(output, |
| 456 "Histogram: %s recorded %d samples", | 453 "Histogram: %s recorded %d samples", |
| 457 histogram_name().c_str(), | 454 histogram_name().c_str(), |
| 458 sample_count); | 455 sample_count); |
| 459 if (0 == sample_count) { | 456 if (0 == sample_count) { |
| 460 DCHECK_EQ(samples.sum(), 0); | 457 DCHECK_EQ(samples.sum(), 0); |
| 461 } else { | 458 } else { |
| 462 double average = static_cast<float>(samples.sum()) / sample_count; | 459 double average = static_cast<float>(samples.sum()) / sample_count; |
| 463 | 460 |
| 464 StringAppendF(output, ", average = %.1f", average); | 461 StringAppendF(output, ", average = %.1f", average); |
| 465 } | 462 } |
| 466 if (flags() & ~kHexRangePrintingFlag) | 463 if (flags() & ~kHexRangePrintingFlag) |
| 467 StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag); | 464 StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag); |
| 468 } | 465 } |
| 469 | 466 |
| 470 void Histogram::WriteAsciiBucketContext(const int64 past, | 467 void Histogram::WriteAsciiBucketContext(const int64 past, |
| 471 const Count current, | 468 const Count current, |
| 472 const int64 remaining, | 469 const int64 remaining, |
| 473 const size_t i, | 470 const size_t i, |
| 474 string* output) const { | 471 std::string* output) const { |
| 475 double scaled_sum = (past + current + remaining) / 100.0; | 472 double scaled_sum = (past + current + remaining) / 100.0; |
| 476 WriteAsciiBucketValue(current, scaled_sum, output); | 473 WriteAsciiBucketValue(current, scaled_sum, output); |
| 477 if (0 < i) { | 474 if (0 < i) { |
| 478 double percentage = past / scaled_sum; | 475 double percentage = past / scaled_sum; |
| 479 StringAppendF(output, " {%3.1f%%}", percentage); | 476 StringAppendF(output, " {%3.1f%%}", percentage); |
| 480 } | 477 } |
| 481 } | 478 } |
| 482 | 479 |
| 483 void Histogram::GetParameters(DictionaryValue* params) const { | 480 void Histogram::GetParameters(DictionaryValue* params) const { |
| 484 params->SetString("type", HistogramTypeToString(GetHistogramType())); | 481 params->SetString("type", HistogramTypeToString(GetHistogramType())); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 508 } | 505 } |
| 509 } | 506 } |
| 510 | 507 |
| 511 //------------------------------------------------------------------------------ | 508 //------------------------------------------------------------------------------ |
| 512 // LinearHistogram: This histogram uses a traditional set of evenly spaced | 509 // LinearHistogram: This histogram uses a traditional set of evenly spaced |
| 513 // buckets. | 510 // buckets. |
| 514 //------------------------------------------------------------------------------ | 511 //------------------------------------------------------------------------------ |
| 515 | 512 |
| 516 LinearHistogram::~LinearHistogram() {} | 513 LinearHistogram::~LinearHistogram() {} |
| 517 | 514 |
| 518 HistogramBase* LinearHistogram::FactoryGet(const string& name, | 515 HistogramBase* LinearHistogram::FactoryGet(const std::string& name, |
| 519 Sample minimum, | 516 Sample minimum, |
| 520 Sample maximum, | 517 Sample maximum, |
| 521 size_t bucket_count, | 518 size_t bucket_count, |
| 522 int32 flags) { | 519 int32 flags) { |
| 523 return FactoryGetWithRangeDescription( | 520 return FactoryGetWithRangeDescription( |
| 524 name, minimum, maximum, bucket_count, flags, NULL); | 521 name, minimum, maximum, bucket_count, flags, NULL); |
| 525 } | 522 } |
| 526 | 523 |
| 527 HistogramBase* LinearHistogram::FactoryTimeGet(const string& name, | 524 HistogramBase* LinearHistogram::FactoryTimeGet(const std::string& name, |
| 528 TimeDelta minimum, | 525 TimeDelta minimum, |
| 529 TimeDelta maximum, | 526 TimeDelta maximum, |
| 530 size_t bucket_count, | 527 size_t bucket_count, |
| 531 int32 flags) { | 528 int32 flags) { |
| 532 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()), | 529 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()), |
| 533 static_cast<Sample>(maximum.InMilliseconds()), bucket_count, | 530 static_cast<Sample>(maximum.InMilliseconds()), bucket_count, |
| 534 flags); | 531 flags); |
| 535 } | 532 } |
| 536 | 533 |
| 537 HistogramBase* LinearHistogram::FactoryGetWithRangeDescription( | 534 HistogramBase* LinearHistogram::FactoryGetWithRangeDescription( |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 580 DLOG(ERROR) << "Histogram " << name << " has bad construction arguments"; | 577 DLOG(ERROR) << "Histogram " << name << " has bad construction arguments"; |
| 581 return NULL; | 578 return NULL; |
| 582 } | 579 } |
| 583 return histogram; | 580 return histogram; |
| 584 } | 581 } |
| 585 | 582 |
| 586 HistogramType LinearHistogram::GetHistogramType() const { | 583 HistogramType LinearHistogram::GetHistogramType() const { |
| 587 return LINEAR_HISTOGRAM; | 584 return LINEAR_HISTOGRAM; |
| 588 } | 585 } |
| 589 | 586 |
| 590 LinearHistogram::LinearHistogram(const string& name, | 587 LinearHistogram::LinearHistogram(const std::string& name, |
| 591 Sample minimum, | 588 Sample minimum, |
| 592 Sample maximum, | 589 Sample maximum, |
| 593 const BucketRanges* ranges) | 590 const BucketRanges* ranges) |
| 594 : Histogram(name, minimum, maximum, ranges) { | 591 : Histogram(name, minimum, maximum, ranges) { |
| 595 } | 592 } |
| 596 | 593 |
| 597 double LinearHistogram::GetBucketSize(Count current, size_t i) const { | 594 double LinearHistogram::GetBucketSize(Count current, size_t i) const { |
| 598 DCHECK_GT(ranges(i + 1), ranges(i)); | 595 DCHECK_GT(ranges(i + 1), ranges(i)); |
| 599 // Adjacent buckets with different widths would have "surprisingly" many (few) | 596 // Adjacent buckets with different widths would have "surprisingly" many (few) |
| 600 // samples in a histogram if we didn't normalize this way. | 597 // samples in a histogram if we didn't normalize this way. |
| 601 double denominator = ranges(i + 1) - ranges(i); | 598 double denominator = ranges(i + 1) - ranges(i); |
| 602 return current/denominator; | 599 return current/denominator; |
| 603 } | 600 } |
| 604 | 601 |
| 605 const string LinearHistogram::GetAsciiBucketRange(size_t i) const { | 602 const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const { |
| 606 int range = ranges(i); | 603 int range = ranges(i); |
| 607 BucketDescriptionMap::const_iterator it = bucket_description_.find(range); | 604 BucketDescriptionMap::const_iterator it = bucket_description_.find(range); |
| 608 if (it == bucket_description_.end()) | 605 if (it == bucket_description_.end()) |
| 609 return Histogram::GetAsciiBucketRange(i); | 606 return Histogram::GetAsciiBucketRange(i); |
| 610 return it->second; | 607 return it->second; |
| 611 } | 608 } |
| 612 | 609 |
| 613 bool LinearHistogram::PrintEmptyBucket(size_t index) const { | 610 bool LinearHistogram::PrintEmptyBucket(size_t index) const { |
| 614 return bucket_description_.find(ranges(index)) == bucket_description_.end(); | 611 return bucket_description_.find(ranges(index)) == bucket_description_.end(); |
| 615 } | 612 } |
| 616 | 613 |
| 617 // static | 614 // static |
| 618 void LinearHistogram::InitializeBucketRanges(Sample minimum, | 615 void LinearHistogram::InitializeBucketRanges(Sample minimum, |
| 619 Sample maximum, | 616 Sample maximum, |
| 620 BucketRanges* ranges) { | 617 BucketRanges* ranges) { |
| 621 double min = minimum; | 618 double min = minimum; |
| 622 double max = maximum; | 619 double max = maximum; |
| 623 size_t bucket_count = ranges->bucket_count(); | 620 size_t bucket_count = ranges->bucket_count(); |
| 624 for (size_t i = 1; i < bucket_count; ++i) { | 621 for (size_t i = 1; i < bucket_count; ++i) { |
| 625 double linear_range = | 622 double linear_range = |
| 626 (min * (bucket_count - 1 - i) + max * (i - 1)) / (bucket_count - 2); | 623 (min * (bucket_count - 1 - i) + max * (i - 1)) / (bucket_count - 2); |
| 627 ranges->set_range(i, static_cast<Sample>(linear_range + 0.5)); | 624 ranges->set_range(i, static_cast<Sample>(linear_range + 0.5)); |
| 628 } | 625 } |
| 629 ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX); | 626 ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX); |
| 630 ranges->ResetChecksum(); | 627 ranges->ResetChecksum(); |
| 631 } | 628 } |
| 632 | 629 |
| 633 // static | 630 // static |
| 634 HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) { | 631 HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) { |
| 635 string histogram_name; | 632 std::string histogram_name; |
| 636 int flags; | 633 int flags; |
| 637 int declared_min; | 634 int declared_min; |
| 638 int declared_max; | 635 int declared_max; |
| 639 size_t bucket_count; | 636 size_t bucket_count; |
| 640 uint32 range_checksum; | 637 uint32 range_checksum; |
| 641 | 638 |
| 642 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, | 639 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, |
| 643 &declared_max, &bucket_count, &range_checksum)) { | 640 &declared_max, &bucket_count, &range_checksum)) { |
| 644 return NULL; | 641 return NULL; |
| 645 } | 642 } |
| 646 | 643 |
| 647 HistogramBase* histogram = LinearHistogram::FactoryGet( | 644 HistogramBase* histogram = LinearHistogram::FactoryGet( |
| 648 histogram_name, declared_min, declared_max, bucket_count, flags); | 645 histogram_name, declared_min, declared_max, bucket_count, flags); |
| 649 if (!ValidateRangeChecksum(*histogram, range_checksum)) { | 646 if (!ValidateRangeChecksum(*histogram, range_checksum)) { |
| 650 // The serialized histogram might be corrupted. | 647 // The serialized histogram might be corrupted. |
| 651 return NULL; | 648 return NULL; |
| 652 } | 649 } |
| 653 return histogram; | 650 return histogram; |
| 654 } | 651 } |
| 655 | 652 |
| 656 //------------------------------------------------------------------------------ | 653 //------------------------------------------------------------------------------ |
| 657 // This section provides implementation for BooleanHistogram. | 654 // This section provides implementation for BooleanHistogram. |
| 658 //------------------------------------------------------------------------------ | 655 //------------------------------------------------------------------------------ |
| 659 | 656 |
| 660 HistogramBase* BooleanHistogram::FactoryGet(const string& name, int32 flags) { | 657 HistogramBase* BooleanHistogram::FactoryGet(const std::string& name, |
| 658 int32 flags) { |
| 661 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 659 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); |
| 662 if (!histogram) { | 660 if (!histogram) { |
| 663 // To avoid racy destruction at shutdown, the following will be leaked. | 661 // To avoid racy destruction at shutdown, the following will be leaked. |
| 664 BucketRanges* ranges = new BucketRanges(4); | 662 BucketRanges* ranges = new BucketRanges(4); |
| 665 LinearHistogram::InitializeBucketRanges(1, 2, ranges); | 663 LinearHistogram::InitializeBucketRanges(1, 2, ranges); |
| 666 const BucketRanges* registered_ranges = | 664 const BucketRanges* registered_ranges = |
| 667 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | 665 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); |
| 668 | 666 |
| 669 BooleanHistogram* tentative_histogram = | 667 BooleanHistogram* tentative_histogram = |
| 670 new BooleanHistogram(name, registered_ranges); | 668 new BooleanHistogram(name, registered_ranges); |
| 671 | 669 |
| 672 tentative_histogram->SetFlags(flags); | 670 tentative_histogram->SetFlags(flags); |
| 673 histogram = | 671 histogram = |
| 674 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | 672 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
| 675 } | 673 } |
| 676 | 674 |
| 677 DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType()); | 675 DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType()); |
| 678 return histogram; | 676 return histogram; |
| 679 } | 677 } |
| 680 | 678 |
| 681 HistogramType BooleanHistogram::GetHistogramType() const { | 679 HistogramType BooleanHistogram::GetHistogramType() const { |
| 682 return BOOLEAN_HISTOGRAM; | 680 return BOOLEAN_HISTOGRAM; |
| 683 } | 681 } |
| 684 | 682 |
| 685 BooleanHistogram::BooleanHistogram(const string& name, | 683 BooleanHistogram::BooleanHistogram(const std::string& name, |
| 686 const BucketRanges* ranges) | 684 const BucketRanges* ranges) |
| 687 : LinearHistogram(name, 1, 2, ranges) {} | 685 : LinearHistogram(name, 1, 2, ranges) {} |
| 688 | 686 |
| 689 HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) { | 687 HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) { |
| 690 string histogram_name; | 688 std::string histogram_name; |
| 691 int flags; | 689 int flags; |
| 692 int declared_min; | 690 int declared_min; |
| 693 int declared_max; | 691 int declared_max; |
| 694 size_t bucket_count; | 692 size_t bucket_count; |
| 695 uint32 range_checksum; | 693 uint32 range_checksum; |
| 696 | 694 |
| 697 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, | 695 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, |
| 698 &declared_max, &bucket_count, &range_checksum)) { | 696 &declared_max, &bucket_count, &range_checksum)) { |
| 699 return NULL; | 697 return NULL; |
| 700 } | 698 } |
| 701 | 699 |
| 702 HistogramBase* histogram = BooleanHistogram::FactoryGet( | 700 HistogramBase* histogram = BooleanHistogram::FactoryGet( |
| 703 histogram_name, flags); | 701 histogram_name, flags); |
| 704 if (!ValidateRangeChecksum(*histogram, range_checksum)) { | 702 if (!ValidateRangeChecksum(*histogram, range_checksum)) { |
| 705 // The serialized histogram might be corrupted. | 703 // The serialized histogram might be corrupted. |
| 706 return NULL; | 704 return NULL; |
| 707 } | 705 } |
| 708 return histogram; | 706 return histogram; |
| 709 } | 707 } |
| 710 | 708 |
| 711 //------------------------------------------------------------------------------ | 709 //------------------------------------------------------------------------------ |
| 712 // CustomHistogram: | 710 // CustomHistogram: |
| 713 //------------------------------------------------------------------------------ | 711 //------------------------------------------------------------------------------ |
| 714 | 712 |
| 715 HistogramBase* CustomHistogram::FactoryGet(const string& name, | 713 HistogramBase* CustomHistogram::FactoryGet( |
| 716 const vector<Sample>& custom_ranges, | 714 const std::string& name, |
| 717 int32 flags) { | 715 const std::vector<Sample>& custom_ranges, |
| 716 int32 flags) { |
| 718 CHECK(ValidateCustomRanges(custom_ranges)); | 717 CHECK(ValidateCustomRanges(custom_ranges)); |
| 719 | 718 |
| 720 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 719 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); |
| 721 if (!histogram) { | 720 if (!histogram) { |
| 722 BucketRanges* ranges = CreateBucketRangesFromCustomRanges(custom_ranges); | 721 BucketRanges* ranges = CreateBucketRangesFromCustomRanges(custom_ranges); |
| 723 const BucketRanges* registered_ranges = | 722 const BucketRanges* registered_ranges = |
| 724 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | 723 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); |
| 725 | 724 |
| 726 // To avoid racy destruction at shutdown, the following will be leaked. | 725 // To avoid racy destruction at shutdown, the following will be leaked. |
| 727 CustomHistogram* tentative_histogram = | 726 CustomHistogram* tentative_histogram = |
| 728 new CustomHistogram(name, registered_ranges); | 727 new CustomHistogram(name, registered_ranges); |
| 729 | 728 |
| 730 tentative_histogram->SetFlags(flags); | 729 tentative_histogram->SetFlags(flags); |
| 731 | 730 |
| 732 histogram = | 731 histogram = |
| 733 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | 732 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
| 734 } | 733 } |
| 735 | 734 |
| 736 DCHECK_EQ(histogram->GetHistogramType(), CUSTOM_HISTOGRAM); | 735 DCHECK_EQ(histogram->GetHistogramType(), CUSTOM_HISTOGRAM); |
| 737 return histogram; | 736 return histogram; |
| 738 } | 737 } |
| 739 | 738 |
| 740 HistogramType CustomHistogram::GetHistogramType() const { | 739 HistogramType CustomHistogram::GetHistogramType() const { |
| 741 return CUSTOM_HISTOGRAM; | 740 return CUSTOM_HISTOGRAM; |
| 742 } | 741 } |
| 743 | 742 |
| 744 // static | 743 // static |
| 745 vector<Sample> CustomHistogram::ArrayToCustomRanges( | 744 std::vector<Sample> CustomHistogram::ArrayToCustomRanges( |
| 746 const Sample* values, size_t num_values) { | 745 const Sample* values, size_t num_values) { |
| 747 vector<Sample> all_values; | 746 std::vector<Sample> all_values; |
| 748 for (size_t i = 0; i < num_values; ++i) { | 747 for (size_t i = 0; i < num_values; ++i) { |
| 749 Sample value = values[i]; | 748 Sample value = values[i]; |
| 750 all_values.push_back(value); | 749 all_values.push_back(value); |
| 751 | 750 |
| 752 // Ensure that a guard bucket is added. If we end up with duplicate | 751 // Ensure that a guard bucket is added. If we end up with duplicate |
| 753 // values, FactoryGet will take care of removing them. | 752 // values, FactoryGet will take care of removing them. |
| 754 all_values.push_back(value + 1); | 753 all_values.push_back(value + 1); |
| 755 } | 754 } |
| 756 return all_values; | 755 return all_values; |
| 757 } | 756 } |
| 758 | 757 |
| 759 CustomHistogram::CustomHistogram(const string& name, | 758 CustomHistogram::CustomHistogram(const std::string& name, |
| 760 const BucketRanges* ranges) | 759 const BucketRanges* ranges) |
| 761 : Histogram(name, | 760 : Histogram(name, |
| 762 ranges->range(1), | 761 ranges->range(1), |
| 763 ranges->range(ranges->bucket_count() - 1), | 762 ranges->range(ranges->bucket_count() - 1), |
| 764 ranges) {} | 763 ranges) {} |
| 765 | 764 |
| 766 bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const { | 765 bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const { |
| 767 if (!Histogram::SerializeInfoImpl(pickle)) | 766 if (!Histogram::SerializeInfoImpl(pickle)) |
| 768 return false; | 767 return false; |
| 769 | 768 |
| 770 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't | 769 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't |
| 771 // write them. | 770 // write them. |
| 772 for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) { | 771 for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) { |
| 773 if (!pickle->WriteInt(bucket_ranges()->range(i))) | 772 if (!pickle->WriteInt(bucket_ranges()->range(i))) |
| 774 return false; | 773 return false; |
| 775 } | 774 } |
| 776 return true; | 775 return true; |
| 777 } | 776 } |
| 778 | 777 |
| 779 double CustomHistogram::GetBucketSize(Count current, size_t i) const { | 778 double CustomHistogram::GetBucketSize(Count current, size_t i) const { |
| 780 return 1; | 779 return 1; |
| 781 } | 780 } |
| 782 | 781 |
| 783 // static | 782 // static |
| 784 HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) { | 783 HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) { |
| 785 string histogram_name; | 784 std::string histogram_name; |
| 786 int flags; | 785 int flags; |
| 787 int declared_min; | 786 int declared_min; |
| 788 int declared_max; | 787 int declared_max; |
| 789 size_t bucket_count; | 788 size_t bucket_count; |
| 790 uint32 range_checksum; | 789 uint32 range_checksum; |
| 791 | 790 |
| 792 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, | 791 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, |
| 793 &declared_max, &bucket_count, &range_checksum)) { | 792 &declared_max, &bucket_count, &range_checksum)) { |
| 794 return NULL; | 793 return NULL; |
| 795 } | 794 } |
| 796 | 795 |
| 797 // First and last ranges are not serialized. | 796 // First and last ranges are not serialized. |
| 798 vector<Sample> sample_ranges(bucket_count - 1); | 797 std::vector<Sample> sample_ranges(bucket_count - 1); |
| 799 | 798 |
| 800 for (size_t i = 0; i < sample_ranges.size(); ++i) { | 799 for (size_t i = 0; i < sample_ranges.size(); ++i) { |
| 801 if (!iter->ReadInt(&sample_ranges[i])) | 800 if (!iter->ReadInt(&sample_ranges[i])) |
| 802 return NULL; | 801 return NULL; |
| 803 } | 802 } |
| 804 | 803 |
| 805 HistogramBase* histogram = CustomHistogram::FactoryGet( | 804 HistogramBase* histogram = CustomHistogram::FactoryGet( |
| 806 histogram_name, sample_ranges, flags); | 805 histogram_name, sample_ranges, flags); |
| 807 if (!ValidateRangeChecksum(*histogram, range_checksum)) { | 806 if (!ValidateRangeChecksum(*histogram, range_checksum)) { |
| 808 // The serialized histogram might be corrupted. | 807 // The serialized histogram might be corrupted. |
| 809 return NULL; | 808 return NULL; |
| 810 } | 809 } |
| 811 return histogram; | 810 return histogram; |
| 812 } | 811 } |
| 813 | 812 |
| 814 // static | 813 // static |
| 815 bool CustomHistogram::ValidateCustomRanges( | 814 bool CustomHistogram::ValidateCustomRanges( |
| 816 const vector<Sample>& custom_ranges) { | 815 const std::vector<Sample>& custom_ranges) { |
| 817 bool has_valid_range = false; | 816 bool has_valid_range = false; |
| 818 for (size_t i = 0; i < custom_ranges.size(); i++) { | 817 for (size_t i = 0; i < custom_ranges.size(); i++) { |
| 819 Sample sample = custom_ranges[i]; | 818 Sample sample = custom_ranges[i]; |
| 820 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) | 819 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) |
| 821 return false; | 820 return false; |
| 822 if (sample != 0) | 821 if (sample != 0) |
| 823 has_valid_range = true; | 822 has_valid_range = true; |
| 824 } | 823 } |
| 825 return has_valid_range; | 824 return has_valid_range; |
| 826 } | 825 } |
| 827 | 826 |
| 828 // static | 827 // static |
| 829 BucketRanges* CustomHistogram::CreateBucketRangesFromCustomRanges( | 828 BucketRanges* CustomHistogram::CreateBucketRangesFromCustomRanges( |
| 830 const vector<Sample>& custom_ranges) { | 829 const std::vector<Sample>& custom_ranges) { |
| 831 // Remove the duplicates in the custom ranges array. | 830 // Remove the duplicates in the custom ranges array. |
| 832 vector<int> ranges = custom_ranges; | 831 std::vector<int> ranges = custom_ranges; |
| 833 ranges.push_back(0); // Ensure we have a zero value. | 832 ranges.push_back(0); // Ensure we have a zero value. |
| 834 ranges.push_back(HistogramBase::kSampleType_MAX); | 833 ranges.push_back(HistogramBase::kSampleType_MAX); |
| 835 std::sort(ranges.begin(), ranges.end()); | 834 std::sort(ranges.begin(), ranges.end()); |
| 836 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end()); | 835 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end()); |
| 837 | 836 |
| 838 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); | 837 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); |
| 839 for (size_t i = 0; i < ranges.size(); i++) { | 838 for (size_t i = 0; i < ranges.size(); i++) { |
| 840 bucket_ranges->set_range(i, ranges[i]); | 839 bucket_ranges->set_range(i, ranges[i]); |
| 841 } | 840 } |
| 842 bucket_ranges->ResetChecksum(); | 841 bucket_ranges->ResetChecksum(); |
| 843 return bucket_ranges; | 842 return bucket_ranges; |
| 844 } | 843 } |
| 845 | 844 |
| 846 } // namespace base | 845 } // namespace base |
| OLD | NEW |