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 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 }; | 147 }; |
148 | 148 |
149 HistogramBase* Histogram::Factory::Build() { | 149 HistogramBase* Histogram::Factory::Build() { |
150 // Import histograms from known persistent storage. Histograms could have | 150 // Import histograms from known persistent storage. Histograms could have |
151 // been added by other processes and they must be fetched and recognized | 151 // been added by other processes and they must be fetched and recognized |
152 // locally in order to be found by FindHistograms() below. If the persistent | 152 // locally in order to be found by FindHistograms() below. If the persistent |
153 // memory segment is not shared between processes, this call does nothing. | 153 // memory segment is not shared between processes, this call does nothing. |
154 ImportPersistentHistograms(); | 154 ImportPersistentHistograms(); |
155 | 155 |
156 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_); | 156 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_); |
157 | |
158 // crbug.com/588946 debugging. See comment at end of function. | |
159 const BucketRanges* created_ranges = | |
160 reinterpret_cast<const BucketRanges*>(0xDEADBEEF); | |
161 const BucketRanges* registered_ranges = | |
162 reinterpret_cast<const BucketRanges*>(0xDEADBEEF); | |
163 HistogramBase* tentative_histogram = | |
164 reinterpret_cast<HistogramBase*>(0xDEADBEEF); | |
165 PersistentMemoryAllocator* allocator = | |
166 reinterpret_cast<PersistentMemoryAllocator*>(0xDEADBEEF); | |
167 PersistentMemoryAllocator::Reference histogram_ref = 0xDEADBEEF; | |
168 | |
169 if (!histogram) { | 157 if (!histogram) { |
170 // To avoid racy destruction at shutdown, the following will be leaked. | 158 // To avoid racy destruction at shutdown, the following will be leaked. |
171 created_ranges = CreateRanges(); | 159 const BucketRanges* created_ranges = CreateRanges(); |
172 registered_ranges = | 160 const BucketRanges* registered_ranges = |
173 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges); | 161 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges); |
174 | 162 |
175 // In most cases, the bucket-count, minimum, and maximum values are known | 163 // In most cases, the bucket-count, minimum, and maximum values are known |
176 // when the code is written and so are passed in explicitly. In other | 164 // when the code is written and so are passed in explicitly. In other |
177 // cases (such as with a CustomHistogram), they are calculated dynamically | 165 // cases (such as with a CustomHistogram), they are calculated dynamically |
178 // at run-time. In the latter case, those ctor parameters are zero and | 166 // at run-time. In the latter case, those ctor parameters are zero and |
179 // the results extracted from the result of CreateRanges(). | 167 // the results extracted from the result of CreateRanges(). |
180 if (bucket_count_ == 0) { | 168 if (bucket_count_ == 0) { |
181 bucket_count_ = static_cast<uint32_t>(registered_ranges->bucket_count()); | 169 bucket_count_ = static_cast<uint32_t>(registered_ranges->bucket_count()); |
182 minimum_ = registered_ranges->range(1); | 170 minimum_ = registered_ranges->range(1); |
183 maximum_ = registered_ranges->range(bucket_count_ - 1); | 171 maximum_ = registered_ranges->range(bucket_count_ - 1); |
184 } | 172 } |
185 CHECK_LT(0, minimum_); | |
186 CHECK_LT(0, maximum_); | |
187 | 173 |
188 // Try to create the histogram using a "persistent" allocator. As of | 174 // Try to create the histogram using a "persistent" allocator. As of |
189 // 2015-01-14, the availability of such is controlled by a base::Feature | 175 // 2015-01-14, the availability of such is controlled by a base::Feature |
190 // that is off by default. If the allocator doesn't exist or if | 176 // that is off by default. If the allocator doesn't exist or if |
191 // allocating from it fails, code below will allocate the histogram from | 177 // allocating from it fails, code below will allocate the histogram from |
192 // the process heap. | 178 // the process heap. |
193 histogram_ref = 0; | 179 PersistentMemoryAllocator::Reference histogram_ref = 0; |
194 tentative_histogram = nullptr; | 180 HistogramBase* tentative_histogram = nullptr; |
195 allocator = | 181 PersistentMemoryAllocator* allocator = |
196 GetPersistentHistogramMemoryAllocator(); | 182 GetPersistentHistogramMemoryAllocator(); |
197 if (allocator) { | 183 if (allocator) { |
198 flags_ |= HistogramBase::kIsPersistent; | 184 flags_ |= HistogramBase::kIsPersistent; |
199 tentative_histogram = AllocatePersistentHistogram( | 185 tentative_histogram = AllocatePersistentHistogram( |
200 allocator, | 186 allocator, |
201 histogram_type_, | 187 histogram_type_, |
202 name_, | 188 name_, |
203 minimum_, | 189 minimum_, |
204 maximum_, | 190 maximum_, |
205 registered_ranges, | 191 registered_ranges, |
206 flags_, | 192 flags_, |
207 &histogram_ref); | 193 &histogram_ref); |
208 CHECK_LT(0, minimum_); | |
209 CHECK_LT(0, maximum_); | |
210 CHECK_EQ(minimum_, | |
211 static_cast<Histogram*>(tentative_histogram)->declared_min_); | |
212 CHECK_EQ(maximum_, | |
213 static_cast<Histogram*>(tentative_histogram)->declared_max_); | |
214 } | 194 } |
215 | 195 |
216 // Handle the case where no persistent allocator is present or the | 196 // Handle the case where no persistent allocator is present or the |
217 // persistent allocation fails (perhaps because it is full). | 197 // persistent allocation fails (perhaps because it is full). |
218 if (!tentative_histogram) { | 198 if (!tentative_histogram) { |
219 DCHECK(!histogram_ref); // Should never have been set. | 199 DCHECK(!histogram_ref); // Should never have been set. |
220 DCHECK(!allocator); // Shouldn't have failed. | 200 DCHECK(!allocator); // Shouldn't have failed. |
221 flags_ &= ~HistogramBase::kIsPersistent; | 201 flags_ &= ~HistogramBase::kIsPersistent; |
222 tentative_histogram = HeapAlloc(registered_ranges); | 202 tentative_histogram = HeapAlloc(registered_ranges); |
223 CHECK_LT(0, minimum_); | |
224 CHECK_LT(0, maximum_); | |
225 CHECK_EQ(minimum_, | |
226 static_cast<Histogram*>(tentative_histogram)->declared_min_); | |
227 CHECK_EQ(maximum_, | |
228 static_cast<Histogram*>(tentative_histogram)->declared_max_); | |
229 } | 203 } |
230 | 204 |
231 FillHistogram(tentative_histogram); | 205 FillHistogram(tentative_histogram); |
232 histogram = | 206 histogram = |
233 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | 207 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
234 | 208 |
235 // Persistent histograms need some follow-up processing. | 209 // Persistent histograms need some follow-up processing. |
236 if (histogram_ref) { | 210 if (histogram_ref) { |
237 FinalizePersistentHistogram(histogram_ref, | 211 FinalizePersistentHistogram(histogram_ref, |
238 histogram == tentative_histogram); | 212 histogram == tentative_histogram); |
239 } | 213 } |
240 } | 214 } |
241 | 215 |
242 DCHECK_EQ(histogram_type_, histogram->GetHistogramType()); | 216 DCHECK_EQ(histogram_type_, histogram->GetHistogramType()); |
243 bool bad_args = false; | |
244 HistogramBase* existing_histogram = histogram; | |
245 HistogramType existing_type = histogram->GetHistogramType(); | |
246 const char* existing_name = histogram->histogram_name().c_str(); | |
247 Sample existing_minimum = static_cast<Histogram*>(histogram)->declared_min_; | |
248 Sample existing_maximum = static_cast<Histogram*>(histogram)->declared_max_; | |
249 uint32_t existing_bucket_count = | |
250 static_cast<Histogram*>(histogram)->bucket_count(); | |
251 | |
252 if (bucket_count_ != 0 && | 217 if (bucket_count_ != 0 && |
253 !histogram->HasConstructionArguments(minimum_, maximum_, bucket_count_)) { | 218 !histogram->HasConstructionArguments(minimum_, maximum_, bucket_count_)) { |
254 // The construction arguments do not match the existing histogram. This can | 219 // The construction arguments do not match the existing histogram. This can |
255 // come about if an extension updates in the middle of a chrome run and has | 220 // come about if an extension updates in the middle of a chrome run and has |
256 // changed one of them, or simply by bad code within Chrome itself. We | 221 // changed one of them, or simply by bad code within Chrome itself. We |
257 // return NULL here with the expectation that bad code in Chrome will crash | 222 // return NULL here with the expectation that bad code in Chrome will crash |
258 // on dereference, but extension/Pepper APIs will guard against NULL and not | 223 // on dereference, but extension/Pepper APIs will guard against NULL and not |
259 // crash. | 224 // crash. |
260 DLOG(ERROR) << "Histogram " << name_ << " has bad construction arguments"; | 225 DLOG(ERROR) << "Histogram " << name_ << " has bad construction arguments"; |
261 bad_args = true; | 226 return nullptr; |
262 histogram = nullptr; | |
263 } | 227 } |
264 | |
265 #if !DCHECK_IS_ON() // Don't affect tests, only release builds. | |
266 // For the moment, crash here so that collected crash reports have access | |
267 // to the construction values in order to figure out why this is failing. | |
268 // TODO(bcwhite): Remove this once crbug.com/588946 is resolved. Also remove | |
269 // from beta-branch because we don't want crashes due to misbehaving | |
270 // extensions (see comment above). | |
271 if (!histogram) { | |
272 HistogramType histogram_type = histogram_type_; | |
273 HistogramBase::Sample minimum = minimum_; | |
274 HistogramBase::Sample maximum = maximum_; | |
275 uint32_t bucket_count = bucket_count_; | |
276 int32_t flags = flags_; | |
277 CHECK(histogram) << name_ << ": bad-args=" << bad_args; | |
278 base::debug::Alias(&histogram_type); | |
279 base::debug::Alias(&minimum); | |
280 base::debug::Alias(&maximum); | |
281 base::debug::Alias(&bucket_count); | |
282 base::debug::Alias(&flags); | |
283 base::debug::Alias(&created_ranges); | |
284 base::debug::Alias(®istered_ranges); | |
285 base::debug::Alias(&histogram_ref); | |
286 base::debug::Alias(&tentative_histogram); | |
287 base::debug::Alias(&allocator); | |
288 base::debug::Alias(&tentative_histogram); | |
289 } | |
290 #endif | |
291 | |
292 // Down here so vars are always "used". | |
293 base::debug::Alias(&bad_args); | |
294 base::debug::Alias(&existing_histogram); | |
295 base::debug::Alias(&existing_type); | |
296 base::debug::Alias(&existing_name); | |
297 base::debug::Alias(&existing_minimum); | |
298 base::debug::Alias(&existing_maximum); | |
299 base::debug::Alias(&existing_bucket_count); | |
300 return histogram; | 228 return histogram; |
301 } | 229 } |
302 | 230 |
303 HistogramBase* Histogram::FactoryGet(const std::string& name, | 231 HistogramBase* Histogram::FactoryGet(const std::string& name, |
304 Sample minimum, | 232 Sample minimum, |
305 Sample maximum, | 233 Sample maximum, |
306 uint32_t bucket_count, | 234 uint32_t bucket_count, |
307 int32_t flags) { | 235 int32_t flags) { |
308 bool valid_arguments = | 236 bool valid_arguments = |
309 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); | 237 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); |
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
551 } | 479 } |
552 | 480 |
553 Histogram::Histogram(const std::string& name, | 481 Histogram::Histogram(const std::string& name, |
554 Sample minimum, | 482 Sample minimum, |
555 Sample maximum, | 483 Sample maximum, |
556 const BucketRanges* ranges) | 484 const BucketRanges* ranges) |
557 : HistogramBase(name), | 485 : HistogramBase(name), |
558 bucket_ranges_(ranges), | 486 bucket_ranges_(ranges), |
559 declared_min_(minimum), | 487 declared_min_(minimum), |
560 declared_max_(maximum) { | 488 declared_max_(maximum) { |
561 CHECK_LT(0, minimum); | |
562 CHECK_LT(0, maximum); | |
563 if (ranges) | 489 if (ranges) |
564 samples_.reset(new SampleVector(HashMetricName(name), ranges)); | 490 samples_.reset(new SampleVector(HashMetricName(name), ranges)); |
565 CHECK_EQ(minimum, declared_min_); | |
566 CHECK_EQ(maximum, declared_max_); | |
567 } | 491 } |
568 | 492 |
569 Histogram::Histogram(const std::string& name, | 493 Histogram::Histogram(const std::string& name, |
570 Sample minimum, | 494 Sample minimum, |
571 Sample maximum, | 495 Sample maximum, |
572 const BucketRanges* ranges, | 496 const BucketRanges* ranges, |
573 HistogramBase::AtomicCount* counts, | 497 HistogramBase::AtomicCount* counts, |
574 HistogramBase::AtomicCount* logged_counts, | 498 HistogramBase::AtomicCount* logged_counts, |
575 uint32_t counts_size, | 499 uint32_t counts_size, |
576 HistogramSamples::Metadata* meta, | 500 HistogramSamples::Metadata* meta, |
577 HistogramSamples::Metadata* logged_meta) | 501 HistogramSamples::Metadata* logged_meta) |
578 : HistogramBase(name), | 502 : HistogramBase(name), |
579 bucket_ranges_(ranges), | 503 bucket_ranges_(ranges), |
580 declared_min_(minimum), | 504 declared_min_(minimum), |
581 declared_max_(maximum) { | 505 declared_max_(maximum) { |
582 CHECK_LT(0, minimum); | |
583 CHECK_LT(0, maximum); | |
584 if (ranges) { | 506 if (ranges) { |
585 samples_.reset(new SampleVector(HashMetricName(name), | 507 samples_.reset(new SampleVector(HashMetricName(name), |
586 counts, counts_size, meta, ranges)); | 508 counts, counts_size, meta, ranges)); |
587 logged_samples_.reset(new SampleVector(samples_->id(), logged_counts, | 509 logged_samples_.reset(new SampleVector(samples_->id(), logged_counts, |
588 counts_size, logged_meta, ranges)); | 510 counts_size, logged_meta, ranges)); |
589 } | 511 } |
590 CHECK_EQ(minimum, declared_min_); | |
591 CHECK_EQ(maximum, declared_max_); | |
592 } | 512 } |
593 | 513 |
594 Histogram::~Histogram() { | 514 Histogram::~Histogram() { |
595 } | 515 } |
596 | 516 |
597 bool Histogram::PrintEmptyBucket(uint32_t index) const { | 517 bool Histogram::PrintEmptyBucket(uint32_t index) const { |
598 return true; | 518 return true; |
599 } | 519 } |
600 | 520 |
601 // Use the actual bucket widths (like a linear histogram) until the widths get | 521 // Use the actual bucket widths (like a linear histogram) until the widths get |
(...skipping 633 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1235 Sample sample = custom_ranges[i]; | 1155 Sample sample = custom_ranges[i]; |
1236 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) | 1156 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) |
1237 return false; | 1157 return false; |
1238 if (sample != 0) | 1158 if (sample != 0) |
1239 has_valid_range = true; | 1159 has_valid_range = true; |
1240 } | 1160 } |
1241 return has_valid_range; | 1161 return has_valid_range; |
1242 } | 1162 } |
1243 | 1163 |
1244 } // namespace base | 1164 } // namespace base |
OLD | NEW |