| 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" |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 size_t bucket_count, | 90 size_t bucket_count, |
| 91 int32 flags) { | 91 int32 flags) { |
| 92 bool valid_arguments = | 92 bool valid_arguments = |
| 93 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); | 93 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); |
| 94 DCHECK(valid_arguments); | 94 DCHECK(valid_arguments); |
| 95 | 95 |
| 96 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 96 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); |
| 97 if (!histogram) { | 97 if (!histogram) { |
| 98 // To avoid racy destruction at shutdown, the following will be leaked. | 98 // To avoid racy destruction at shutdown, the following will be leaked. |
| 99 BucketRanges* ranges = new BucketRanges(bucket_count + 1); | 99 BucketRanges* ranges = new BucketRanges(bucket_count + 1); |
| 100 InitializeBucketRanges(minimum, maximum, bucket_count, ranges); | 100 InitializeBucketRanges(minimum, maximum, ranges); |
| 101 const BucketRanges* registered_ranges = | 101 const BucketRanges* registered_ranges = |
| 102 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | 102 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); |
| 103 | 103 |
| 104 Histogram* tentative_histogram = | 104 Histogram* tentative_histogram = |
| 105 new Histogram(name, minimum, maximum, bucket_count, registered_ranges); | 105 new Histogram(name, minimum, maximum, registered_ranges); |
| 106 | 106 |
| 107 tentative_histogram->SetFlags(flags); | 107 tentative_histogram->SetFlags(flags); |
| 108 histogram = | 108 histogram = |
| 109 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | 109 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
| 110 } | 110 } |
| 111 | 111 |
| 112 DCHECK_EQ(HISTOGRAM, histogram->GetHistogramType()); | 112 DCHECK_EQ(HISTOGRAM, histogram->GetHistogramType()); |
| 113 CHECK(histogram->HasConstructionArguments(minimum, maximum, bucket_count)); | 113 CHECK(histogram->HasConstructionArguments(minimum, maximum, bucket_count)); |
| 114 return histogram; | 114 return histogram; |
| 115 } | 115 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 136 // consecutive buckets that is sooo small, that the integer bounds are the same | 136 // consecutive buckets that is sooo small, that the integer bounds are the same |
| 137 // (effectively making one bucket get no values). We need to avoid: | 137 // (effectively making one bucket get no values). We need to avoid: |
| 138 // ranges(i) == ranges(i + 1) | 138 // ranges(i) == ranges(i + 1) |
| 139 // To avoid that, we just do a fine-grained bucket width as far as we need to | 139 // To avoid that, we just do a fine-grained bucket width as far as we need to |
| 140 // until we get a ratio that moves us along at least 2 units at a time. From | 140 // until we get a ratio that moves us along at least 2 units at a time. From |
| 141 // that bucket onward we do use the exponential growth of buckets. | 141 // that bucket onward we do use the exponential growth of buckets. |
| 142 // | 142 // |
| 143 // static | 143 // static |
| 144 void Histogram::InitializeBucketRanges(Sample minimum, | 144 void Histogram::InitializeBucketRanges(Sample minimum, |
| 145 Sample maximum, | 145 Sample maximum, |
| 146 size_t bucket_count, | |
| 147 BucketRanges* ranges) { | 146 BucketRanges* ranges) { |
| 148 DCHECK_EQ(ranges->size(), bucket_count + 1); | |
| 149 double log_max = log(static_cast<double>(maximum)); | 147 double log_max = log(static_cast<double>(maximum)); |
| 150 double log_ratio; | 148 double log_ratio; |
| 151 double log_next; | 149 double log_next; |
| 152 size_t bucket_index = 1; | 150 size_t bucket_index = 1; |
| 153 Sample current = minimum; | 151 Sample current = minimum; |
| 154 ranges->set_range(bucket_index, current); | 152 ranges->set_range(bucket_index, current); |
| 153 size_t bucket_count = ranges->BucketCount(); |
| 155 while (bucket_count > ++bucket_index) { | 154 while (bucket_count > ++bucket_index) { |
| 156 double log_current; | 155 double log_current; |
| 157 log_current = log(static_cast<double>(current)); | 156 log_current = log(static_cast<double>(current)); |
| 158 // Calculate the count'th root of the range. | 157 // Calculate the count'th root of the range. |
| 159 log_ratio = (log_max - log_current) / (bucket_count - bucket_index); | 158 log_ratio = (log_max - log_current) / (bucket_count - bucket_index); |
| 160 // See where the next bucket would start. | 159 // See where the next bucket would start. |
| 161 log_next = log_current + log_ratio; | 160 log_next = log_current + log_ratio; |
| 162 Sample next; | 161 Sample next; |
| 163 next = static_cast<int>(floor(exp(log_next) + 0.5)); | 162 next = static_cast<int>(floor(exp(log_next) + 0.5)); |
| 164 if (next > current) | 163 if (next > current) |
| 165 current = next; | 164 current = next; |
| 166 else | 165 else |
| 167 ++current; // Just do a narrow bucket, and keep trying. | 166 ++current; // Just do a narrow bucket, and keep trying. |
| 168 ranges->set_range(bucket_index, current); | 167 ranges->set_range(bucket_index, current); |
| 169 } | 168 } |
| 170 ranges->set_range(ranges->size() - 1, HistogramBase::kSampleType_MAX); | 169 ranges->set_range(ranges->BucketCount(), HistogramBase::kSampleType_MAX); |
| 171 ranges->ResetChecksum(); | 170 ranges->ResetChecksum(); |
| 172 } | 171 } |
| 173 | 172 |
| 174 // static | 173 // static |
| 175 const int Histogram::kCommonRaceBasedCountMismatch = 5; | 174 const int Histogram::kCommonRaceBasedCountMismatch = 5; |
| 176 | 175 |
| 177 int Histogram::FindCorruption(const HistogramSamples& samples) const { | 176 int Histogram::FindCorruption(const HistogramSamples& samples) const { |
| 178 int inconsistencies = NO_INCONSISTENCIES; | 177 int inconsistencies = NO_INCONSISTENCIES; |
| 179 Sample previous_range = -1; // Bottom range is always 0. | 178 Sample previous_range = -1; // Bottom range is always 0. |
| 180 for (size_t index = 0; index < bucket_count(); ++index) { | 179 for (size_t index = 0; index < BucketCount(); ++index) { |
| 181 int new_range = ranges(index); | 180 int new_range = ranges(index); |
| 182 if (previous_range >= new_range) | 181 if (previous_range >= new_range) |
| 183 inconsistencies |= BUCKET_ORDER_ERROR; | 182 inconsistencies |= BUCKET_ORDER_ERROR; |
| 184 previous_range = new_range; | 183 previous_range = new_range; |
| 185 } | 184 } |
| 186 | 185 |
| 187 if (!bucket_ranges()->HasValidChecksum()) | 186 if (!bucket_ranges()->HasValidChecksum()) |
| 188 inconsistencies |= RANGE_CHECKSUM_ERROR; | 187 inconsistencies |= RANGE_CHECKSUM_ERROR; |
| 189 | 188 |
| 190 int64 delta64 = samples.redundant_count() - samples.TotalCount(); | 189 int64 delta64 = samples.redundant_count() - samples.TotalCount(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 203 inconsistencies |= COUNT_LOW_ERROR; | 202 inconsistencies |= COUNT_LOW_ERROR; |
| 204 } | 203 } |
| 205 } | 204 } |
| 206 return inconsistencies; | 205 return inconsistencies; |
| 207 } | 206 } |
| 208 | 207 |
| 209 Sample Histogram::ranges(size_t i) const { | 208 Sample Histogram::ranges(size_t i) const { |
| 210 return bucket_ranges_->range(i); | 209 return bucket_ranges_->range(i); |
| 211 } | 210 } |
| 212 | 211 |
| 213 size_t Histogram::bucket_count() const { | 212 size_t Histogram::BucketCount() const { |
| 214 return bucket_count_; | 213 return bucket_ranges_->BucketCount(); |
| 215 } | 214 } |
| 216 | 215 |
| 217 // static | 216 // static |
| 218 bool Histogram::InspectConstructionArguments(const string& name, | 217 bool Histogram::InspectConstructionArguments(const string& name, |
| 219 Sample* minimum, | 218 Sample* minimum, |
| 220 Sample* maximum, | 219 Sample* maximum, |
| 221 size_t* bucket_count) { | 220 size_t* bucket_count) { |
| 222 // Defensive code for backward compatibility. | 221 // Defensive code for backward compatibility. |
| 223 if (*minimum < 1) { | 222 if (*minimum < 1) { |
| 224 DVLOG(1) << "Histogram: " << name << " has bad minimum: " << *minimum; | 223 DVLOG(1) << "Histogram: " << name << " has bad minimum: " << *minimum; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 244 } | 243 } |
| 245 | 244 |
| 246 HistogramType Histogram::GetHistogramType() const { | 245 HistogramType Histogram::GetHistogramType() const { |
| 247 return HISTOGRAM; | 246 return HISTOGRAM; |
| 248 } | 247 } |
| 249 | 248 |
| 250 bool Histogram::HasConstructionArguments(Sample minimum, | 249 bool Histogram::HasConstructionArguments(Sample minimum, |
| 251 Sample maximum, | 250 Sample maximum, |
| 252 size_t bucket_count) const { | 251 size_t bucket_count) const { |
| 253 return ((minimum == declared_min_) && (maximum == declared_max_) && | 252 return ((minimum == declared_min_) && (maximum == declared_max_) && |
| 254 (bucket_count == bucket_count_)); | 253 (bucket_count == BucketCount())); |
| 255 } | 254 } |
| 256 | 255 |
| 257 void Histogram::Add(int value) { | 256 void Histogram::Add(int value) { |
| 258 DCHECK_EQ(0, ranges(0)); | 257 DCHECK_EQ(0, ranges(0)); |
| 259 DCHECK_EQ(kSampleType_MAX, ranges(bucket_count_)); | 258 DCHECK_EQ(kSampleType_MAX, ranges(BucketCount())); |
| 260 | 259 |
| 261 if (value > kSampleType_MAX - 1) | 260 if (value > kSampleType_MAX - 1) |
| 262 value = kSampleType_MAX - 1; | 261 value = kSampleType_MAX - 1; |
| 263 if (value < 0) | 262 if (value < 0) |
| 264 value = 0; | 263 value = 0; |
| 265 samples_->Accumulate(value, 1); | 264 samples_->Accumulate(value, 1); |
| 266 } | 265 } |
| 267 | 266 |
| 268 scoped_ptr<HistogramSamples> Histogram::SnapshotSamples() const { | 267 scoped_ptr<HistogramSamples> Histogram::SnapshotSamples() const { |
| 269 return SnapshotSampleVector().PassAs<HistogramSamples>(); | 268 return SnapshotSampleVector().PassAs<HistogramSamples>(); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 288 void Histogram::WriteAscii(string* output) const { | 287 void Histogram::WriteAscii(string* output) const { |
| 289 WriteAsciiImpl(true, "\n", output); | 288 WriteAsciiImpl(true, "\n", output); |
| 290 } | 289 } |
| 291 | 290 |
| 292 bool Histogram::SerializeInfoImpl(Pickle* pickle) const { | 291 bool Histogram::SerializeInfoImpl(Pickle* pickle) const { |
| 293 DCHECK(bucket_ranges()->HasValidChecksum()); | 292 DCHECK(bucket_ranges()->HasValidChecksum()); |
| 294 return pickle->WriteString(histogram_name()) && | 293 return pickle->WriteString(histogram_name()) && |
| 295 pickle->WriteInt(flags()) && | 294 pickle->WriteInt(flags()) && |
| 296 pickle->WriteInt(declared_min()) && | 295 pickle->WriteInt(declared_min()) && |
| 297 pickle->WriteInt(declared_max()) && | 296 pickle->WriteInt(declared_max()) && |
| 298 pickle->WriteUInt64(bucket_count()) && | 297 pickle->WriteUInt64(BucketCount()) && |
| 299 pickle->WriteUInt32(bucket_ranges()->checksum()); | 298 pickle->WriteUInt32(bucket_ranges()->checksum()); |
| 300 } | 299 } |
| 301 | 300 |
| 302 Histogram::Histogram(const string& name, | 301 Histogram::Histogram(const string& name, |
| 303 Sample minimum, | 302 Sample minimum, |
| 304 Sample maximum, | 303 Sample maximum, |
| 305 size_t bucket_count, | |
| 306 const BucketRanges* ranges) | 304 const BucketRanges* ranges) |
| 307 : HistogramBase(name), | 305 : HistogramBase(name), |
| 308 bucket_ranges_(ranges), | 306 bucket_ranges_(ranges), |
| 309 declared_min_(minimum), | 307 declared_min_(minimum), |
| 310 declared_max_(maximum), | 308 declared_max_(maximum) { |
| 311 bucket_count_(bucket_count) { | |
| 312 if (ranges) | 309 if (ranges) |
| 313 samples_.reset(new SampleVector(ranges)); | 310 samples_.reset(new SampleVector(ranges)); |
| 314 } | 311 } |
| 315 | 312 |
| 316 Histogram::~Histogram() { | 313 Histogram::~Histogram() { |
| 317 } | 314 } |
| 318 | 315 |
| 319 bool Histogram::PrintEmptyBucket(size_t index) const { | 316 bool Histogram::PrintEmptyBucket(size_t index) const { |
| 320 return true; | 317 return true; |
| 321 } | 318 } |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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; |
| 388 if (graph_it) | 385 if (graph_it) |
| 389 max_size = GetPeakBucketSize(*snapshot); | 386 max_size = GetPeakBucketSize(*snapshot); |
| 390 | 387 |
| 391 // Calculate space needed to print bucket range numbers. Leave room to print | 388 // Calculate space needed to print bucket range numbers. Leave room to print |
| 392 // nearly the largest bucket range without sliding over the histogram. | 389 // nearly the largest bucket range without sliding over the histogram. |
| 393 size_t largest_non_empty_bucket = bucket_count() - 1; | 390 size_t largest_non_empty_bucket = BucketCount() - 1; |
| 394 while (0 == snapshot->GetCountAtIndex(largest_non_empty_bucket)) { | 391 while (0 == snapshot->GetCountAtIndex(largest_non_empty_bucket)) { |
| 395 if (0 == largest_non_empty_bucket) | 392 if (0 == largest_non_empty_bucket) |
| 396 break; // All buckets are empty. | 393 break; // All buckets are empty. |
| 397 --largest_non_empty_bucket; | 394 --largest_non_empty_bucket; |
| 398 } | 395 } |
| 399 | 396 |
| 400 // Calculate largest print width needed for any of our bucket range displays. | 397 // Calculate largest print width needed for any of our bucket range displays. |
| 401 size_t print_width = 1; | 398 size_t print_width = 1; |
| 402 for (size_t i = 0; i < bucket_count(); ++i) { | 399 for (size_t i = 0; i < BucketCount(); ++i) { |
| 403 if (snapshot->GetCountAtIndex(i)) { | 400 if (snapshot->GetCountAtIndex(i)) { |
| 404 size_t width = GetAsciiBucketRange(i).size() + 1; | 401 size_t width = GetAsciiBucketRange(i).size() + 1; |
| 405 if (width > print_width) | 402 if (width > print_width) |
| 406 print_width = width; | 403 print_width = width; |
| 407 } | 404 } |
| 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 < BucketCount(); ++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 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 < BucketCount() - 1 && |
| 423 0 == snapshot->GetCountAtIndex(i + 1)) { | 420 0 == snapshot->GetCountAtIndex(i + 1)) { |
| 424 while (i < bucket_count() - 1 && | 421 while (i < BucketCount() - 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("... "); |
| 429 output->append(newline); | 426 output->append(newline); |
| 430 continue; // No reason to plot emptiness. | 427 continue; // No reason to plot emptiness. |
| 431 } | 428 } |
| 432 double current_size = GetBucketSize(current, i); | 429 double current_size = GetBucketSize(current, i); |
| 433 if (graph_it) | 430 if (graph_it) |
| 434 WriteAsciiBucketGraph(current_size, max_size, output); | 431 WriteAsciiBucketGraph(current_size, max_size, output); |
| 435 WriteAsciiBucketContext(past, current, remaining, i, output); | 432 WriteAsciiBucketContext(past, current, remaining, i, output); |
| 436 output->append(newline); | 433 output->append(newline); |
| 437 past += current; | 434 past += current; |
| 438 } | 435 } |
| 439 DCHECK_EQ(sample_count, past); | 436 DCHECK_EQ(sample_count, past); |
| 440 } | 437 } |
| 441 | 438 |
| 442 double Histogram::GetPeakBucketSize(const SampleVector& samples) const { | 439 double Histogram::GetPeakBucketSize(const SampleVector& samples) const { |
| 443 double max = 0; | 440 double max = 0; |
| 444 for (size_t i = 0; i < bucket_count() ; ++i) { | 441 for (size_t i = 0; i < BucketCount() ; ++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 string* output) const { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 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())); |
| 485 params->SetInteger("min", declared_min()); | 482 params->SetInteger("min", declared_min()); |
| 486 params->SetInteger("max", declared_max()); | 483 params->SetInteger("max", declared_max()); |
| 487 params->SetInteger("bucket_count", static_cast<int>(bucket_count())); | 484 params->SetInteger("bucket_count", static_cast<int>(BucketCount())); |
| 488 } | 485 } |
| 489 | 486 |
| 490 void Histogram::GetCountAndBucketData(Count* count, | 487 void Histogram::GetCountAndBucketData(Count* count, |
| 491 int64* sum, | 488 int64* sum, |
| 492 ListValue* buckets) const { | 489 ListValue* buckets) const { |
| 493 scoped_ptr<SampleVector> snapshot = SnapshotSampleVector(); | 490 scoped_ptr<SampleVector> snapshot = SnapshotSampleVector(); |
| 494 *count = snapshot->TotalCount(); | 491 *count = snapshot->TotalCount(); |
| 495 *sum = snapshot->sum(); | 492 *sum = snapshot->sum(); |
| 496 size_t index = 0; | 493 size_t index = 0; |
| 497 for (size_t i = 0; i < bucket_count(); ++i) { | 494 for (size_t i = 0; i < BucketCount(); ++i) { |
| 498 Sample count = snapshot->GetCountAtIndex(i); | 495 Sample count = snapshot->GetCountAtIndex(i); |
| 499 if (count > 0) { | 496 if (count > 0) { |
| 500 scoped_ptr<DictionaryValue> bucket_value(new DictionaryValue()); | 497 scoped_ptr<DictionaryValue> bucket_value(new DictionaryValue()); |
| 501 bucket_value->SetInteger("low", ranges(i)); | 498 bucket_value->SetInteger("low", ranges(i)); |
| 502 if (i != bucket_count() - 1) | 499 if (i != BucketCount() - 1) |
| 503 bucket_value->SetInteger("high", ranges(i + 1)); | 500 bucket_value->SetInteger("high", ranges(i + 1)); |
| 504 bucket_value->SetInteger("count", count); | 501 bucket_value->SetInteger("count", count); |
| 505 buckets->Set(index, bucket_value.release()); | 502 buckets->Set(index, bucket_value.release()); |
| 506 ++index; | 503 ++index; |
| 507 } | 504 } |
| 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 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 541 int32 flags, | 538 int32 flags, |
| 542 const DescriptionPair descriptions[]) { | 539 const DescriptionPair descriptions[]) { |
| 543 bool valid_arguments = Histogram::InspectConstructionArguments( | 540 bool valid_arguments = Histogram::InspectConstructionArguments( |
| 544 name, &minimum, &maximum, &bucket_count); | 541 name, &minimum, &maximum, &bucket_count); |
| 545 DCHECK(valid_arguments); | 542 DCHECK(valid_arguments); |
| 546 | 543 |
| 547 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 544 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); |
| 548 if (!histogram) { | 545 if (!histogram) { |
| 549 // To avoid racy destruction at shutdown, the following will be leaked. | 546 // To avoid racy destruction at shutdown, the following will be leaked. |
| 550 BucketRanges* ranges = new BucketRanges(bucket_count + 1); | 547 BucketRanges* ranges = new BucketRanges(bucket_count + 1); |
| 551 InitializeBucketRanges(minimum, maximum, bucket_count, ranges); | 548 InitializeBucketRanges(minimum, maximum, ranges); |
| 552 const BucketRanges* registered_ranges = | 549 const BucketRanges* registered_ranges = |
| 553 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | 550 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); |
| 554 | 551 |
| 555 LinearHistogram* tentative_histogram = | 552 LinearHistogram* tentative_histogram = |
| 556 new LinearHistogram(name, minimum, maximum, bucket_count, | 553 new LinearHistogram(name, minimum, maximum, registered_ranges); |
| 557 registered_ranges); | |
| 558 | 554 |
| 559 // Set range descriptions. | 555 // Set range descriptions. |
| 560 if (descriptions) { | 556 if (descriptions) { |
| 561 for (int i = 0; descriptions[i].description; ++i) { | 557 for (int i = 0; descriptions[i].description; ++i) { |
| 562 tentative_histogram->bucket_description_[descriptions[i].sample] = | 558 tentative_histogram->bucket_description_[descriptions[i].sample] = |
| 563 descriptions[i].description; | 559 descriptions[i].description; |
| 564 } | 560 } |
| 565 } | 561 } |
| 566 | 562 |
| 567 tentative_histogram->SetFlags(flags); | 563 tentative_histogram->SetFlags(flags); |
| 568 histogram = | 564 histogram = |
| 569 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | 565 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
| 570 } | 566 } |
| 571 | 567 |
| 572 DCHECK_EQ(LINEAR_HISTOGRAM, histogram->GetHistogramType()); | 568 DCHECK_EQ(LINEAR_HISTOGRAM, histogram->GetHistogramType()); |
| 573 CHECK(histogram->HasConstructionArguments(minimum, maximum, bucket_count)); | 569 CHECK(histogram->HasConstructionArguments(minimum, maximum, bucket_count)); |
| 574 return histogram; | 570 return histogram; |
| 575 } | 571 } |
| 576 | 572 |
| 577 HistogramType LinearHistogram::GetHistogramType() const { | 573 HistogramType LinearHistogram::GetHistogramType() const { |
| 578 return LINEAR_HISTOGRAM; | 574 return LINEAR_HISTOGRAM; |
| 579 } | 575 } |
| 580 | 576 |
| 581 LinearHistogram::LinearHistogram(const string& name, | 577 LinearHistogram::LinearHistogram(const string& name, |
| 582 Sample minimum, | 578 Sample minimum, |
| 583 Sample maximum, | 579 Sample maximum, |
| 584 size_t bucket_count, | |
| 585 const BucketRanges* ranges) | 580 const BucketRanges* ranges) |
| 586 : Histogram(name, minimum, maximum, bucket_count, ranges) { | 581 : Histogram(name, minimum, maximum, ranges) { |
| 587 } | 582 } |
| 588 | 583 |
| 589 double LinearHistogram::GetBucketSize(Count current, size_t i) const { | 584 double LinearHistogram::GetBucketSize(Count current, size_t i) const { |
| 590 DCHECK_GT(ranges(i + 1), ranges(i)); | 585 DCHECK_GT(ranges(i + 1), ranges(i)); |
| 591 // Adjacent buckets with different widths would have "surprisingly" many (few) | 586 // Adjacent buckets with different widths would have "surprisingly" many (few) |
| 592 // samples in a histogram if we didn't normalize this way. | 587 // samples in a histogram if we didn't normalize this way. |
| 593 double denominator = ranges(i + 1) - ranges(i); | 588 double denominator = ranges(i + 1) - ranges(i); |
| 594 return current/denominator; | 589 return current/denominator; |
| 595 } | 590 } |
| 596 | 591 |
| 597 const string LinearHistogram::GetAsciiBucketRange(size_t i) const { | 592 const string LinearHistogram::GetAsciiBucketRange(size_t i) const { |
| 598 int range = ranges(i); | 593 int range = ranges(i); |
| 599 BucketDescriptionMap::const_iterator it = bucket_description_.find(range); | 594 BucketDescriptionMap::const_iterator it = bucket_description_.find(range); |
| 600 if (it == bucket_description_.end()) | 595 if (it == bucket_description_.end()) |
| 601 return Histogram::GetAsciiBucketRange(i); | 596 return Histogram::GetAsciiBucketRange(i); |
| 602 return it->second; | 597 return it->second; |
| 603 } | 598 } |
| 604 | 599 |
| 605 bool LinearHistogram::PrintEmptyBucket(size_t index) const { | 600 bool LinearHistogram::PrintEmptyBucket(size_t index) const { |
| 606 return bucket_description_.find(ranges(index)) == bucket_description_.end(); | 601 return bucket_description_.find(ranges(index)) == bucket_description_.end(); |
| 607 } | 602 } |
| 608 | 603 |
| 609 // static | 604 // static |
| 610 void LinearHistogram::InitializeBucketRanges(Sample minimum, | 605 void LinearHistogram::InitializeBucketRanges(Sample minimum, |
| 611 Sample maximum, | 606 Sample maximum, |
| 612 size_t bucket_count, | |
| 613 BucketRanges* ranges) { | 607 BucketRanges* ranges) { |
| 614 DCHECK_EQ(ranges->size(), bucket_count + 1); | |
| 615 double min = minimum; | 608 double min = minimum; |
| 616 double max = maximum; | 609 double max = maximum; |
| 617 size_t i; | 610 size_t bucket_count = ranges->BucketCount(); |
| 618 for (i = 1; i < bucket_count; ++i) { | 611 for (size_t i = 1; i < bucket_count; ++i) { |
| 619 double linear_range = | 612 double linear_range = |
| 620 (min * (bucket_count -1 - i) + max * (i - 1)) / (bucket_count - 2); | 613 (min * (bucket_count - 1 - i) + max * (i - 1)) / (bucket_count - 2); |
| 621 ranges->set_range(i, static_cast<Sample>(linear_range + 0.5)); | 614 ranges->set_range(i, static_cast<Sample>(linear_range + 0.5)); |
| 622 } | 615 } |
| 623 ranges->set_range(ranges->size() - 1, HistogramBase::kSampleType_MAX); | 616 ranges->set_range(ranges->BucketCount(), HistogramBase::kSampleType_MAX); |
| 624 ranges->ResetChecksum(); | 617 ranges->ResetChecksum(); |
| 625 } | 618 } |
| 626 | 619 |
| 627 // static | 620 // static |
| 628 HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) { | 621 HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) { |
| 629 string histogram_name; | 622 string histogram_name; |
| 630 int flags; | 623 int flags; |
| 631 int declared_min; | 624 int declared_min; |
| 632 int declared_max; | 625 int declared_max; |
| 633 uint64 bucket_count; | 626 uint64 bucket_count; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 649 | 642 |
| 650 //------------------------------------------------------------------------------ | 643 //------------------------------------------------------------------------------ |
| 651 // This section provides implementation for BooleanHistogram. | 644 // This section provides implementation for BooleanHistogram. |
| 652 //------------------------------------------------------------------------------ | 645 //------------------------------------------------------------------------------ |
| 653 | 646 |
| 654 HistogramBase* BooleanHistogram::FactoryGet(const string& name, int32 flags) { | 647 HistogramBase* BooleanHistogram::FactoryGet(const string& name, int32 flags) { |
| 655 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 648 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); |
| 656 if (!histogram) { | 649 if (!histogram) { |
| 657 // To avoid racy destruction at shutdown, the following will be leaked. | 650 // To avoid racy destruction at shutdown, the following will be leaked. |
| 658 BucketRanges* ranges = new BucketRanges(4); | 651 BucketRanges* ranges = new BucketRanges(4); |
| 659 LinearHistogram::InitializeBucketRanges(1, 2, 3, ranges); | 652 LinearHistogram::InitializeBucketRanges(1, 2, ranges); |
| 660 const BucketRanges* registered_ranges = | 653 const BucketRanges* registered_ranges = |
| 661 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | 654 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); |
| 662 | 655 |
| 663 BooleanHistogram* tentative_histogram = | 656 BooleanHistogram* tentative_histogram = |
| 664 new BooleanHistogram(name, registered_ranges); | 657 new BooleanHistogram(name, registered_ranges); |
| 665 | 658 |
| 666 tentative_histogram->SetFlags(flags); | 659 tentative_histogram->SetFlags(flags); |
| 667 histogram = | 660 histogram = |
| 668 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | 661 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
| 669 } | 662 } |
| 670 | 663 |
| 671 DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType()); | 664 DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType()); |
| 672 return histogram; | 665 return histogram; |
| 673 } | 666 } |
| 674 | 667 |
| 675 HistogramType BooleanHistogram::GetHistogramType() const { | 668 HistogramType BooleanHistogram::GetHistogramType() const { |
| 676 return BOOLEAN_HISTOGRAM; | 669 return BOOLEAN_HISTOGRAM; |
| 677 } | 670 } |
| 678 | 671 |
| 679 BooleanHistogram::BooleanHistogram(const string& name, | 672 BooleanHistogram::BooleanHistogram(const string& name, |
| 680 const BucketRanges* ranges) | 673 const BucketRanges* ranges) |
| 681 : LinearHistogram(name, 1, 2, 3, ranges) {} | 674 : LinearHistogram(name, 1, 2, ranges) {} |
| 682 | 675 |
| 683 HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) { | 676 HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) { |
| 684 string histogram_name; | 677 string histogram_name; |
| 685 int flags; | 678 int flags; |
| 686 int declared_min; | 679 int declared_min; |
| 687 int declared_max; | 680 int declared_max; |
| 688 uint64 bucket_count; | 681 uint64 bucket_count; |
| 689 uint32 range_checksum; | 682 uint32 range_checksum; |
| 690 | 683 |
| 691 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, | 684 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 747 // values, FactoryGet will take care of removing them. | 740 // values, FactoryGet will take care of removing them. |
| 748 all_values.push_back(value + 1); | 741 all_values.push_back(value + 1); |
| 749 } | 742 } |
| 750 return all_values; | 743 return all_values; |
| 751 } | 744 } |
| 752 | 745 |
| 753 CustomHistogram::CustomHistogram(const string& name, | 746 CustomHistogram::CustomHistogram(const string& name, |
| 754 const BucketRanges* ranges) | 747 const BucketRanges* ranges) |
| 755 : Histogram(name, | 748 : Histogram(name, |
| 756 ranges->range(1), | 749 ranges->range(1), |
| 757 ranges->range(ranges->size() - 2), | 750 ranges->range(ranges->BucketCount() - 1), |
| 758 ranges->size() - 1, | |
| 759 ranges) {} | 751 ranges) {} |
| 760 | 752 |
| 761 bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const { | 753 bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const { |
| 762 if (!Histogram::SerializeInfoImpl(pickle)) | 754 if (!Histogram::SerializeInfoImpl(pickle)) |
| 763 return false; | 755 return false; |
| 764 | 756 |
| 765 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't | 757 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't |
| 766 // write them. | 758 // write them. |
| 767 for (size_t i = 1; i < bucket_ranges()->size() - 1; ++i) { | 759 for (size_t i = 1; i < bucket_ranges()->BucketCount(); ++i) { |
| 768 if (!pickle->WriteInt(bucket_ranges()->range(i))) | 760 if (!pickle->WriteInt(bucket_ranges()->range(i))) |
| 769 return false; | 761 return false; |
| 770 } | 762 } |
| 771 return true; | 763 return true; |
| 772 } | 764 } |
| 773 | 765 |
| 774 double CustomHistogram::GetBucketSize(Count current, size_t i) const { | 766 double CustomHistogram::GetBucketSize(Count current, size_t i) const { |
| 775 return 1; | 767 return 1; |
| 776 } | 768 } |
| 777 | 769 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 832 | 824 |
| 833 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); | 825 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); |
| 834 for (size_t i = 0; i < ranges.size(); i++) { | 826 for (size_t i = 0; i < ranges.size(); i++) { |
| 835 bucket_ranges->set_range(i, ranges[i]); | 827 bucket_ranges->set_range(i, ranges[i]); |
| 836 } | 828 } |
| 837 bucket_ranges->ResetChecksum(); | 829 bucket_ranges->ResetChecksum(); |
| 838 return bucket_ranges; | 830 return bucket_ranges; |
| 839 } | 831 } |
| 840 | 832 |
| 841 } // namespace base | 833 } // namespace base |
| OLD | NEW |