Chromium Code Reviews| 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/memory/persistent_memory_allocator.h" | |
| 20 #include "base/metrics/histogram_macros.h" | 21 #include "base/metrics/histogram_macros.h" |
| 22 #include "base/metrics/histogram_persistence.h" | |
| 21 #include "base/metrics/metrics_hashes.h" | 23 #include "base/metrics/metrics_hashes.h" |
| 22 #include "base/metrics/sample_vector.h" | 24 #include "base/metrics/sample_vector.h" |
| 23 #include "base/metrics/statistics_recorder.h" | 25 #include "base/metrics/statistics_recorder.h" |
| 24 #include "base/pickle.h" | 26 #include "base/pickle.h" |
| 25 #include "base/strings/string_util.h" | 27 #include "base/strings/string_util.h" |
| 26 #include "base/strings/stringprintf.h" | 28 #include "base/strings/stringprintf.h" |
| 27 #include "base/synchronization/lock.h" | 29 #include "base/synchronization/lock.h" |
| 28 #include "base/values.h" | 30 #include "base/values.h" |
| 29 | 31 |
| 30 namespace base { | 32 namespace base { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 70 bool ValidateRangeChecksum(const HistogramBase& histogram, | 72 bool ValidateRangeChecksum(const HistogramBase& histogram, |
| 71 uint32 range_checksum) { | 73 uint32 range_checksum) { |
| 72 const Histogram& casted_histogram = | 74 const Histogram& casted_histogram = |
| 73 static_cast<const Histogram&>(histogram); | 75 static_cast<const Histogram&>(histogram); |
| 74 | 76 |
| 75 return casted_histogram.bucket_ranges()->checksum() == range_checksum; | 77 return casted_histogram.bucket_ranges()->checksum() == range_checksum; |
| 76 } | 78 } |
| 77 | 79 |
| 78 } // namespace | 80 } // namespace |
| 79 | 81 |
| 82 | |
| 83 class Histogram::Factory { | |
| 84 public: | |
| 85 Factory(const std::string& name, | |
| 86 HistogramBase::Sample minimum, | |
| 87 HistogramBase::Sample maximum, | |
| 88 size_t bucket_count, | |
| 89 int32 flags) | |
| 90 : Factory(name, HISTOGRAM, minimum, maximum, bucket_count, flags) {} | |
| 91 | |
| 92 HistogramBase* Build(); | |
| 93 | |
| 94 protected: | |
| 95 Factory(const std::string& name, | |
| 96 HistogramType histogram_type, | |
| 97 HistogramBase::Sample minimum, | |
| 98 HistogramBase::Sample maximum, | |
| 99 size_t bucket_count, | |
| 100 int32 flags) | |
| 101 : name_(name), | |
| 102 histogram_type_(histogram_type), | |
| 103 minimum_(minimum), | |
| 104 maximum_(maximum), | |
| 105 bucket_count_(bucket_count), | |
| 106 flags_(flags) {} | |
| 107 | |
| 108 virtual BucketRanges* CreateRanges(); | |
| 109 virtual HistogramBase* HeapAlloc(const BucketRanges* ranges); | |
| 110 virtual void FillHistogram(HistogramBase* histogram); | |
| 111 | |
| 112 const std::string& name_; | |
| 113 const HistogramType histogram_type_; | |
| 114 HistogramBase::Sample minimum_; | |
| 115 HistogramBase::Sample maximum_; | |
| 116 size_t bucket_count_; | |
| 117 int32 flags_; | |
|
Alexei Svitkine (slow)
2015/12/15 23:03:37
Do these need to be members or could they be param
bcwhite
2015/12/16 13:36:34
Whether the defaults are set in the ctor or as par
Alexei Svitkine (slow)
2015/12/16 16:33:49
Sorry, I didn't mention it, but one of the reason
bcwhite
2015/12/17 15:55:48
I think given that the class is a utility class co
| |
| 118 }; | |
| 119 | |
| 120 HistogramBase* Histogram::Factory::Build() { | |
| 121 ImportPersistentHistograms(); | |
| 122 | |
| 123 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_); | |
| 124 if (!histogram) { | |
| 125 // To avoid racy destruction at shutdown, the following will be leaked. | |
| 126 const BucketRanges* created_ranges = CreateRanges(); | |
| 127 const BucketRanges* registered_ranges = | |
| 128 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges); | |
| 129 | |
| 130 // Sometimes the bucket info is dynamically determined in create_ranges(). | |
| 131 if (bucket_count_ == 0) { | |
| 132 bucket_count_ = registered_ranges->bucket_count(); | |
| 133 minimum_ = registered_ranges->range(1); | |
| 134 maximum_ = registered_ranges->range(bucket_count_ - 1); | |
| 135 } | |
| 136 | |
| 137 PersistentMemoryAllocator::Reference histogram_ref = 0; | |
| 138 HistogramBase* tentative_histogram = nullptr; | |
| 139 PersistentMemoryAllocator* allocator = | |
| 140 GetPersistentHistogramMemoryAllocator(); | |
| 141 if (allocator) { | |
| 142 flags_ |= HistogramBase::kIsPersistent; | |
| 143 tentative_histogram = AllocatePersistentHistogram( | |
| 144 allocator, | |
| 145 histogram_type_, | |
| 146 name_, | |
| 147 minimum_, | |
| 148 maximum_, | |
| 149 registered_ranges, | |
| 150 flags_, | |
| 151 &histogram_ref); | |
| 152 } | |
| 153 if (!tentative_histogram) { | |
| 154 flags_ &= ~HistogramBase::kIsPersistent; | |
| 155 tentative_histogram = HeapAlloc(registered_ranges); | |
| 156 } | |
| 157 | |
| 158 FillHistogram(tentative_histogram); | |
| 159 | |
| 160 tentative_histogram->SetFlags(flags_); | |
| 161 histogram = | |
| 162 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | |
| 163 | |
| 164 // Persistent histograms need some follow-up processing. | |
| 165 if (histogram_ref) { | |
| 166 // If the created persistent histogram is canonical then it needs to be | |
| 167 // marked as "iterable" in order to be found by other processes. | |
| 168 if (histogram == tentative_histogram) | |
| 169 GetPersistentHistogramMemoryAllocator()->MakeIterable(histogram_ref); | |
| 170 // If it's not the canonical one then a race condition must have caused | |
| 171 // two to be created. The allocator does not support releasing the | |
| 172 // acquired memory so just change the type to be empty. | |
| 173 else | |
| 174 GetPersistentHistogramMemoryAllocator()->SetType(histogram_ref, 0); | |
| 175 } | |
| 176 } | |
| 177 | |
| 178 DCHECK_EQ(histogram_type_, histogram->GetHistogramType()); | |
| 179 if (bucket_count_ != 0 && | |
| 180 !histogram->HasConstructionArguments(minimum_, maximum_, bucket_count_)) { | |
| 181 // The construction arguments do not match the existing histogram. This can | |
| 182 // come about if an extension updates in the middle of a chrome run and has | |
| 183 // changed one of them, or simply by bad code within Chrome itself. We | |
| 184 // return NULL here with the expectation that bad code in Chrome will crash | |
| 185 // on dereference, but extension/Pepper APIs will guard against NULL and not | |
| 186 // crash. | |
| 187 DLOG(ERROR) << "Histogram " << name_ << " has bad construction arguments"; | |
| 188 return NULL; | |
|
Alexei Svitkine (slow)
2015/12/16 16:33:49
Nit: nullptr
bcwhite
2015/12/17 15:55:48
Old habits die hard. Done.
| |
| 189 } | |
| 190 return histogram; | |
| 191 } | |
| 192 | |
| 193 BucketRanges* Histogram::Factory::CreateRanges() { | |
|
Alexei Svitkine (slow)
2015/12/16 16:33:49
So, thinking about this more.... given that these
bcwhite
2015/12/17 15:55:48
I wouldn't even need a class for that. It would j
| |
| 194 BucketRanges* ranges = new BucketRanges(bucket_count_ + 1); | |
| 195 Histogram::InitializeBucketRanges(minimum_, maximum_, ranges); | |
| 196 return ranges; | |
| 197 } | |
| 198 | |
| 199 HistogramBase* Histogram::Factory::HeapAlloc(const BucketRanges* ranges) { | |
| 200 return new Histogram(name_, minimum_, maximum_, ranges); | |
| 201 } | |
| 202 | |
| 203 void Histogram::Factory::FillHistogram(HistogramBase* histogram) { | |
| 204 } | |
| 205 | |
| 206 | |
| 207 class LinearHistogram::Factory : public Histogram::Factory { | |
| 208 public: | |
| 209 Factory(const std::string& name, | |
| 210 HistogramBase::Sample minimum, | |
| 211 HistogramBase::Sample maximum, | |
| 212 size_t bucket_count, | |
| 213 int32 flags, | |
| 214 const DescriptionPair* descriptions) | |
| 215 : Histogram::Factory(name, LINEAR_HISTOGRAM, minimum, maximum, | |
| 216 bucket_count, flags) { | |
| 217 descriptions_ = descriptions; | |
| 218 } | |
| 219 | |
| 220 protected: | |
| 221 BucketRanges* CreateRanges(); | |
| 222 HistogramBase* HeapAlloc(const BucketRanges* ranges) override; | |
| 223 void FillHistogram(HistogramBase* histogram) override; | |
| 224 | |
| 225 const DescriptionPair* descriptions_; | |
| 226 }; | |
| 227 | |
| 228 BucketRanges* LinearHistogram::Factory::CreateRanges() { | |
| 229 BucketRanges* ranges = new BucketRanges(bucket_count_ + 1); | |
| 230 LinearHistogram::InitializeBucketRanges(minimum_, maximum_, ranges); | |
| 231 return ranges; | |
| 232 } | |
| 233 | |
| 234 HistogramBase* LinearHistogram::Factory::HeapAlloc(const BucketRanges* ranges) { | |
| 235 return new LinearHistogram(name_, minimum_, maximum_, ranges); | |
| 236 } | |
| 237 | |
| 238 void LinearHistogram::Factory::FillHistogram(HistogramBase* base_histogram) { | |
| 239 LinearHistogram* histogram = static_cast<LinearHistogram*>(base_histogram); | |
| 240 // Set range descriptions. | |
| 241 if (descriptions_) { | |
| 242 for (int i = 0; descriptions_[i].description; ++i) { | |
| 243 histogram->bucket_description_[descriptions_[i].sample] = | |
| 244 descriptions_[i].description; | |
| 245 } | |
| 246 } | |
| 247 } | |
| 248 | |
| 249 | |
| 250 class BooleanHistogram::Factory : public Histogram::Factory { | |
| 251 public: | |
| 252 Factory(const std::string& name, int32 flags) | |
| 253 : Histogram::Factory(name, BOOLEAN_HISTOGRAM, 1, 2, 3, flags) {} | |
| 254 | |
| 255 protected: | |
| 256 BucketRanges* CreateRanges(); | |
| 257 HistogramBase* HeapAlloc(const BucketRanges* ranges) override; | |
| 258 }; | |
| 259 | |
| 260 BucketRanges* BooleanHistogram::Factory::CreateRanges() { | |
| 261 BucketRanges* ranges = new BucketRanges(3 + 1); | |
| 262 LinearHistogram::InitializeBucketRanges(1, 2, ranges); | |
| 263 return ranges; | |
| 264 } | |
| 265 | |
| 266 HistogramBase* BooleanHistogram::Factory::HeapAlloc( | |
| 267 const BucketRanges* ranges) { | |
| 268 return new BooleanHistogram(name_, ranges); | |
| 269 } | |
| 270 | |
| 271 | |
| 272 class CustomHistogram::Factory : public Histogram::Factory { | |
| 273 public: | |
| 274 Factory(const std::string& name, | |
| 275 const std::vector<Sample>* custom_ranges, | |
| 276 int32 flags) | |
| 277 : Histogram::Factory(name, CUSTOM_HISTOGRAM, 0, 0, 0, flags) { | |
| 278 custom_ranges_ = custom_ranges; | |
| 279 } | |
| 280 | |
| 281 protected: | |
| 282 BucketRanges* CreateRanges(); | |
| 283 HistogramBase* HeapAlloc(const BucketRanges* ranges) override; | |
| 284 | |
| 285 const std::vector<Sample>* custom_ranges_; | |
| 286 }; | |
| 287 | |
| 288 BucketRanges* CustomHistogram::Factory::CreateRanges() { | |
| 289 // Remove the duplicates in the custom ranges array. | |
| 290 std::vector<int> ranges = *custom_ranges_; | |
| 291 ranges.push_back(0); // Ensure we have a zero value. | |
| 292 ranges.push_back(HistogramBase::kSampleType_MAX); | |
| 293 std::sort(ranges.begin(), ranges.end()); | |
| 294 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end()); | |
| 295 | |
| 296 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); | |
| 297 for (size_t i = 0; i < ranges.size(); i++) { | |
| 298 bucket_ranges->set_range(i, ranges[i]); | |
| 299 } | |
| 300 bucket_ranges->ResetChecksum(); | |
| 301 return bucket_ranges; | |
| 302 } | |
| 303 | |
| 304 HistogramBase* CustomHistogram::Factory::HeapAlloc(const BucketRanges* ranges) { | |
| 305 return new CustomHistogram(name_, ranges); | |
| 306 } | |
| 307 | |
| 308 | |
| 80 typedef HistogramBase::Count Count; | 309 typedef HistogramBase::Count Count; |
| 81 typedef HistogramBase::Sample Sample; | 310 typedef HistogramBase::Sample Sample; |
| 82 | 311 |
| 83 // static | 312 // static |
| 84 const size_t Histogram::kBucketCount_MAX = 16384u; | 313 const size_t Histogram::kBucketCount_MAX = 16384u; |
| 85 | 314 |
| 86 HistogramBase* Histogram::FactoryGet(const std::string& name, | 315 HistogramBase* Histogram::FactoryGet(const std::string& name, |
| 87 Sample minimum, | 316 Sample minimum, |
| 88 Sample maximum, | 317 Sample maximum, |
| 89 size_t bucket_count, | 318 size_t bucket_count, |
| 90 int32 flags) { | 319 int32 flags) { |
| 91 bool valid_arguments = | 320 bool valid_arguments = |
| 92 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); | 321 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); |
| 93 DCHECK(valid_arguments); | 322 DCHECK(valid_arguments); |
| 94 | 323 |
| 95 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 324 return Factory(name, minimum, maximum, bucket_count, flags).Build(); |
| 96 if (!histogram) { | |
| 97 // To avoid racy destruction at shutdown, the following will be leaked. | |
| 98 BucketRanges* ranges = new BucketRanges(bucket_count + 1); | |
| 99 InitializeBucketRanges(minimum, maximum, ranges); | |
| 100 const BucketRanges* registered_ranges = | |
| 101 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | |
| 102 | |
| 103 Histogram* tentative_histogram = | |
| 104 new Histogram(name, minimum, maximum, registered_ranges); | |
| 105 | |
| 106 tentative_histogram->SetFlags(flags); | |
| 107 histogram = | |
| 108 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | |
| 109 } | |
| 110 | |
| 111 DCHECK_EQ(HISTOGRAM, histogram->GetHistogramType()); | |
| 112 if (!histogram->HasConstructionArguments(minimum, maximum, bucket_count)) { | |
| 113 // The construction arguments do not match the existing histogram. This can | |
| 114 // come about if an extension updates in the middle of a chrome run and has | |
| 115 // changed one of them, or simply by bad code within Chrome itself. We | |
| 116 // return NULL here with the expectation that bad code in Chrome will crash | |
| 117 // on dereference, but extension/Pepper APIs will guard against NULL and not | |
| 118 // crash. | |
| 119 DLOG(ERROR) << "Histogram " << name << " has bad construction arguments"; | |
| 120 return NULL; | |
| 121 } | |
| 122 return histogram; | |
| 123 } | 325 } |
| 124 | 326 |
| 125 HistogramBase* Histogram::FactoryTimeGet(const std::string& name, | 327 HistogramBase* Histogram::FactoryTimeGet(const std::string& name, |
| 126 TimeDelta minimum, | 328 TimeDelta minimum, |
| 127 TimeDelta maximum, | 329 TimeDelta maximum, |
| 128 size_t bucket_count, | 330 size_t bucket_count, |
| 129 int32 flags) { | 331 int32 flags) { |
| 130 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()), | 332 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()), |
| 131 static_cast<Sample>(maximum.InMilliseconds()), bucket_count, | 333 static_cast<Sample>(maximum.InMilliseconds()), bucket_count, |
| 132 flags); | 334 flags); |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 336 Sample maximum, | 538 Sample maximum, |
| 337 const BucketRanges* ranges) | 539 const BucketRanges* ranges) |
| 338 : HistogramBase(name), | 540 : HistogramBase(name), |
| 339 bucket_ranges_(ranges), | 541 bucket_ranges_(ranges), |
| 340 declared_min_(minimum), | 542 declared_min_(minimum), |
| 341 declared_max_(maximum) { | 543 declared_max_(maximum) { |
| 342 if (ranges) | 544 if (ranges) |
| 343 samples_.reset(new SampleVector(HashMetricName(name), ranges)); | 545 samples_.reset(new SampleVector(HashMetricName(name), ranges)); |
| 344 } | 546 } |
| 345 | 547 |
| 548 Histogram::Histogram(const std::string& name, | |
| 549 Sample minimum, | |
| 550 Sample maximum, | |
| 551 const BucketRanges* ranges, | |
| 552 HistogramBase::AtomicCount* counts, | |
| 553 size_t counts_size, | |
| 554 HistogramSamples::Metadata* meta) | |
| 555 : HistogramBase(name), | |
| 556 bucket_ranges_(ranges), | |
| 557 declared_min_(minimum), | |
| 558 declared_max_(maximum) { | |
| 559 if (ranges) | |
| 560 samples_.reset(new SampleVector(HashMetricName(name), | |
| 561 counts, counts_size, meta, ranges)); | |
| 562 } | |
| 563 | |
| 346 Histogram::~Histogram() { | 564 Histogram::~Histogram() { |
| 347 } | 565 } |
| 348 | 566 |
| 349 bool Histogram::PrintEmptyBucket(size_t index) const { | 567 bool Histogram::PrintEmptyBucket(size_t index) const { |
| 350 return true; | 568 return true; |
| 351 } | 569 } |
| 352 | 570 |
| 353 // Use the actual bucket widths (like a linear histogram) until the widths get | 571 // Use the actual bucket widths (like a linear histogram) until the widths get |
| 354 // over some transition value, and then use that transition width. Exponentials | 572 // over some transition value, and then use that transition width. Exponentials |
| 355 // get so big so fast (and we don't expect to see a lot of entries in the large | 573 // get so big so fast (and we don't expect to see a lot of entries in the large |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 586 const std::string& name, | 804 const std::string& name, |
| 587 Sample minimum, | 805 Sample minimum, |
| 588 Sample maximum, | 806 Sample maximum, |
| 589 size_t bucket_count, | 807 size_t bucket_count, |
| 590 int32 flags, | 808 int32 flags, |
| 591 const DescriptionPair descriptions[]) { | 809 const DescriptionPair descriptions[]) { |
| 592 bool valid_arguments = Histogram::InspectConstructionArguments( | 810 bool valid_arguments = Histogram::InspectConstructionArguments( |
| 593 name, &minimum, &maximum, &bucket_count); | 811 name, &minimum, &maximum, &bucket_count); |
| 594 DCHECK(valid_arguments); | 812 DCHECK(valid_arguments); |
| 595 | 813 |
| 596 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 814 return Factory(name, minimum, maximum, bucket_count, flags, descriptions) |
| 597 if (!histogram) { | 815 .Build(); |
| 598 // To avoid racy destruction at shutdown, the following will be leaked. | |
| 599 BucketRanges* ranges = new BucketRanges(bucket_count + 1); | |
| 600 InitializeBucketRanges(minimum, maximum, ranges); | |
| 601 const BucketRanges* registered_ranges = | |
| 602 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | |
| 603 | |
| 604 LinearHistogram* tentative_histogram = | |
| 605 new LinearHistogram(name, minimum, maximum, registered_ranges); | |
| 606 | |
| 607 // Set range descriptions. | |
| 608 if (descriptions) { | |
| 609 for (int i = 0; descriptions[i].description; ++i) { | |
| 610 tentative_histogram->bucket_description_[descriptions[i].sample] = | |
| 611 descriptions[i].description; | |
| 612 } | |
| 613 } | |
| 614 | |
| 615 tentative_histogram->SetFlags(flags); | |
| 616 histogram = | |
| 617 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | |
| 618 } | |
| 619 | |
| 620 DCHECK_EQ(LINEAR_HISTOGRAM, histogram->GetHistogramType()); | |
| 621 if (!histogram->HasConstructionArguments(minimum, maximum, bucket_count)) { | |
| 622 // The construction arguments do not match the existing histogram. This can | |
| 623 // come about if an extension updates in the middle of a chrome run and has | |
| 624 // changed one of them, or simply by bad code within Chrome itself. We | |
| 625 // return NULL here with the expectation that bad code in Chrome will crash | |
| 626 // on dereference, but extension/Pepper APIs will guard against NULL and not | |
| 627 // crash. | |
| 628 DLOG(ERROR) << "Histogram " << name << " has bad construction arguments"; | |
| 629 return NULL; | |
| 630 } | |
| 631 return histogram; | |
| 632 } | 816 } |
| 633 | 817 |
| 634 HistogramType LinearHistogram::GetHistogramType() const { | 818 HistogramType LinearHistogram::GetHistogramType() const { |
| 635 return LINEAR_HISTOGRAM; | 819 return LINEAR_HISTOGRAM; |
| 636 } | 820 } |
| 637 | 821 |
| 638 LinearHistogram::LinearHistogram(const std::string& name, | 822 LinearHistogram::LinearHistogram(const std::string& name, |
| 639 Sample minimum, | 823 Sample minimum, |
| 640 Sample maximum, | 824 Sample maximum, |
| 641 const BucketRanges* ranges) | 825 const BucketRanges* ranges) |
| 642 : Histogram(name, minimum, maximum, ranges) { | 826 : Histogram(name, minimum, maximum, ranges) { |
| 643 } | 827 } |
| 644 | 828 |
| 829 LinearHistogram::LinearHistogram(const std::string& name, | |
| 830 Sample minimum, | |
| 831 Sample maximum, | |
| 832 const BucketRanges* ranges, | |
| 833 HistogramBase::AtomicCount* counts, | |
| 834 size_t counts_size, | |
| 835 HistogramSamples::Metadata* meta) | |
| 836 : Histogram(name, | |
| 837 minimum, | |
| 838 maximum, | |
| 839 ranges, | |
| 840 counts, | |
| 841 counts_size, | |
| 842 meta) {} | |
| 843 | |
| 645 double LinearHistogram::GetBucketSize(Count current, size_t i) const { | 844 double LinearHistogram::GetBucketSize(Count current, size_t i) const { |
| 646 DCHECK_GT(ranges(i + 1), ranges(i)); | 845 DCHECK_GT(ranges(i + 1), ranges(i)); |
| 647 // Adjacent buckets with different widths would have "surprisingly" many (few) | 846 // Adjacent buckets with different widths would have "surprisingly" many (few) |
| 648 // samples in a histogram if we didn't normalize this way. | 847 // samples in a histogram if we didn't normalize this way. |
| 649 double denominator = ranges(i + 1) - ranges(i); | 848 double denominator = ranges(i + 1) - ranges(i); |
| 650 return current/denominator; | 849 return current/denominator; |
| 651 } | 850 } |
| 652 | 851 |
| 653 const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const { | 852 const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const { |
| 654 int range = ranges(i); | 853 int range = ranges(i); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 700 } | 899 } |
| 701 return histogram; | 900 return histogram; |
| 702 } | 901 } |
| 703 | 902 |
| 704 //------------------------------------------------------------------------------ | 903 //------------------------------------------------------------------------------ |
| 705 // This section provides implementation for BooleanHistogram. | 904 // This section provides implementation for BooleanHistogram. |
| 706 //------------------------------------------------------------------------------ | 905 //------------------------------------------------------------------------------ |
| 707 | 906 |
| 708 HistogramBase* BooleanHistogram::FactoryGet(const std::string& name, | 907 HistogramBase* BooleanHistogram::FactoryGet(const std::string& name, |
| 709 int32 flags) { | 908 int32 flags) { |
| 710 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 909 return Factory(name, flags).Build(); |
| 711 if (!histogram) { | |
| 712 // To avoid racy destruction at shutdown, the following will be leaked. | |
| 713 BucketRanges* ranges = new BucketRanges(4); | |
| 714 LinearHistogram::InitializeBucketRanges(1, 2, ranges); | |
| 715 const BucketRanges* registered_ranges = | |
| 716 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | |
| 717 | |
| 718 BooleanHistogram* tentative_histogram = | |
| 719 new BooleanHistogram(name, registered_ranges); | |
| 720 | |
| 721 tentative_histogram->SetFlags(flags); | |
| 722 histogram = | |
| 723 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | |
| 724 } | |
| 725 | |
| 726 DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType()); | |
| 727 return histogram; | |
| 728 } | 910 } |
| 729 | 911 |
| 730 HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32 flags) { | 912 HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32 flags) { |
| 731 return FactoryGet(std::string(name), flags); | 913 return FactoryGet(std::string(name), flags); |
| 732 } | 914 } |
| 733 | 915 |
| 734 HistogramType BooleanHistogram::GetHistogramType() const { | 916 HistogramType BooleanHistogram::GetHistogramType() const { |
| 735 return BOOLEAN_HISTOGRAM; | 917 return BOOLEAN_HISTOGRAM; |
| 736 } | 918 } |
| 737 | 919 |
| 738 BooleanHistogram::BooleanHistogram(const std::string& name, | 920 BooleanHistogram::BooleanHistogram(const std::string& name, |
| 739 const BucketRanges* ranges) | 921 const BucketRanges* ranges) |
| 740 : LinearHistogram(name, 1, 2, ranges) {} | 922 : LinearHistogram(name, 1, 2, ranges) {} |
| 741 | 923 |
| 924 BooleanHistogram::BooleanHistogram(const std::string& name, | |
| 925 const BucketRanges* ranges, | |
| 926 HistogramBase::AtomicCount* counts, | |
| 927 HistogramSamples::Metadata* meta) | |
| 928 : LinearHistogram(name, 1, 2, ranges, counts, 2, meta) {} | |
| 929 | |
| 742 HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) { | 930 HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) { |
| 743 std::string histogram_name; | 931 std::string histogram_name; |
| 744 int flags; | 932 int flags; |
| 745 int declared_min; | 933 int declared_min; |
| 746 int declared_max; | 934 int declared_max; |
| 747 size_t bucket_count; | 935 size_t bucket_count; |
| 748 uint32 range_checksum; | 936 uint32 range_checksum; |
| 749 | 937 |
| 750 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, | 938 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, |
| 751 &declared_max, &bucket_count, &range_checksum)) { | 939 &declared_max, &bucket_count, &range_checksum)) { |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 764 //------------------------------------------------------------------------------ | 952 //------------------------------------------------------------------------------ |
| 765 // CustomHistogram: | 953 // CustomHistogram: |
| 766 //------------------------------------------------------------------------------ | 954 //------------------------------------------------------------------------------ |
| 767 | 955 |
| 768 HistogramBase* CustomHistogram::FactoryGet( | 956 HistogramBase* CustomHistogram::FactoryGet( |
| 769 const std::string& name, | 957 const std::string& name, |
| 770 const std::vector<Sample>& custom_ranges, | 958 const std::vector<Sample>& custom_ranges, |
| 771 int32 flags) { | 959 int32 flags) { |
| 772 CHECK(ValidateCustomRanges(custom_ranges)); | 960 CHECK(ValidateCustomRanges(custom_ranges)); |
| 773 | 961 |
| 774 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 962 return Factory(name, &custom_ranges, flags).Build(); |
| 775 if (!histogram) { | |
| 776 BucketRanges* ranges = CreateBucketRangesFromCustomRanges(custom_ranges); | |
| 777 const BucketRanges* registered_ranges = | |
| 778 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | |
| 779 | |
| 780 // To avoid racy destruction at shutdown, the following will be leaked. | |
| 781 CustomHistogram* tentative_histogram = | |
| 782 new CustomHistogram(name, registered_ranges); | |
| 783 | |
| 784 tentative_histogram->SetFlags(flags); | |
| 785 | |
| 786 histogram = | |
| 787 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | |
| 788 } | |
| 789 | |
| 790 DCHECK_EQ(histogram->GetHistogramType(), CUSTOM_HISTOGRAM); | |
| 791 return histogram; | |
| 792 } | 963 } |
| 793 | 964 |
| 794 HistogramBase* CustomHistogram::FactoryGet( | 965 HistogramBase* CustomHistogram::FactoryGet( |
| 795 const char* name, | 966 const char* name, |
| 796 const std::vector<Sample>& custom_ranges, | 967 const std::vector<Sample>& custom_ranges, |
| 797 int32 flags) { | 968 int32 flags) { |
| 798 return FactoryGet(std::string(name), custom_ranges, flags); | 969 return FactoryGet(std::string(name), custom_ranges, flags); |
| 799 } | 970 } |
| 800 | 971 |
| 801 HistogramType CustomHistogram::GetHistogramType() const { | 972 HistogramType CustomHistogram::GetHistogramType() const { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 817 return all_values; | 988 return all_values; |
| 818 } | 989 } |
| 819 | 990 |
| 820 CustomHistogram::CustomHistogram(const std::string& name, | 991 CustomHistogram::CustomHistogram(const std::string& name, |
| 821 const BucketRanges* ranges) | 992 const BucketRanges* ranges) |
| 822 : Histogram(name, | 993 : Histogram(name, |
| 823 ranges->range(1), | 994 ranges->range(1), |
| 824 ranges->range(ranges->bucket_count() - 1), | 995 ranges->range(ranges->bucket_count() - 1), |
| 825 ranges) {} | 996 ranges) {} |
| 826 | 997 |
| 998 CustomHistogram::CustomHistogram(const std::string& name, | |
| 999 const BucketRanges* ranges, | |
| 1000 HistogramBase::AtomicCount* counts, | |
| 1001 size_t counts_size, | |
| 1002 HistogramSamples::Metadata* meta) | |
| 1003 : Histogram(name, | |
| 1004 ranges->range(1), | |
| 1005 ranges->range(ranges->bucket_count() - 1), | |
| 1006 ranges, | |
| 1007 counts, | |
| 1008 counts_size, | |
| 1009 meta) {} | |
| 1010 | |
| 827 bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const { | 1011 bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const { |
| 828 if (!Histogram::SerializeInfoImpl(pickle)) | 1012 if (!Histogram::SerializeInfoImpl(pickle)) |
| 829 return false; | 1013 return false; |
| 830 | 1014 |
| 831 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't | 1015 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't |
| 832 // write them. | 1016 // write them. |
| 833 for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) { | 1017 for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) { |
| 834 if (!pickle->WriteInt(bucket_ranges()->range(i))) | 1018 if (!pickle->WriteInt(bucket_ranges()->range(i))) |
| 835 return false; | 1019 return false; |
| 836 } | 1020 } |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 879 for (size_t i = 0; i < custom_ranges.size(); i++) { | 1063 for (size_t i = 0; i < custom_ranges.size(); i++) { |
| 880 Sample sample = custom_ranges[i]; | 1064 Sample sample = custom_ranges[i]; |
| 881 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) | 1065 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) |
| 882 return false; | 1066 return false; |
| 883 if (sample != 0) | 1067 if (sample != 0) |
| 884 has_valid_range = true; | 1068 has_valid_range = true; |
| 885 } | 1069 } |
| 886 return has_valid_range; | 1070 return has_valid_range; |
| 887 } | 1071 } |
| 888 | 1072 |
| 889 // static | |
| 890 BucketRanges* CustomHistogram::CreateBucketRangesFromCustomRanges( | |
| 891 const std::vector<Sample>& custom_ranges) { | |
| 892 // Remove the duplicates in the custom ranges array. | |
| 893 std::vector<int> ranges = custom_ranges; | |
| 894 ranges.push_back(0); // Ensure we have a zero value. | |
| 895 ranges.push_back(HistogramBase::kSampleType_MAX); | |
| 896 std::sort(ranges.begin(), ranges.end()); | |
| 897 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end()); | |
| 898 | |
| 899 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); | |
| 900 for (size_t i = 0; i < ranges.size(); i++) { | |
| 901 bucket_ranges->set_range(i, ranges[i]); | |
| 902 } | |
| 903 bucket_ranges->ResetChecksum(); | |
| 904 return bucket_ranges; | |
| 905 } | |
| 906 | |
| 907 } // namespace base | 1073 } // namespace base |
| OLD | NEW |