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 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
146 }; | 146 }; |
147 | 147 |
148 HistogramBase* Histogram::Factory::Build() { | 148 HistogramBase* Histogram::Factory::Build() { |
149 // Import histograms from known persistent storage. Histograms could have | 149 // Import histograms from known persistent storage. Histograms could have |
150 // been added by other processes and they must be fetched and recognized | 150 // been added by other processes and they must be fetched and recognized |
151 // locally in order to be found by FindHistograms() below. If the persistent | 151 // locally in order to be found by FindHistograms() below. If the persistent |
152 // memory segment is not shared between processes, this call does nothing. | 152 // memory segment is not shared between processes, this call does nothing. |
153 PersistentHistogramAllocator::ImportGlobalHistograms(); | 153 PersistentHistogramAllocator::ImportGlobalHistograms(); |
154 | 154 |
155 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_); | 155 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_); |
| 156 |
| 157 // crbug.com/588946 debugging. See comment at end of function. |
| 158 const BucketRanges* created_ranges = |
| 159 reinterpret_cast<const BucketRanges*>(0xDEADBEEF); |
| 160 const BucketRanges* registered_ranges = |
| 161 reinterpret_cast<const BucketRanges*>(0xDEADBEEF); |
| 162 scoped_ptr<HistogramBase> tentative_histogram; |
| 163 PersistentHistogramAllocator* allocator = |
| 164 reinterpret_cast<PersistentHistogramAllocator*>(0xDEADBEEF); |
| 165 PersistentHistogramAllocator::Reference histogram_ref = 0xDEADBEEF; |
| 166 |
156 if (!histogram) { | 167 if (!histogram) { |
157 // To avoid racy destruction at shutdown, the following will be leaked. | 168 // To avoid racy destruction at shutdown, the following will be leaked. |
158 const BucketRanges* created_ranges = CreateRanges(); | 169 created_ranges = CreateRanges(); |
159 const BucketRanges* registered_ranges = | 170 registered_ranges = |
160 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges); | 171 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges); |
161 | 172 |
162 // In most cases, the bucket-count, minimum, and maximum values are known | 173 // In most cases, the bucket-count, minimum, and maximum values are known |
163 // when the code is written and so are passed in explicitly. In other | 174 // when the code is written and so are passed in explicitly. In other |
164 // cases (such as with a CustomHistogram), they are calculated dynamically | 175 // cases (such as with a CustomHistogram), they are calculated dynamically |
165 // at run-time. In the latter case, those ctor parameters are zero and | 176 // at run-time. In the latter case, those ctor parameters are zero and |
166 // the results extracted from the result of CreateRanges(). | 177 // the results extracted from the result of CreateRanges(). |
167 if (bucket_count_ == 0) { | 178 if (bucket_count_ == 0) { |
168 bucket_count_ = static_cast<uint32_t>(registered_ranges->bucket_count()); | 179 bucket_count_ = static_cast<uint32_t>(registered_ranges->bucket_count()); |
169 minimum_ = registered_ranges->range(1); | 180 minimum_ = registered_ranges->range(1); |
170 maximum_ = registered_ranges->range(bucket_count_ - 1); | 181 maximum_ = registered_ranges->range(bucket_count_ - 1); |
171 } | 182 } |
| 183 CHECK_LT(0, minimum_); |
| 184 CHECK_LT(0, maximum_); |
172 | 185 |
173 // Try to create the histogram using a "persistent" allocator. As of | 186 // Try to create the histogram using a "persistent" allocator. As of |
174 // 2016-02-25, the availability of such is controlled by a base::Feature | 187 // 2016-02-25, the availability of such is controlled by a base::Feature |
175 // that is off by default. If the allocator doesn't exist or if | 188 // that is off by default. If the allocator doesn't exist or if |
176 // allocating from it fails, code below will allocate the histogram from | 189 // allocating from it fails, code below will allocate the histogram from |
177 // the process heap. | 190 // the process heap. |
178 PersistentHistogramAllocator::Reference histogram_ref = 0; | 191 allocator = |
179 scoped_ptr<HistogramBase> tentative_histogram; | |
180 PersistentHistogramAllocator* allocator = | |
181 PersistentHistogramAllocator::GetGlobalAllocator(); | 192 PersistentHistogramAllocator::GetGlobalAllocator(); |
182 if (allocator) { | 193 if (allocator) { |
183 tentative_histogram = allocator->AllocateHistogram( | 194 tentative_histogram = allocator->AllocateHistogram( |
184 histogram_type_, | 195 histogram_type_, |
185 name_, | 196 name_, |
186 minimum_, | 197 minimum_, |
187 maximum_, | 198 maximum_, |
188 registered_ranges, | 199 registered_ranges, |
189 flags_, | 200 flags_, |
190 &histogram_ref); | 201 &histogram_ref); |
| 202 CHECK_LT(0, minimum_); |
| 203 CHECK_LT(0, maximum_); |
| 204 CHECK_EQ( |
| 205 minimum_, |
| 206 static_cast<Histogram*>(tentative_histogram.get())->declared_min_); |
| 207 CHECK_EQ( |
| 208 maximum_, |
| 209 static_cast<Histogram*>(tentative_histogram.get())->declared_max_); |
191 } | 210 } |
192 | 211 |
193 // Handle the case where no persistent allocator is present or the | 212 // Handle the case where no persistent allocator is present or the |
194 // persistent allocation fails (perhaps because it is full). | 213 // persistent allocation fails (perhaps because it is full). |
195 if (!tentative_histogram) { | 214 if (!tentative_histogram) { |
196 DCHECK(!histogram_ref); // Should never have been set. | 215 // DCHECK(!histogram_ref); // Should never have been set. |
197 DCHECK(!allocator); // Shouldn't have failed. | 216 // DCHECK(!allocator); // Shouldn't have failed. |
198 flags_ &= ~HistogramBase::kIsPersistent; | 217 flags_ &= ~HistogramBase::kIsPersistent; |
199 tentative_histogram = HeapAlloc(registered_ranges); | 218 tentative_histogram = HeapAlloc(registered_ranges); |
200 tentative_histogram->SetFlags(flags_); | 219 tentative_histogram->SetFlags(flags_); |
| 220 |
| 221 CHECK_LT(0, minimum_); |
| 222 CHECK_LT(0, maximum_); |
| 223 CHECK_EQ( |
| 224 minimum_, |
| 225 static_cast<Histogram*>(tentative_histogram.get())->declared_min_); |
| 226 CHECK_EQ( |
| 227 maximum_, |
| 228 static_cast<Histogram*>(tentative_histogram.get())->declared_max_); |
201 } | 229 } |
202 | 230 |
203 FillHistogram(tentative_histogram.get()); | 231 FillHistogram(tentative_histogram.get()); |
204 | 232 |
205 // Register this histogram with the StatisticsRecorder. Keep a copy of | 233 // Register this histogram with the StatisticsRecorder. Keep a copy of |
206 // the pointer value to tell later whether the locally created histogram | 234 // the pointer value to tell later whether the locally created histogram |
207 // was registered or deleted. The type is "void" because it could point | 235 // was registered or deleted. The type is "void" because it could point |
208 // to released memory after the following line. | 236 // to released memory after the following line. |
209 const void* tentative_histogram_ptr = tentative_histogram.get(); | 237 const void* tentative_histogram_ptr = tentative_histogram.get(); |
210 histogram = StatisticsRecorder::RegisterOrDeleteDuplicate( | 238 histogram = StatisticsRecorder::RegisterOrDeleteDuplicate( |
211 tentative_histogram.release()); | 239 tentative_histogram.release()); |
212 | 240 |
213 // Persistent histograms need some follow-up processing. | 241 // Persistent histograms need some follow-up processing. |
214 if (histogram_ref) { | 242 if (histogram_ref != 0xDEADBEEF) { |
215 allocator->FinalizeHistogram(histogram_ref, | 243 allocator->FinalizeHistogram(histogram_ref, |
216 histogram == tentative_histogram_ptr); | 244 histogram == tentative_histogram_ptr); |
217 } | 245 } |
218 | 246 |
219 // Update report on created histograms. | 247 // Update report on created histograms. |
220 ReportHistogramActivity(*histogram, HISTOGRAM_CREATED); | 248 ReportHistogramActivity(*histogram, HISTOGRAM_CREATED); |
221 } else { | 249 } else { |
222 // Update report on lookup histograms. | 250 // Update report on lookup histograms. |
223 ReportHistogramActivity(*histogram, HISTOGRAM_LOOKUP); | 251 ReportHistogramActivity(*histogram, HISTOGRAM_LOOKUP); |
224 } | 252 } |
225 | 253 |
226 DCHECK_EQ(histogram_type_, histogram->GetHistogramType()) << name_; | 254 DCHECK_EQ(histogram_type_, histogram->GetHistogramType()) << name_; |
| 255 bool bad_args = false; |
| 256 HistogramBase* existing_histogram = histogram; |
| 257 HistogramType existing_type = histogram->GetHistogramType(); |
| 258 const char* existing_name = histogram->histogram_name().c_str(); |
| 259 Sample existing_minimum = static_cast<Histogram*>(histogram)->declared_min_; |
| 260 Sample existing_maximum = static_cast<Histogram*>(histogram)->declared_max_; |
| 261 uint32_t existing_bucket_count = |
| 262 static_cast<Histogram*>(histogram)->bucket_count(); |
| 263 |
227 if (bucket_count_ != 0 && | 264 if (bucket_count_ != 0 && |
228 !histogram->HasConstructionArguments(minimum_, maximum_, bucket_count_)) { | 265 !histogram->HasConstructionArguments(minimum_, maximum_, bucket_count_)) { |
229 // The construction arguments do not match the existing histogram. This can | 266 // The construction arguments do not match the existing histogram. This can |
230 // come about if an extension updates in the middle of a chrome run and has | 267 // come about if an extension updates in the middle of a chrome run and has |
231 // changed one of them, or simply by bad code within Chrome itself. We | 268 // changed one of them, or simply by bad code within Chrome itself. We |
232 // return NULL here with the expectation that bad code in Chrome will crash | 269 // return NULL here with the expectation that bad code in Chrome will crash |
233 // on dereference, but extension/Pepper APIs will guard against NULL and not | 270 // on dereference, but extension/Pepper APIs will guard against NULL and not |
234 // crash. | 271 // crash. |
235 DLOG(ERROR) << "Histogram " << name_ << " has bad construction arguments"; | 272 DLOG(ERROR) << "Histogram " << name_ << " has bad construction arguments"; |
236 return nullptr; | 273 bad_args = true; |
| 274 histogram = nullptr; |
237 } | 275 } |
| 276 |
| 277 #if !DCHECK_IS_ON() && defined(OS_WIN) // Affect only Windows release builds. |
| 278 // For the moment, crash here so that collected crash reports have access |
| 279 // to the construction values in order to figure out why this is failing. |
| 280 // TODO(bcwhite): Remove this once crbug.com/588946 is resolved. Also remove |
| 281 // from beta-branch because we don't want crashes due to misbehaving |
| 282 // extensions (see comment above). |
| 283 if (!histogram) { |
| 284 HistogramType histogram_type = histogram_type_; |
| 285 HistogramBase::Sample minimum = minimum_; |
| 286 HistogramBase::Sample maximum = maximum_; |
| 287 uint32_t bucket_count = bucket_count_; |
| 288 int32_t flags = flags_; |
| 289 CHECK(histogram) << name_ << ": bad-args=" << bad_args; |
| 290 base::debug::Alias(&histogram_type); |
| 291 base::debug::Alias(&minimum); |
| 292 base::debug::Alias(&maximum); |
| 293 base::debug::Alias(&bucket_count); |
| 294 base::debug::Alias(&flags); |
| 295 base::debug::Alias(&created_ranges); |
| 296 base::debug::Alias(®istered_ranges); |
| 297 base::debug::Alias(&histogram_ref); |
| 298 base::debug::Alias(&tentative_histogram); |
| 299 base::debug::Alias(&allocator); |
| 300 base::debug::Alias(&tentative_histogram); |
| 301 } |
| 302 #endif |
| 303 |
| 304 // Down here so vars are always "used". |
| 305 base::debug::Alias(&bad_args); |
| 306 base::debug::Alias(&existing_histogram); |
| 307 base::debug::Alias(&existing_type); |
| 308 base::debug::Alias(&existing_name); |
| 309 base::debug::Alias(&existing_minimum); |
| 310 base::debug::Alias(&existing_maximum); |
| 311 base::debug::Alias(&existing_bucket_count); |
238 return histogram; | 312 return histogram; |
239 } | 313 } |
240 | 314 |
241 HistogramBase* Histogram::FactoryGet(const std::string& name, | 315 HistogramBase* Histogram::FactoryGet(const std::string& name, |
242 Sample minimum, | 316 Sample minimum, |
243 Sample maximum, | 317 Sample maximum, |
244 uint32_t bucket_count, | 318 uint32_t bucket_count, |
245 int32_t flags) { | 319 int32_t flags) { |
246 bool valid_arguments = | 320 bool valid_arguments = |
247 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); | 321 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
490 } | 564 } |
491 | 565 |
492 Histogram::Histogram(const std::string& name, | 566 Histogram::Histogram(const std::string& name, |
493 Sample minimum, | 567 Sample minimum, |
494 Sample maximum, | 568 Sample maximum, |
495 const BucketRanges* ranges) | 569 const BucketRanges* ranges) |
496 : HistogramBase(name), | 570 : HistogramBase(name), |
497 bucket_ranges_(ranges), | 571 bucket_ranges_(ranges), |
498 declared_min_(minimum), | 572 declared_min_(minimum), |
499 declared_max_(maximum) { | 573 declared_max_(maximum) { |
| 574 CHECK_LT(0, minimum); |
| 575 CHECK_LT(0, maximum); |
500 if (ranges) | 576 if (ranges) |
501 samples_.reset(new SampleVector(HashMetricName(name), ranges)); | 577 samples_.reset(new SampleVector(HashMetricName(name), ranges)); |
| 578 CHECK_EQ(minimum, declared_min_); |
| 579 CHECK_EQ(maximum, declared_max_); |
502 } | 580 } |
503 | 581 |
504 Histogram::Histogram(const std::string& name, | 582 Histogram::Histogram(const std::string& name, |
505 Sample minimum, | 583 Sample minimum, |
506 Sample maximum, | 584 Sample maximum, |
507 const BucketRanges* ranges, | 585 const BucketRanges* ranges, |
508 HistogramBase::AtomicCount* counts, | 586 HistogramBase::AtomicCount* counts, |
509 HistogramBase::AtomicCount* logged_counts, | 587 HistogramBase::AtomicCount* logged_counts, |
510 uint32_t counts_size, | 588 uint32_t counts_size, |
511 HistogramSamples::Metadata* meta, | 589 HistogramSamples::Metadata* meta, |
512 HistogramSamples::Metadata* logged_meta) | 590 HistogramSamples::Metadata* logged_meta) |
513 : HistogramBase(name), | 591 : HistogramBase(name), |
514 bucket_ranges_(ranges), | 592 bucket_ranges_(ranges), |
515 declared_min_(minimum), | 593 declared_min_(minimum), |
516 declared_max_(maximum) { | 594 declared_max_(maximum) { |
| 595 CHECK_LT(0, minimum); |
| 596 CHECK_LT(0, maximum); |
517 if (ranges) { | 597 if (ranges) { |
518 samples_.reset(new SampleVector(HashMetricName(name), | 598 samples_.reset(new SampleVector(HashMetricName(name), |
519 counts, counts_size, meta, ranges)); | 599 counts, counts_size, meta, ranges)); |
520 logged_samples_.reset(new SampleVector(samples_->id(), logged_counts, | 600 logged_samples_.reset(new SampleVector(samples_->id(), logged_counts, |
521 counts_size, logged_meta, ranges)); | 601 counts_size, logged_meta, ranges)); |
522 } | 602 } |
| 603 CHECK_EQ(minimum, declared_min_); |
| 604 CHECK_EQ(maximum, declared_max_); |
523 } | 605 } |
524 | 606 |
525 Histogram::~Histogram() { | 607 Histogram::~Histogram() { |
526 } | 608 } |
527 | 609 |
528 bool Histogram::PrintEmptyBucket(uint32_t index) const { | 610 bool Histogram::PrintEmptyBucket(uint32_t index) const { |
529 return true; | 611 return true; |
530 } | 612 } |
531 | 613 |
532 // Use the actual bucket widths (like a linear histogram) until the widths get | 614 // Use the actual bucket widths (like a linear histogram) until the widths get |
(...skipping 635 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1168 Sample sample = custom_ranges[i]; | 1250 Sample sample = custom_ranges[i]; |
1169 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) | 1251 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) |
1170 return false; | 1252 return false; |
1171 if (sample != 0) | 1253 if (sample != 0) |
1172 has_valid_range = true; | 1254 has_valid_range = true; |
1173 } | 1255 } |
1174 return has_valid_range; | 1256 return has_valid_range; |
1175 } | 1257 } |
1176 | 1258 |
1177 } // namespace base | 1259 } // namespace base |
OLD | NEW |