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 | |
167 if (!histogram) { | 156 if (!histogram) { |
168 // To avoid racy destruction at shutdown, the following will be leaked. | 157 // To avoid racy destruction at shutdown, the following will be leaked. |
169 created_ranges = CreateRanges(); | 158 const BucketRanges* created_ranges = CreateRanges(); |
170 registered_ranges = | 159 const BucketRanges* registered_ranges = |
171 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges); | 160 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges); |
172 | 161 |
173 // In most cases, the bucket-count, minimum, and maximum values are known | 162 // In most cases, the bucket-count, minimum, and maximum values are known |
174 // when the code is written and so are passed in explicitly. In other | 163 // when the code is written and so are passed in explicitly. In other |
175 // cases (such as with a CustomHistogram), they are calculated dynamically | 164 // cases (such as with a CustomHistogram), they are calculated dynamically |
176 // at run-time. In the latter case, those ctor parameters are zero and | 165 // at run-time. In the latter case, those ctor parameters are zero and |
177 // the results extracted from the result of CreateRanges(). | 166 // the results extracted from the result of CreateRanges(). |
178 if (bucket_count_ == 0) { | 167 if (bucket_count_ == 0) { |
179 bucket_count_ = static_cast<uint32_t>(registered_ranges->bucket_count()); | 168 bucket_count_ = static_cast<uint32_t>(registered_ranges->bucket_count()); |
180 minimum_ = registered_ranges->range(1); | 169 minimum_ = registered_ranges->range(1); |
181 maximum_ = registered_ranges->range(bucket_count_ - 1); | 170 maximum_ = registered_ranges->range(bucket_count_ - 1); |
182 } | 171 } |
183 CHECK_LT(0, minimum_); | |
184 CHECK_LT(0, maximum_); | |
185 | 172 |
186 // Try to create the histogram using a "persistent" allocator. As of | 173 // Try to create the histogram using a "persistent" allocator. As of |
187 // 2016-02-25, the availability of such is controlled by a base::Feature | 174 // 2016-02-25, the availability of such is controlled by a base::Feature |
188 // that is off by default. If the allocator doesn't exist or if | 175 // that is off by default. If the allocator doesn't exist or if |
189 // allocating from it fails, code below will allocate the histogram from | 176 // allocating from it fails, code below will allocate the histogram from |
190 // the process heap. | 177 // the process heap. |
191 allocator = | 178 PersistentHistogramAllocator::Reference histogram_ref = 0; |
| 179 scoped_ptr<HistogramBase> tentative_histogram; |
| 180 PersistentHistogramAllocator* allocator = |
192 PersistentHistogramAllocator::GetGlobalAllocator(); | 181 PersistentHistogramAllocator::GetGlobalAllocator(); |
193 if (allocator) { | 182 if (allocator) { |
194 tentative_histogram = allocator->AllocateHistogram( | 183 tentative_histogram = allocator->AllocateHistogram( |
195 histogram_type_, | 184 histogram_type_, |
196 name_, | 185 name_, |
197 minimum_, | 186 minimum_, |
198 maximum_, | 187 maximum_, |
199 registered_ranges, | 188 registered_ranges, |
200 flags_, | 189 flags_, |
201 &histogram_ref); | 190 &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_); | |
210 } | 191 } |
211 | 192 |
212 // Handle the case where no persistent allocator is present or the | 193 // Handle the case where no persistent allocator is present or the |
213 // persistent allocation fails (perhaps because it is full). | 194 // persistent allocation fails (perhaps because it is full). |
214 if (!tentative_histogram) { | 195 if (!tentative_histogram) { |
215 // DCHECK(!histogram_ref); // Should never have been set. | 196 DCHECK(!histogram_ref); // Should never have been set. |
216 // DCHECK(!allocator); // Shouldn't have failed. | 197 DCHECK(!allocator); // Shouldn't have failed. |
217 flags_ &= ~HistogramBase::kIsPersistent; | 198 flags_ &= ~HistogramBase::kIsPersistent; |
218 tentative_histogram = HeapAlloc(registered_ranges); | 199 tentative_histogram = HeapAlloc(registered_ranges); |
219 tentative_histogram->SetFlags(flags_); | 200 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_); | |
229 } | 201 } |
230 | 202 |
231 FillHistogram(tentative_histogram.get()); | 203 FillHistogram(tentative_histogram.get()); |
232 | 204 |
233 // Register this histogram with the StatisticsRecorder. Keep a copy of | 205 // Register this histogram with the StatisticsRecorder. Keep a copy of |
234 // the pointer value to tell later whether the locally created histogram | 206 // the pointer value to tell later whether the locally created histogram |
235 // was registered or deleted. The type is "void" because it could point | 207 // was registered or deleted. The type is "void" because it could point |
236 // to released memory after the following line. | 208 // to released memory after the following line. |
237 const void* tentative_histogram_ptr = tentative_histogram.get(); | 209 const void* tentative_histogram_ptr = tentative_histogram.get(); |
238 histogram = StatisticsRecorder::RegisterOrDeleteDuplicate( | 210 histogram = StatisticsRecorder::RegisterOrDeleteDuplicate( |
239 tentative_histogram.release()); | 211 tentative_histogram.release()); |
240 | 212 |
241 // Persistent histograms need some follow-up processing. | 213 // Persistent histograms need some follow-up processing. |
242 if (histogram_ref != 0xDEADBEEF) { | 214 if (histogram_ref) { |
243 allocator->FinalizeHistogram(histogram_ref, | 215 allocator->FinalizeHistogram(histogram_ref, |
244 histogram == tentative_histogram_ptr); | 216 histogram == tentative_histogram_ptr); |
245 } | 217 } |
246 | 218 |
247 // Update report on created histograms. | 219 // Update report on created histograms. |
248 ReportHistogramActivity(*histogram, HISTOGRAM_CREATED); | 220 ReportHistogramActivity(*histogram, HISTOGRAM_CREATED); |
249 } else { | 221 } else { |
250 // Update report on lookup histograms. | 222 // Update report on lookup histograms. |
251 ReportHistogramActivity(*histogram, HISTOGRAM_LOOKUP); | 223 ReportHistogramActivity(*histogram, HISTOGRAM_LOOKUP); |
252 } | 224 } |
253 | 225 |
254 DCHECK_EQ(histogram_type_, histogram->GetHistogramType()) << name_; | 226 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 | |
264 if (bucket_count_ != 0 && | 227 if (bucket_count_ != 0 && |
265 !histogram->HasConstructionArguments(minimum_, maximum_, bucket_count_)) { | 228 !histogram->HasConstructionArguments(minimum_, maximum_, bucket_count_)) { |
266 // The construction arguments do not match the existing histogram. This can | 229 // The construction arguments do not match the existing histogram. This can |
267 // come about if an extension updates in the middle of a chrome run and has | 230 // come about if an extension updates in the middle of a chrome run and has |
268 // changed one of them, or simply by bad code within Chrome itself. We | 231 // changed one of them, or simply by bad code within Chrome itself. We |
269 // return NULL here with the expectation that bad code in Chrome will crash | 232 // return NULL here with the expectation that bad code in Chrome will crash |
270 // on dereference, but extension/Pepper APIs will guard against NULL and not | 233 // on dereference, but extension/Pepper APIs will guard against NULL and not |
271 // crash. | 234 // crash. |
272 DLOG(ERROR) << "Histogram " << name_ << " has bad construction arguments"; | 235 DLOG(ERROR) << "Histogram " << name_ << " has bad construction arguments"; |
273 bad_args = true; | 236 return nullptr; |
274 histogram = nullptr; | |
275 } | 237 } |
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); | |
312 return histogram; | 238 return histogram; |
313 } | 239 } |
314 | 240 |
315 HistogramBase* Histogram::FactoryGet(const std::string& name, | 241 HistogramBase* Histogram::FactoryGet(const std::string& name, |
316 Sample minimum, | 242 Sample minimum, |
317 Sample maximum, | 243 Sample maximum, |
318 uint32_t bucket_count, | 244 uint32_t bucket_count, |
319 int32_t flags) { | 245 int32_t flags) { |
320 bool valid_arguments = | 246 bool valid_arguments = |
321 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); | 247 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
564 } | 490 } |
565 | 491 |
566 Histogram::Histogram(const std::string& name, | 492 Histogram::Histogram(const std::string& name, |
567 Sample minimum, | 493 Sample minimum, |
568 Sample maximum, | 494 Sample maximum, |
569 const BucketRanges* ranges) | 495 const BucketRanges* ranges) |
570 : HistogramBase(name), | 496 : HistogramBase(name), |
571 bucket_ranges_(ranges), | 497 bucket_ranges_(ranges), |
572 declared_min_(minimum), | 498 declared_min_(minimum), |
573 declared_max_(maximum) { | 499 declared_max_(maximum) { |
574 CHECK_LT(0, minimum); | |
575 CHECK_LT(0, maximum); | |
576 if (ranges) | 500 if (ranges) |
577 samples_.reset(new SampleVector(HashMetricName(name), ranges)); | 501 samples_.reset(new SampleVector(HashMetricName(name), ranges)); |
578 CHECK_EQ(minimum, declared_min_); | |
579 CHECK_EQ(maximum, declared_max_); | |
580 } | 502 } |
581 | 503 |
582 Histogram::Histogram(const std::string& name, | 504 Histogram::Histogram(const std::string& name, |
583 Sample minimum, | 505 Sample minimum, |
584 Sample maximum, | 506 Sample maximum, |
585 const BucketRanges* ranges, | 507 const BucketRanges* ranges, |
586 HistogramBase::AtomicCount* counts, | 508 HistogramBase::AtomicCount* counts, |
587 HistogramBase::AtomicCount* logged_counts, | 509 HistogramBase::AtomicCount* logged_counts, |
588 uint32_t counts_size, | 510 uint32_t counts_size, |
589 HistogramSamples::Metadata* meta, | 511 HistogramSamples::Metadata* meta, |
590 HistogramSamples::Metadata* logged_meta) | 512 HistogramSamples::Metadata* logged_meta) |
591 : HistogramBase(name), | 513 : HistogramBase(name), |
592 bucket_ranges_(ranges), | 514 bucket_ranges_(ranges), |
593 declared_min_(minimum), | 515 declared_min_(minimum), |
594 declared_max_(maximum) { | 516 declared_max_(maximum) { |
595 CHECK_LT(0, minimum); | |
596 CHECK_LT(0, maximum); | |
597 if (ranges) { | 517 if (ranges) { |
598 samples_.reset(new SampleVector(HashMetricName(name), | 518 samples_.reset(new SampleVector(HashMetricName(name), |
599 counts, counts_size, meta, ranges)); | 519 counts, counts_size, meta, ranges)); |
600 logged_samples_.reset(new SampleVector(samples_->id(), logged_counts, | 520 logged_samples_.reset(new SampleVector(samples_->id(), logged_counts, |
601 counts_size, logged_meta, ranges)); | 521 counts_size, logged_meta, ranges)); |
602 } | 522 } |
603 CHECK_EQ(minimum, declared_min_); | |
604 CHECK_EQ(maximum, declared_max_); | |
605 } | 523 } |
606 | 524 |
607 Histogram::~Histogram() { | 525 Histogram::~Histogram() { |
608 } | 526 } |
609 | 527 |
610 bool Histogram::PrintEmptyBucket(uint32_t index) const { | 528 bool Histogram::PrintEmptyBucket(uint32_t index) const { |
611 return true; | 529 return true; |
612 } | 530 } |
613 | 531 |
614 // Use the actual bucket widths (like a linear histogram) until the widths get | 532 // 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... |
1250 Sample sample = custom_ranges[i]; | 1168 Sample sample = custom_ranges[i]; |
1251 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) | 1169 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) |
1252 return false; | 1170 return false; |
1253 if (sample != 0) | 1171 if (sample != 0) |
1254 has_valid_range = true; | 1172 has_valid_range = true; |
1255 } | 1173 } |
1256 return has_valid_range; | 1174 return has_valid_range; |
1257 } | 1175 } |
1258 | 1176 |
1259 } // namespace base | 1177 } // namespace base |
OLD | NEW |