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/metrics/sample_vector.h" | 20 #include "base/metrics/sample_vector.h" |
21 #include "base/metrics/statistics_recorder.h" | 21 #include "base/metrics/statistics_recorder.h" |
22 #include "base/pickle.h" | 22 #include "base/pickle.h" |
23 #include "base/strings/string_util.h" | 23 #include "base/strings/string_util.h" |
24 #include "base/strings/stringprintf.h" | 24 #include "base/strings/stringprintf.h" |
25 #include "base/synchronization/lock.h" | 25 #include "base/synchronization/lock.h" |
26 #include "base/values.h" | 26 #include "base/values.h" |
27 | 27 |
28 using std::string; | |
29 using std::vector; | |
30 | |
31 namespace base { | 28 namespace base { |
32 | 29 |
33 namespace { | 30 namespace { |
34 | 31 |
35 bool ReadHistogramArguments(PickleIterator* iter, | 32 bool ReadHistogramArguments(PickleIterator* iter, |
36 string* histogram_name, | 33 std::string* histogram_name, |
37 int* flags, | 34 int* flags, |
38 int* declared_min, | 35 int* declared_min, |
39 int* declared_max, | 36 int* declared_max, |
40 size_t* bucket_count, | 37 size_t* bucket_count, |
41 uint32* range_checksum) { | 38 uint32* range_checksum) { |
42 if (!iter->ReadString(histogram_name) || | 39 if (!iter->ReadString(histogram_name) || |
43 !iter->ReadInt(flags) || | 40 !iter->ReadInt(flags) || |
44 !iter->ReadInt(declared_min) || | 41 !iter->ReadInt(declared_min) || |
45 !iter->ReadInt(declared_max) || | 42 !iter->ReadInt(declared_max) || |
46 !iter->ReadSizeT(bucket_count) || | 43 !iter->ReadSizeT(bucket_count) || |
(...skipping 30 matching lines...) Expand all Loading... |
77 } | 74 } |
78 | 75 |
79 } // namespace | 76 } // namespace |
80 | 77 |
81 typedef HistogramBase::Count Count; | 78 typedef HistogramBase::Count Count; |
82 typedef HistogramBase::Sample Sample; | 79 typedef HistogramBase::Sample Sample; |
83 | 80 |
84 // static | 81 // static |
85 const size_t Histogram::kBucketCount_MAX = 16384u; | 82 const size_t Histogram::kBucketCount_MAX = 16384u; |
86 | 83 |
87 HistogramBase* Histogram::FactoryGet(const string& name, | 84 HistogramBase* Histogram::FactoryGet(const std::string& name, |
88 Sample minimum, | 85 Sample minimum, |
89 Sample maximum, | 86 Sample maximum, |
90 size_t bucket_count, | 87 size_t bucket_count, |
91 int32 flags) { | 88 int32 flags) { |
92 bool valid_arguments = | 89 bool valid_arguments = |
93 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); | 90 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); |
94 DCHECK(valid_arguments); | 91 DCHECK(valid_arguments); |
95 | 92 |
96 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 93 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); |
97 if (!histogram) { | 94 if (!histogram) { |
(...skipping 18 matching lines...) Expand all Loading... |
116 // changed one of them, or simply by bad code within Chrome itself. We | 113 // changed one of them, or simply by bad code within Chrome itself. We |
117 // return NULL here with the expectation that bad code in Chrome will crash | 114 // return NULL here with the expectation that bad code in Chrome will crash |
118 // on dereference, but extension/Pepper APIs will guard against NULL and not | 115 // on dereference, but extension/Pepper APIs will guard against NULL and not |
119 // crash. | 116 // crash. |
120 DLOG(ERROR) << "Histogram " << name << " has bad construction arguments"; | 117 DLOG(ERROR) << "Histogram " << name << " has bad construction arguments"; |
121 return NULL; | 118 return NULL; |
122 } | 119 } |
123 return histogram; | 120 return histogram; |
124 } | 121 } |
125 | 122 |
126 HistogramBase* Histogram::FactoryTimeGet(const string& name, | 123 HistogramBase* Histogram::FactoryTimeGet(const std::string& name, |
127 TimeDelta minimum, | 124 TimeDelta minimum, |
128 TimeDelta maximum, | 125 TimeDelta maximum, |
129 size_t bucket_count, | 126 size_t bucket_count, |
130 int32 flags) { | 127 int32 flags) { |
131 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()), | 128 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()), |
132 static_cast<Sample>(maximum.InMilliseconds()), bucket_count, | 129 static_cast<Sample>(maximum.InMilliseconds()), bucket_count, |
133 flags); | 130 flags); |
134 } | 131 } |
135 | 132 |
136 // Calculate what range of values are held in each bucket. | 133 // Calculate what range of values are held in each bucket. |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
209 | 206 |
210 Sample Histogram::ranges(size_t i) const { | 207 Sample Histogram::ranges(size_t i) const { |
211 return bucket_ranges_->range(i); | 208 return bucket_ranges_->range(i); |
212 } | 209 } |
213 | 210 |
214 size_t Histogram::bucket_count() const { | 211 size_t Histogram::bucket_count() const { |
215 return bucket_ranges_->bucket_count(); | 212 return bucket_ranges_->bucket_count(); |
216 } | 213 } |
217 | 214 |
218 // static | 215 // static |
219 bool Histogram::InspectConstructionArguments(const string& name, | 216 bool Histogram::InspectConstructionArguments(const std::string& name, |
220 Sample* minimum, | 217 Sample* minimum, |
221 Sample* maximum, | 218 Sample* maximum, |
222 size_t* bucket_count) { | 219 size_t* bucket_count) { |
223 // Defensive code for backward compatibility. | 220 // Defensive code for backward compatibility. |
224 if (*minimum < 1) { | 221 if (*minimum < 1) { |
225 DVLOG(1) << "Histogram: " << name << " has bad minimum: " << *minimum; | 222 DVLOG(1) << "Histogram: " << name << " has bad minimum: " << *minimum; |
226 *minimum = 1; | 223 *minimum = 1; |
227 } | 224 } |
228 if (*maximum >= kSampleType_MAX) { | 225 if (*maximum >= kSampleType_MAX) { |
229 DVLOG(1) << "Histogram: " << name << " has bad maximum: " << *maximum; | 226 DVLOG(1) << "Histogram: " << name << " has bad maximum: " << *maximum; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
273 | 270 |
274 void Histogram::AddSamples(const HistogramSamples& samples) { | 271 void Histogram::AddSamples(const HistogramSamples& samples) { |
275 samples_->Add(samples); | 272 samples_->Add(samples); |
276 } | 273 } |
277 | 274 |
278 bool Histogram::AddSamplesFromPickle(PickleIterator* iter) { | 275 bool Histogram::AddSamplesFromPickle(PickleIterator* iter) { |
279 return samples_->AddFromPickle(iter); | 276 return samples_->AddFromPickle(iter); |
280 } | 277 } |
281 | 278 |
282 // The following methods provide a graphical histogram display. | 279 // The following methods provide a graphical histogram display. |
283 void Histogram::WriteHTMLGraph(string* output) const { | 280 void Histogram::WriteHTMLGraph(std::string* output) const { |
284 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc. | 281 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc. |
285 output->append("<PRE>"); | 282 output->append("<PRE>"); |
286 WriteAsciiImpl(true, "<br>", output); | 283 WriteAsciiImpl(true, "<br>", output); |
287 output->append("</PRE>"); | 284 output->append("</PRE>"); |
288 } | 285 } |
289 | 286 |
290 void Histogram::WriteAscii(string* output) const { | 287 void Histogram::WriteAscii(std::string* output) const { |
291 WriteAsciiImpl(true, "\n", output); | 288 WriteAsciiImpl(true, "\n", output); |
292 } | 289 } |
293 | 290 |
294 bool Histogram::SerializeInfoImpl(Pickle* pickle) const { | 291 bool Histogram::SerializeInfoImpl(Pickle* pickle) const { |
295 DCHECK(bucket_ranges()->HasValidChecksum()); | 292 DCHECK(bucket_ranges()->HasValidChecksum()); |
296 return pickle->WriteString(histogram_name()) && | 293 return pickle->WriteString(histogram_name()) && |
297 pickle->WriteInt(flags()) && | 294 pickle->WriteInt(flags()) && |
298 pickle->WriteInt(declared_min()) && | 295 pickle->WriteInt(declared_min()) && |
299 pickle->WriteInt(declared_max()) && | 296 pickle->WriteInt(declared_max()) && |
300 pickle->WriteSizeT(bucket_count()) && | 297 pickle->WriteSizeT(bucket_count()) && |
301 pickle->WriteUInt32(bucket_ranges()->checksum()); | 298 pickle->WriteUInt32(bucket_ranges()->checksum()); |
302 } | 299 } |
303 | 300 |
304 Histogram::Histogram(const string& name, | 301 Histogram::Histogram(const std::string& name, |
305 Sample minimum, | 302 Sample minimum, |
306 Sample maximum, | 303 Sample maximum, |
307 const BucketRanges* ranges) | 304 const BucketRanges* ranges) |
308 : HistogramBase(name), | 305 : HistogramBase(name), |
309 bucket_ranges_(ranges), | 306 bucket_ranges_(ranges), |
310 declared_min_(minimum), | 307 declared_min_(minimum), |
311 declared_max_(maximum) { | 308 declared_max_(maximum) { |
312 if (ranges) | 309 if (ranges) |
313 samples_.reset(new SampleVector(ranges)); | 310 samples_.reset(new SampleVector(ranges)); |
314 } | 311 } |
(...skipping 12 matching lines...) Expand all Loading... |
327 // not have 0-graphical-height buckets. | 324 // not have 0-graphical-height buckets. |
328 double Histogram::GetBucketSize(Count current, size_t i) const { | 325 double Histogram::GetBucketSize(Count current, size_t i) const { |
329 DCHECK_GT(ranges(i + 1), ranges(i)); | 326 DCHECK_GT(ranges(i + 1), ranges(i)); |
330 static const double kTransitionWidth = 5; | 327 static const double kTransitionWidth = 5; |
331 double denominator = ranges(i + 1) - ranges(i); | 328 double denominator = ranges(i + 1) - ranges(i); |
332 if (denominator > kTransitionWidth) | 329 if (denominator > kTransitionWidth) |
333 denominator = kTransitionWidth; // Stop trying to normalize. | 330 denominator = kTransitionWidth; // Stop trying to normalize. |
334 return current/denominator; | 331 return current/denominator; |
335 } | 332 } |
336 | 333 |
337 const string Histogram::GetAsciiBucketRange(size_t i) const { | 334 const std::string Histogram::GetAsciiBucketRange(size_t i) const { |
338 return GetSimpleAsciiBucketRange(ranges(i)); | 335 return GetSimpleAsciiBucketRange(ranges(i)); |
339 } | 336 } |
340 | 337 |
341 //------------------------------------------------------------------------------ | 338 //------------------------------------------------------------------------------ |
342 // Private methods | 339 // Private methods |
343 | 340 |
344 // static | 341 // static |
345 HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) { | 342 HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) { |
346 string histogram_name; | 343 std::string histogram_name; |
347 int flags; | 344 int flags; |
348 int declared_min; | 345 int declared_min; |
349 int declared_max; | 346 int declared_max; |
350 size_t bucket_count; | 347 size_t bucket_count; |
351 uint32 range_checksum; | 348 uint32 range_checksum; |
352 | 349 |
353 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, | 350 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, |
354 &declared_max, &bucket_count, &range_checksum)) { | 351 &declared_max, &bucket_count, &range_checksum)) { |
355 return NULL; | 352 return NULL; |
356 } | 353 } |
357 | 354 |
358 // Find or create the local version of the histogram in this process. | 355 // Find or create the local version of the histogram in this process. |
359 HistogramBase* histogram = Histogram::FactoryGet( | 356 HistogramBase* histogram = Histogram::FactoryGet( |
360 histogram_name, declared_min, declared_max, bucket_count, flags); | 357 histogram_name, declared_min, declared_max, bucket_count, flags); |
361 | 358 |
362 if (!ValidateRangeChecksum(*histogram, range_checksum)) { | 359 if (!ValidateRangeChecksum(*histogram, range_checksum)) { |
363 // The serialized histogram might be corrupted. | 360 // The serialized histogram might be corrupted. |
364 return NULL; | 361 return NULL; |
365 } | 362 } |
366 return histogram; | 363 return histogram; |
367 } | 364 } |
368 | 365 |
369 scoped_ptr<SampleVector> Histogram::SnapshotSampleVector() const { | 366 scoped_ptr<SampleVector> Histogram::SnapshotSampleVector() const { |
370 scoped_ptr<SampleVector> samples(new SampleVector(bucket_ranges())); | 367 scoped_ptr<SampleVector> samples(new SampleVector(bucket_ranges())); |
371 samples->Add(*samples_); | 368 samples->Add(*samples_); |
372 return samples.Pass(); | 369 return samples.Pass(); |
373 } | 370 } |
374 | 371 |
375 void Histogram::WriteAsciiImpl(bool graph_it, | 372 void Histogram::WriteAsciiImpl(bool graph_it, |
376 const string& newline, | 373 const std::string& newline, |
377 string* output) const { | 374 std::string* output) const { |
378 // Get local (stack) copies of all effectively volatile class data so that we | 375 // Get local (stack) copies of all effectively volatile class data so that we |
379 // are consistent across our output activities. | 376 // are consistent across our output activities. |
380 scoped_ptr<SampleVector> snapshot = SnapshotSampleVector(); | 377 scoped_ptr<SampleVector> snapshot = SnapshotSampleVector(); |
381 Count sample_count = snapshot->TotalCount(); | 378 Count sample_count = snapshot->TotalCount(); |
382 | 379 |
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; |
(...skipping 20 matching lines...) Expand all Loading... |
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 < bucket_count(); ++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 std::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 < bucket_count() - 1 && |
423 0 == snapshot->GetCountAtIndex(i + 1)) { | 420 0 == snapshot->GetCountAtIndex(i + 1)) { |
424 while (i < bucket_count() - 1 && | 421 while (i < bucket_count() - 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("... "); |
(...skipping 15 matching lines...) Expand all Loading... |
444 for (size_t i = 0; i < bucket_count() ; ++i) { | 441 for (size_t i = 0; i < bucket_count() ; ++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 std::string* output) const { |
455 StringAppendF(output, | 452 StringAppendF(output, |
456 "Histogram: %s recorded %d samples", | 453 "Histogram: %s recorded %d samples", |
457 histogram_name().c_str(), | 454 histogram_name().c_str(), |
458 sample_count); | 455 sample_count); |
459 if (0 == sample_count) { | 456 if (0 == sample_count) { |
460 DCHECK_EQ(samples.sum(), 0); | 457 DCHECK_EQ(samples.sum(), 0); |
461 } else { | 458 } else { |
462 double average = static_cast<float>(samples.sum()) / sample_count; | 459 double average = static_cast<float>(samples.sum()) / sample_count; |
463 | 460 |
464 StringAppendF(output, ", average = %.1f", average); | 461 StringAppendF(output, ", average = %.1f", average); |
465 } | 462 } |
466 if (flags() & ~kHexRangePrintingFlag) | 463 if (flags() & ~kHexRangePrintingFlag) |
467 StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag); | 464 StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag); |
468 } | 465 } |
469 | 466 |
470 void Histogram::WriteAsciiBucketContext(const int64 past, | 467 void Histogram::WriteAsciiBucketContext(const int64 past, |
471 const Count current, | 468 const Count current, |
472 const int64 remaining, | 469 const int64 remaining, |
473 const size_t i, | 470 const size_t i, |
474 string* output) const { | 471 std::string* output) const { |
475 double scaled_sum = (past + current + remaining) / 100.0; | 472 double scaled_sum = (past + current + remaining) / 100.0; |
476 WriteAsciiBucketValue(current, scaled_sum, output); | 473 WriteAsciiBucketValue(current, scaled_sum, output); |
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())); |
(...skipping 23 matching lines...) Expand all Loading... |
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 |
513 // buckets. | 510 // buckets. |
514 //------------------------------------------------------------------------------ | 511 //------------------------------------------------------------------------------ |
515 | 512 |
516 LinearHistogram::~LinearHistogram() {} | 513 LinearHistogram::~LinearHistogram() {} |
517 | 514 |
518 HistogramBase* LinearHistogram::FactoryGet(const string& name, | 515 HistogramBase* LinearHistogram::FactoryGet(const std::string& name, |
519 Sample minimum, | 516 Sample minimum, |
520 Sample maximum, | 517 Sample maximum, |
521 size_t bucket_count, | 518 size_t bucket_count, |
522 int32 flags) { | 519 int32 flags) { |
523 return FactoryGetWithRangeDescription( | 520 return FactoryGetWithRangeDescription( |
524 name, minimum, maximum, bucket_count, flags, NULL); | 521 name, minimum, maximum, bucket_count, flags, NULL); |
525 } | 522 } |
526 | 523 |
527 HistogramBase* LinearHistogram::FactoryTimeGet(const string& name, | 524 HistogramBase* LinearHistogram::FactoryTimeGet(const std::string& name, |
528 TimeDelta minimum, | 525 TimeDelta minimum, |
529 TimeDelta maximum, | 526 TimeDelta maximum, |
530 size_t bucket_count, | 527 size_t bucket_count, |
531 int32 flags) { | 528 int32 flags) { |
532 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()), | 529 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()), |
533 static_cast<Sample>(maximum.InMilliseconds()), bucket_count, | 530 static_cast<Sample>(maximum.InMilliseconds()), bucket_count, |
534 flags); | 531 flags); |
535 } | 532 } |
536 | 533 |
537 HistogramBase* LinearHistogram::FactoryGetWithRangeDescription( | 534 HistogramBase* LinearHistogram::FactoryGetWithRangeDescription( |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
580 DLOG(ERROR) << "Histogram " << name << " has bad construction arguments"; | 577 DLOG(ERROR) << "Histogram " << name << " has bad construction arguments"; |
581 return NULL; | 578 return NULL; |
582 } | 579 } |
583 return histogram; | 580 return histogram; |
584 } | 581 } |
585 | 582 |
586 HistogramType LinearHistogram::GetHistogramType() const { | 583 HistogramType LinearHistogram::GetHistogramType() const { |
587 return LINEAR_HISTOGRAM; | 584 return LINEAR_HISTOGRAM; |
588 } | 585 } |
589 | 586 |
590 LinearHistogram::LinearHistogram(const string& name, | 587 LinearHistogram::LinearHistogram(const std::string& name, |
591 Sample minimum, | 588 Sample minimum, |
592 Sample maximum, | 589 Sample maximum, |
593 const BucketRanges* ranges) | 590 const BucketRanges* ranges) |
594 : Histogram(name, minimum, maximum, ranges) { | 591 : Histogram(name, minimum, maximum, ranges) { |
595 } | 592 } |
596 | 593 |
597 double LinearHistogram::GetBucketSize(Count current, size_t i) const { | 594 double LinearHistogram::GetBucketSize(Count current, size_t i) const { |
598 DCHECK_GT(ranges(i + 1), ranges(i)); | 595 DCHECK_GT(ranges(i + 1), ranges(i)); |
599 // Adjacent buckets with different widths would have "surprisingly" many (few) | 596 // Adjacent buckets with different widths would have "surprisingly" many (few) |
600 // samples in a histogram if we didn't normalize this way. | 597 // samples in a histogram if we didn't normalize this way. |
601 double denominator = ranges(i + 1) - ranges(i); | 598 double denominator = ranges(i + 1) - ranges(i); |
602 return current/denominator; | 599 return current/denominator; |
603 } | 600 } |
604 | 601 |
605 const string LinearHistogram::GetAsciiBucketRange(size_t i) const { | 602 const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const { |
606 int range = ranges(i); | 603 int range = ranges(i); |
607 BucketDescriptionMap::const_iterator it = bucket_description_.find(range); | 604 BucketDescriptionMap::const_iterator it = bucket_description_.find(range); |
608 if (it == bucket_description_.end()) | 605 if (it == bucket_description_.end()) |
609 return Histogram::GetAsciiBucketRange(i); | 606 return Histogram::GetAsciiBucketRange(i); |
610 return it->second; | 607 return it->second; |
611 } | 608 } |
612 | 609 |
613 bool LinearHistogram::PrintEmptyBucket(size_t index) const { | 610 bool LinearHistogram::PrintEmptyBucket(size_t index) const { |
614 return bucket_description_.find(ranges(index)) == bucket_description_.end(); | 611 return bucket_description_.find(ranges(index)) == bucket_description_.end(); |
615 } | 612 } |
616 | 613 |
617 // static | 614 // static |
618 void LinearHistogram::InitializeBucketRanges(Sample minimum, | 615 void LinearHistogram::InitializeBucketRanges(Sample minimum, |
619 Sample maximum, | 616 Sample maximum, |
620 BucketRanges* ranges) { | 617 BucketRanges* ranges) { |
621 double min = minimum; | 618 double min = minimum; |
622 double max = maximum; | 619 double max = maximum; |
623 size_t bucket_count = ranges->bucket_count(); | 620 size_t bucket_count = ranges->bucket_count(); |
624 for (size_t i = 1; i < bucket_count; ++i) { | 621 for (size_t i = 1; i < bucket_count; ++i) { |
625 double linear_range = | 622 double linear_range = |
626 (min * (bucket_count - 1 - i) + max * (i - 1)) / (bucket_count - 2); | 623 (min * (bucket_count - 1 - i) + max * (i - 1)) / (bucket_count - 2); |
627 ranges->set_range(i, static_cast<Sample>(linear_range + 0.5)); | 624 ranges->set_range(i, static_cast<Sample>(linear_range + 0.5)); |
628 } | 625 } |
629 ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX); | 626 ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX); |
630 ranges->ResetChecksum(); | 627 ranges->ResetChecksum(); |
631 } | 628 } |
632 | 629 |
633 // static | 630 // static |
634 HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) { | 631 HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) { |
635 string histogram_name; | 632 std::string histogram_name; |
636 int flags; | 633 int flags; |
637 int declared_min; | 634 int declared_min; |
638 int declared_max; | 635 int declared_max; |
639 size_t bucket_count; | 636 size_t bucket_count; |
640 uint32 range_checksum; | 637 uint32 range_checksum; |
641 | 638 |
642 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, | 639 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, |
643 &declared_max, &bucket_count, &range_checksum)) { | 640 &declared_max, &bucket_count, &range_checksum)) { |
644 return NULL; | 641 return NULL; |
645 } | 642 } |
646 | 643 |
647 HistogramBase* histogram = LinearHistogram::FactoryGet( | 644 HistogramBase* histogram = LinearHistogram::FactoryGet( |
648 histogram_name, declared_min, declared_max, bucket_count, flags); | 645 histogram_name, declared_min, declared_max, bucket_count, flags); |
649 if (!ValidateRangeChecksum(*histogram, range_checksum)) { | 646 if (!ValidateRangeChecksum(*histogram, range_checksum)) { |
650 // The serialized histogram might be corrupted. | 647 // The serialized histogram might be corrupted. |
651 return NULL; | 648 return NULL; |
652 } | 649 } |
653 return histogram; | 650 return histogram; |
654 } | 651 } |
655 | 652 |
656 //------------------------------------------------------------------------------ | 653 //------------------------------------------------------------------------------ |
657 // This section provides implementation for BooleanHistogram. | 654 // This section provides implementation for BooleanHistogram. |
658 //------------------------------------------------------------------------------ | 655 //------------------------------------------------------------------------------ |
659 | 656 |
660 HistogramBase* BooleanHistogram::FactoryGet(const string& name, int32 flags) { | 657 HistogramBase* BooleanHistogram::FactoryGet(const std::string& name, |
| 658 int32 flags) { |
661 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 659 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); |
662 if (!histogram) { | 660 if (!histogram) { |
663 // To avoid racy destruction at shutdown, the following will be leaked. | 661 // To avoid racy destruction at shutdown, the following will be leaked. |
664 BucketRanges* ranges = new BucketRanges(4); | 662 BucketRanges* ranges = new BucketRanges(4); |
665 LinearHistogram::InitializeBucketRanges(1, 2, ranges); | 663 LinearHistogram::InitializeBucketRanges(1, 2, ranges); |
666 const BucketRanges* registered_ranges = | 664 const BucketRanges* registered_ranges = |
667 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | 665 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); |
668 | 666 |
669 BooleanHistogram* tentative_histogram = | 667 BooleanHistogram* tentative_histogram = |
670 new BooleanHistogram(name, registered_ranges); | 668 new BooleanHistogram(name, registered_ranges); |
671 | 669 |
672 tentative_histogram->SetFlags(flags); | 670 tentative_histogram->SetFlags(flags); |
673 histogram = | 671 histogram = |
674 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | 672 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
675 } | 673 } |
676 | 674 |
677 DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType()); | 675 DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType()); |
678 return histogram; | 676 return histogram; |
679 } | 677 } |
680 | 678 |
681 HistogramType BooleanHistogram::GetHistogramType() const { | 679 HistogramType BooleanHistogram::GetHistogramType() const { |
682 return BOOLEAN_HISTOGRAM; | 680 return BOOLEAN_HISTOGRAM; |
683 } | 681 } |
684 | 682 |
685 BooleanHistogram::BooleanHistogram(const string& name, | 683 BooleanHistogram::BooleanHistogram(const std::string& name, |
686 const BucketRanges* ranges) | 684 const BucketRanges* ranges) |
687 : LinearHistogram(name, 1, 2, ranges) {} | 685 : LinearHistogram(name, 1, 2, ranges) {} |
688 | 686 |
689 HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) { | 687 HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) { |
690 string histogram_name; | 688 std::string histogram_name; |
691 int flags; | 689 int flags; |
692 int declared_min; | 690 int declared_min; |
693 int declared_max; | 691 int declared_max; |
694 size_t bucket_count; | 692 size_t bucket_count; |
695 uint32 range_checksum; | 693 uint32 range_checksum; |
696 | 694 |
697 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, | 695 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, |
698 &declared_max, &bucket_count, &range_checksum)) { | 696 &declared_max, &bucket_count, &range_checksum)) { |
699 return NULL; | 697 return NULL; |
700 } | 698 } |
701 | 699 |
702 HistogramBase* histogram = BooleanHistogram::FactoryGet( | 700 HistogramBase* histogram = BooleanHistogram::FactoryGet( |
703 histogram_name, flags); | 701 histogram_name, flags); |
704 if (!ValidateRangeChecksum(*histogram, range_checksum)) { | 702 if (!ValidateRangeChecksum(*histogram, range_checksum)) { |
705 // The serialized histogram might be corrupted. | 703 // The serialized histogram might be corrupted. |
706 return NULL; | 704 return NULL; |
707 } | 705 } |
708 return histogram; | 706 return histogram; |
709 } | 707 } |
710 | 708 |
711 //------------------------------------------------------------------------------ | 709 //------------------------------------------------------------------------------ |
712 // CustomHistogram: | 710 // CustomHistogram: |
713 //------------------------------------------------------------------------------ | 711 //------------------------------------------------------------------------------ |
714 | 712 |
715 HistogramBase* CustomHistogram::FactoryGet(const string& name, | 713 HistogramBase* CustomHistogram::FactoryGet( |
716 const vector<Sample>& custom_ranges, | 714 const std::string& name, |
717 int32 flags) { | 715 const std::vector<Sample>& custom_ranges, |
| 716 int32 flags) { |
718 CHECK(ValidateCustomRanges(custom_ranges)); | 717 CHECK(ValidateCustomRanges(custom_ranges)); |
719 | 718 |
720 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); | 719 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); |
721 if (!histogram) { | 720 if (!histogram) { |
722 BucketRanges* ranges = CreateBucketRangesFromCustomRanges(custom_ranges); | 721 BucketRanges* ranges = CreateBucketRangesFromCustomRanges(custom_ranges); |
723 const BucketRanges* registered_ranges = | 722 const BucketRanges* registered_ranges = |
724 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | 723 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); |
725 | 724 |
726 // To avoid racy destruction at shutdown, the following will be leaked. | 725 // To avoid racy destruction at shutdown, the following will be leaked. |
727 CustomHistogram* tentative_histogram = | 726 CustomHistogram* tentative_histogram = |
728 new CustomHistogram(name, registered_ranges); | 727 new CustomHistogram(name, registered_ranges); |
729 | 728 |
730 tentative_histogram->SetFlags(flags); | 729 tentative_histogram->SetFlags(flags); |
731 | 730 |
732 histogram = | 731 histogram = |
733 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); | 732 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
734 } | 733 } |
735 | 734 |
736 DCHECK_EQ(histogram->GetHistogramType(), CUSTOM_HISTOGRAM); | 735 DCHECK_EQ(histogram->GetHistogramType(), CUSTOM_HISTOGRAM); |
737 return histogram; | 736 return histogram; |
738 } | 737 } |
739 | 738 |
740 HistogramType CustomHistogram::GetHistogramType() const { | 739 HistogramType CustomHistogram::GetHistogramType() const { |
741 return CUSTOM_HISTOGRAM; | 740 return CUSTOM_HISTOGRAM; |
742 } | 741 } |
743 | 742 |
744 // static | 743 // static |
745 vector<Sample> CustomHistogram::ArrayToCustomRanges( | 744 std::vector<Sample> CustomHistogram::ArrayToCustomRanges( |
746 const Sample* values, size_t num_values) { | 745 const Sample* values, size_t num_values) { |
747 vector<Sample> all_values; | 746 std::vector<Sample> all_values; |
748 for (size_t i = 0; i < num_values; ++i) { | 747 for (size_t i = 0; i < num_values; ++i) { |
749 Sample value = values[i]; | 748 Sample value = values[i]; |
750 all_values.push_back(value); | 749 all_values.push_back(value); |
751 | 750 |
752 // Ensure that a guard bucket is added. If we end up with duplicate | 751 // Ensure that a guard bucket is added. If we end up with duplicate |
753 // values, FactoryGet will take care of removing them. | 752 // values, FactoryGet will take care of removing them. |
754 all_values.push_back(value + 1); | 753 all_values.push_back(value + 1); |
755 } | 754 } |
756 return all_values; | 755 return all_values; |
757 } | 756 } |
758 | 757 |
759 CustomHistogram::CustomHistogram(const string& name, | 758 CustomHistogram::CustomHistogram(const std::string& name, |
760 const BucketRanges* ranges) | 759 const BucketRanges* ranges) |
761 : Histogram(name, | 760 : Histogram(name, |
762 ranges->range(1), | 761 ranges->range(1), |
763 ranges->range(ranges->bucket_count() - 1), | 762 ranges->range(ranges->bucket_count() - 1), |
764 ranges) {} | 763 ranges) {} |
765 | 764 |
766 bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const { | 765 bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const { |
767 if (!Histogram::SerializeInfoImpl(pickle)) | 766 if (!Histogram::SerializeInfoImpl(pickle)) |
768 return false; | 767 return false; |
769 | 768 |
770 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't | 769 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't |
771 // write them. | 770 // write them. |
772 for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) { | 771 for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) { |
773 if (!pickle->WriteInt(bucket_ranges()->range(i))) | 772 if (!pickle->WriteInt(bucket_ranges()->range(i))) |
774 return false; | 773 return false; |
775 } | 774 } |
776 return true; | 775 return true; |
777 } | 776 } |
778 | 777 |
779 double CustomHistogram::GetBucketSize(Count current, size_t i) const { | 778 double CustomHistogram::GetBucketSize(Count current, size_t i) const { |
780 return 1; | 779 return 1; |
781 } | 780 } |
782 | 781 |
783 // static | 782 // static |
784 HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) { | 783 HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) { |
785 string histogram_name; | 784 std::string histogram_name; |
786 int flags; | 785 int flags; |
787 int declared_min; | 786 int declared_min; |
788 int declared_max; | 787 int declared_max; |
789 size_t bucket_count; | 788 size_t bucket_count; |
790 uint32 range_checksum; | 789 uint32 range_checksum; |
791 | 790 |
792 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, | 791 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min, |
793 &declared_max, &bucket_count, &range_checksum)) { | 792 &declared_max, &bucket_count, &range_checksum)) { |
794 return NULL; | 793 return NULL; |
795 } | 794 } |
796 | 795 |
797 // First and last ranges are not serialized. | 796 // First and last ranges are not serialized. |
798 vector<Sample> sample_ranges(bucket_count - 1); | 797 std::vector<Sample> sample_ranges(bucket_count - 1); |
799 | 798 |
800 for (size_t i = 0; i < sample_ranges.size(); ++i) { | 799 for (size_t i = 0; i < sample_ranges.size(); ++i) { |
801 if (!iter->ReadInt(&sample_ranges[i])) | 800 if (!iter->ReadInt(&sample_ranges[i])) |
802 return NULL; | 801 return NULL; |
803 } | 802 } |
804 | 803 |
805 HistogramBase* histogram = CustomHistogram::FactoryGet( | 804 HistogramBase* histogram = CustomHistogram::FactoryGet( |
806 histogram_name, sample_ranges, flags); | 805 histogram_name, sample_ranges, flags); |
807 if (!ValidateRangeChecksum(*histogram, range_checksum)) { | 806 if (!ValidateRangeChecksum(*histogram, range_checksum)) { |
808 // The serialized histogram might be corrupted. | 807 // The serialized histogram might be corrupted. |
809 return NULL; | 808 return NULL; |
810 } | 809 } |
811 return histogram; | 810 return histogram; |
812 } | 811 } |
813 | 812 |
814 // static | 813 // static |
815 bool CustomHistogram::ValidateCustomRanges( | 814 bool CustomHistogram::ValidateCustomRanges( |
816 const vector<Sample>& custom_ranges) { | 815 const std::vector<Sample>& custom_ranges) { |
817 bool has_valid_range = false; | 816 bool has_valid_range = false; |
818 for (size_t i = 0; i < custom_ranges.size(); i++) { | 817 for (size_t i = 0; i < custom_ranges.size(); i++) { |
819 Sample sample = custom_ranges[i]; | 818 Sample sample = custom_ranges[i]; |
820 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) | 819 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) |
821 return false; | 820 return false; |
822 if (sample != 0) | 821 if (sample != 0) |
823 has_valid_range = true; | 822 has_valid_range = true; |
824 } | 823 } |
825 return has_valid_range; | 824 return has_valid_range; |
826 } | 825 } |
827 | 826 |
828 // static | 827 // static |
829 BucketRanges* CustomHistogram::CreateBucketRangesFromCustomRanges( | 828 BucketRanges* CustomHistogram::CreateBucketRangesFromCustomRanges( |
830 const vector<Sample>& custom_ranges) { | 829 const std::vector<Sample>& custom_ranges) { |
831 // Remove the duplicates in the custom ranges array. | 830 // Remove the duplicates in the custom ranges array. |
832 vector<int> ranges = custom_ranges; | 831 std::vector<int> ranges = custom_ranges; |
833 ranges.push_back(0); // Ensure we have a zero value. | 832 ranges.push_back(0); // Ensure we have a zero value. |
834 ranges.push_back(HistogramBase::kSampleType_MAX); | 833 ranges.push_back(HistogramBase::kSampleType_MAX); |
835 std::sort(ranges.begin(), ranges.end()); | 834 std::sort(ranges.begin(), ranges.end()); |
836 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end()); | 835 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end()); |
837 | 836 |
838 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); | 837 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); |
839 for (size_t i = 0; i < ranges.size(); i++) { | 838 for (size_t i = 0; i < ranges.size(); i++) { |
840 bucket_ranges->set_range(i, ranges[i]); | 839 bucket_ranges->set_range(i, ranges[i]); |
841 } | 840 } |
842 bucket_ranges->ResetChecksum(); | 841 bucket_ranges->ResetChecksum(); |
843 return bucket_ranges; | 842 return bucket_ranges; |
844 } | 843 } |
845 | 844 |
846 } // namespace base | 845 } // namespace base |
OLD | NEW |