Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(171)

Side by Side Diff: base/metrics/histogram.cc

Issue 10829466: SampleSet -> HistogramSamples (will be reused by SparseHistogram) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 13 matching lines...) Expand all
24 #include "base/synchronization/lock.h" 24 #include "base/synchronization/lock.h"
25 25
26 using std::string; 26 using std::string;
27 using std::vector; 27 using std::vector;
28 28
29 namespace base { 29 namespace base {
30 30
31 typedef HistogramBase::Count Count; 31 typedef HistogramBase::Count Count;
32 typedef HistogramBase::Sample Sample; 32 typedef HistogramBase::Sample Sample;
33 33
34 BucketHistogramSamples::BucketHistogramSamples(
35 const BucketRanges* bucket_ranges)
36 : counts_(bucket_ranges->size() - 1),
37 bucket_ranges_(bucket_ranges) {
38 CHECK_GE(bucket_ranges_->size(), 2u);
Ilya Sherman 2012/08/23 07:50:54 nit: Does this need to be a CHECK, or would a DCHE
kaiwang 2012/08/24 04:17:58 This check has litter performance impact, I don't
Ilya Sherman 2012/08/29 08:48:16 That is an argument for only ever using CHECKs, an
Ilya Sherman 2012/08/29 23:46:00 Brett or John, could one of you chime in on this q
39 }
40 BucketHistogramSamples::~BucketHistogramSamples() {}
41
42 void BucketHistogramSamples::Accumulate(Sample value, Count count) {
43 size_t i = BucketIndex(value, bucket_ranges_);
Ilya Sherman 2012/08/23 07:50:54 nit: i -> bucket (prefer to use descriptive names)
kaiwang 2012/08/24 04:17:58 i -> bucket_index
44 counts_[i] += count;
45 sum_ += count * value;
Ilya Sherman 2012/08/23 07:50:54 Any need to check for overflow?
kaiwang 2012/08/24 04:17:58 sum is int64 and count/value are both int32. Also,
Ilya Sherman 2012/08/29 08:48:16 Why isn't clamping to the max value for int64 the
46 redundant_count_ += count;
47 }
48
49 Count BucketHistogramSamples::GetCount(Sample value) const {
50 size_t i = BucketIndex(value, bucket_ranges_);
51 return counts_[i];
52 }
53
54 Count BucketHistogramSamples::TotalCount() const {
55 Count count = 0;
56 for (size_t i = 0; i < counts_.size(); i++) {
57 count += counts_[i];
58 }
59 return count;
60 }
61
62 Count BucketHistogramSamples::GetCountFromBucketIndex(
63 size_t bucket_index) const {
64 return counts_[bucket_index];
65 }
66
67 scoped_ptr<SampleCountIterator> BucketHistogramSamples::Iterator() const {
68 return scoped_ptr<SampleCountIterator>(
69 new BucketHistogramSamplesIterator(&counts_, bucket_ranges_));
70 }
71
72 // Use simple binary search. This is very general, but there are better
73 // approaches if we knew that the buckets were linearly distributed.
74 //
75 // static
76 size_t BucketHistogramSamples::BucketIndex(Sample value,
77 const BucketRanges* bucket_ranges) {
78 size_t bucket_count = bucket_ranges->size() - 1;
79 CHECK_GE(bucket_count, 1u);
80 CHECK_GE(value, bucket_ranges->range(0));
81 CHECK_LT(value, bucket_ranges->range(bucket_count));
82
83 size_t under = 0;
84 size_t over = bucket_count;
85 size_t mid;
86 do {
87 mid = under + (over - under)/2;
88 if (mid == under)
89 break;
90 if (bucket_ranges->range(mid) <= value)
91 under = mid;
92 else
93 over = mid;
94 } while (true);
Ilya Sherman 2012/08/23 07:50:54 Can we use a standard binary search implementation
kaiwang 2012/08/24 04:17:58 This code is copied from below. I think for refact
95 return mid;
96 }
97
98 bool BucketHistogramSamples::AddSubtractHelper(SampleCountIterator* iter,
99 bool is_add) {
100 HistogramBase::Sample min;
101 HistogramBase::Sample max;
102 HistogramBase::Count count;
103
104 size_t index = 0;
105 while (index < counts_.size() && !iter->Done()) {
Ilya Sherman 2012/08/23 07:50:54 Please add a comment describing what this double-i
kaiwang 2012/08/24 04:17:58 Done.
106 iter->Get(&min, &max, &count);
107 if (min == bucket_ranges_->range(index) &&
108 max == bucket_ranges_->range(index + 1)) {
109 // Bucket match!
110 counts_[index] += is_add ? count : - count;
Ilya Sherman 2012/08/23 07:50:54 nit: The unary minus operator should not be follow
kaiwang 2012/08/24 04:17:58 Done.
111 iter->Next();
112 } else if (min > bucket_ranges_->range(index)) {
113 index++;
114 } else {
115 return false;
116 }
117 }
118
119 return iter->Done();
120 }
121
122 BucketHistogramSamplesIterator::BucketHistogramSamplesIterator(
123 const vector<Count>* counts,
124 const BucketRanges* bucket_ranges)
125 : counts_(counts),
126 bucket_ranges_(bucket_ranges),
127 index_(-1),
128 is_done_(false) {
129 CHECK_GT(bucket_ranges_->size(), counts_->size());
130 ForwardIndex();
131 }
132
133 bool BucketHistogramSamplesIterator::Done() {
134 return is_done_;
135 }
136
137 void BucketHistogramSamplesIterator::Next() {
138 ForwardIndex();
139 }
140
141 void BucketHistogramSamplesIterator::Get(HistogramBase::Sample* min,
142 HistogramBase::Sample* max,
143 HistogramBase::Count* count) {
144 CHECK(!Done());
145 if (min != NULL)
Ilya Sherman 2012/08/23 07:50:54 nit: I saw nothing in the method description that
kaiwang 2012/08/24 04:17:58 added to interface comment
146 *min = bucket_ranges_->range(index_);
147 if (max != NULL)
148 *max = bucket_ranges_->range(index_ + 1);
149 if (count != NULL)
150 *count = (*counts_)[index_];
151 }
152
153 void BucketHistogramSamplesIterator::ForwardIndex() {
154 CHECK(!Done());
155
156 while (index_ < static_cast<int>(counts_->size()) - 1) {
157 index_++;
158 if ((*counts_)[index_] != 0)
159 return;
160 }
161 is_done_ = true;
162 }
163
34 // static 164 // static
35 const size_t Histogram::kBucketCount_MAX = 16384u; 165 const size_t Histogram::kBucketCount_MAX = 16384u;
36 166
37 Histogram::SampleSet::SampleSet(size_t size) 167 Histogram::SampleSet::SampleSet(size_t size)
38 : counts_(size, 0), 168 : counts_(size, 0),
39 sum_(0), 169 sum_(0),
40 redundant_count_(0) {} 170 redundant_count_(0) {}
41 171
42 Histogram::SampleSet::SampleSet() 172 Histogram::SampleSet::SampleSet()
43 : counts_(), 173 : counts_(),
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after
238 if (next > current) 368 if (next > current)
239 current = next; 369 current = next;
240 else 370 else
241 ++current; // Just do a narrow bucket, and keep trying. 371 ++current; // Just do a narrow bucket, and keep trying.
242 ranges->set_range(bucket_index, current); 372 ranges->set_range(bucket_index, current);
243 } 373 }
244 ranges->set_range(ranges->size() - 1, HistogramBase::kSampleType_MAX); 374 ranges->set_range(ranges->size() - 1, HistogramBase::kSampleType_MAX);
245 ranges->ResetChecksum(); 375 ranges->ResetChecksum();
246 } 376 }
247 377
248 // static
249 void Histogram::Add(int value) { 378 void Histogram::Add(int value) {
250 if (value > kSampleType_MAX - 1) 379 if (value > ranges(bucket_count_) - 1)
jar (doing other things) 2012/08/30 22:54:38 You appear to have changed a constant comparisons
kaiwang 2012/09/07 01:14:11 Done.
251 value = kSampleType_MAX - 1; 380 value = ranges(bucket_count_) - 1;
252 if (value < 0) 381 if (value < ranges(0))
253 value = 0; 382 value = ranges(0);
254 size_t index = BucketIndex(value); 383 samples_->Accumulate(value, 1);
255 DCHECK_GE(value, ranges(index));
256 DCHECK_LT(value, ranges(index + 1));
257 Accumulate(value, 1, index);
258 } 384 }
259 385
260 void Histogram::AddBoolean(bool value) { 386 void Histogram::AddBoolean(bool value) {
261 DCHECK(false); 387 DCHECK(false);
262 } 388 }
263 389
264 void Histogram::AddSampleSet(const SampleSet& sample) { 390 void Histogram::AddSamples(const HistogramSamples& samples) {
265 sample_.Add(sample); 391 samples_->Add(samples);
392 }
393
394 bool Histogram::AddSamples(PickleIterator* iter) {
395 return samples_->Add(iter);
266 } 396 }
267 397
268 void Histogram::SetRangeDescriptions(const DescriptionPair descriptions[]) { 398 void Histogram::SetRangeDescriptions(const DescriptionPair descriptions[]) {
269 DCHECK(false); 399 DCHECK(false);
270 } 400 }
271 401
272 // The following methods provide a graphical histogram display. 402 // The following methods provide a graphical histogram display.
273 void Histogram::WriteHTMLGraph(string* output) const { 403 void Histogram::WriteHTMLGraph(string* output) const {
274 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc. 404 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
275 output->append("<PRE>"); 405 output->append("<PRE>");
276 WriteAsciiImpl(true, "<br>", output); 406 WriteAsciiImpl(true, "<br>", output);
277 output->append("</PRE>"); 407 output->append("</PRE>");
278 } 408 }
279 409
280 void Histogram::WriteAscii(string* output) const { 410 void Histogram::WriteAscii(string* output) const {
281 WriteAsciiImpl(true, "\n", output); 411 WriteAsciiImpl(true, "\n", output);
282 } 412 }
283 413
284 // static 414 // static
285 string Histogram::SerializeHistogramInfo(const Histogram& histogram, 415 string Histogram::SerializeHistogramInfo(const Histogram& histogram,
286 const SampleSet& snapshot) { 416 const HistogramSamples& snapshot) {
287 DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type()); 417 DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type());
288 DCHECK(histogram.bucket_ranges()->HasValidChecksum()); 418 DCHECK(histogram.bucket_ranges()->HasValidChecksum());
289 419
290 Pickle pickle; 420 Pickle pickle;
291 pickle.WriteString(histogram.histogram_name()); 421 pickle.WriteString(histogram.histogram_name());
292 pickle.WriteInt(histogram.declared_min()); 422 pickle.WriteInt(histogram.declared_min());
293 pickle.WriteInt(histogram.declared_max()); 423 pickle.WriteInt(histogram.declared_max());
294 pickle.WriteUInt64(histogram.bucket_count()); 424 pickle.WriteUInt64(histogram.bucket_count());
295 pickle.WriteUInt32(histogram.bucket_ranges()->checksum()); 425 pickle.WriteUInt32(histogram.bucket_ranges()->checksum());
296 pickle.WriteInt(histogram.histogram_type()); 426 pickle.WriteInt(histogram.histogram_type());
297 pickle.WriteInt(histogram.flags()); 427 pickle.WriteInt(histogram.flags());
298 428
429 histogram.SerializeRanges(&pickle);
Ilya Sherman 2012/08/23 07:50:54 Why did you move this line?
kaiwang 2012/08/24 04:17:58 this is part of "histogram info", while the code b
430
299 snapshot.Serialize(&pickle); 431 snapshot.Serialize(&pickle);
300 432
301 histogram.SerializeRanges(&pickle);
302
303 return string(static_cast<const char*>(pickle.data()), pickle.size()); 433 return string(static_cast<const char*>(pickle.data()), pickle.size());
304 } 434 }
305 435
306 // static 436 // static
307 bool Histogram::DeserializeHistogramInfo(const string& histogram_info) { 437 bool Histogram::DeserializeHistogramInfo(const string& histogram_info) {
308 if (histogram_info.empty()) { 438 if (histogram_info.empty()) {
309 return false; 439 return false;
310 } 440 }
311 441
312 Pickle pickle(histogram_info.data(), 442 Pickle pickle(histogram_info.data(),
313 static_cast<int>(histogram_info.size())); 443 static_cast<int>(histogram_info.size()));
314 string histogram_name; 444 string histogram_name;
315 int declared_min; 445 int declared_min;
316 int declared_max; 446 int declared_max;
317 uint64 bucket_count; 447 uint64 bucket_count;
318 uint32 range_checksum; 448 uint32 range_checksum;
319 int histogram_type; 449 int histogram_type;
320 int pickle_flags; 450 int pickle_flags;
321 SampleSet sample;
322 451
323 PickleIterator iter(pickle); 452 PickleIterator iter(pickle);
324 if (!iter.ReadString(&histogram_name) || 453 if (!iter.ReadString(&histogram_name) ||
325 !iter.ReadInt(&declared_min) || 454 !iter.ReadInt(&declared_min) ||
326 !iter.ReadInt(&declared_max) || 455 !iter.ReadInt(&declared_max) ||
327 !iter.ReadUInt64(&bucket_count) || 456 !iter.ReadUInt64(&bucket_count) ||
328 !iter.ReadUInt32(&range_checksum) || 457 !iter.ReadUInt32(&range_checksum) ||
329 !iter.ReadInt(&histogram_type) || 458 !iter.ReadInt(&histogram_type) ||
330 !iter.ReadInt(&pickle_flags) || 459 !iter.ReadInt(&pickle_flags)) {
331 !sample.Histogram::SampleSet::Deserialize(&iter)) {
jar (doing other things) 2012/08/30 22:54:38 How are these samples recovered? I don't see the
kaiwang 2012/09/07 01:14:11 See line 387, it adds all samples from a PickleIte
332 DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name; 460 DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
333 return false; 461 return false;
334 } 462 }
335 463
336 DCHECK(pickle_flags & kIPCSerializationSourceFlag); 464 DCHECK(pickle_flags & kIPCSerializationSourceFlag);
337 // Since these fields may have come from an untrusted renderer, do additional 465 // Since these fields may have come from an untrusted renderer, do additional
338 // checks above and beyond those in Histogram::Initialize() 466 // checks above and beyond those in Histogram::Initialize()
339 if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min || 467 if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min ||
340 INT_MAX / sizeof(Count) <= bucket_count || bucket_count < 2) { 468 INT_MAX / sizeof(Count) <= bucket_count || bucket_count < 2) {
341 DLOG(ERROR) << "Values error decoding Histogram: " << histogram_name; 469 DLOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 DCHECK_EQ(render_histogram->bucket_count(), bucket_count); 503 DCHECK_EQ(render_histogram->bucket_count(), bucket_count);
376 DCHECK_EQ(render_histogram->histogram_type(), histogram_type); 504 DCHECK_EQ(render_histogram->histogram_type(), histogram_type);
377 505
378 if (render_histogram->bucket_ranges()->checksum() != range_checksum) { 506 if (render_histogram->bucket_ranges()->checksum() != range_checksum) {
379 return false; 507 return false;
380 } 508 }
381 509
382 if (render_histogram->flags() & kIPCSerializationSourceFlag) { 510 if (render_histogram->flags() & kIPCSerializationSourceFlag) {
383 DVLOG(1) << "Single process mode, histogram observed and not copied: " 511 DVLOG(1) << "Single process mode, histogram observed and not copied: "
384 << histogram_name; 512 << histogram_name;
385 } else { 513 return true;
386 DCHECK_EQ(flags & render_histogram->flags(), flags);
387 render_histogram->AddSampleSet(sample);
388 } 514 }
389 515
390 return true; 516 DCHECK_EQ(flags & render_histogram->flags(), flags);
517
Ilya Sherman 2012/08/23 07:50:54 nit: No need for this blank line.
kaiwang 2012/08/24 04:17:58 Done.
518 return render_histogram->AddSamples(&iter);
391 } 519 }
392 520
521 // static
522 const int Histogram::kCommonRaceBasedCountMismatch = 5;
Ilya Sherman 2012/08/23 07:50:54 Why did you move this constant into the Histogram
kaiwang 2012/08/24 04:17:58 It's needed in histogram_snapshot_manager.cc The o
393 523
394 // Validate a sample and related histogram.
Ilya Sherman 2012/08/23 07:50:54 nit: Why did you remove this comment?
kaiwang 2012/08/24 04:17:58 better function comment in .h file
395 Histogram::Inconsistencies Histogram::FindCorruption( 524 Histogram::Inconsistencies Histogram::FindCorruption(
396 const SampleSet& snapshot) const { 525 const HistogramSamples& samples) const {
397 int inconsistencies = NO_INCONSISTENCIES; 526 int inconsistencies = NO_INCONSISTENCIES;
398 Sample previous_range = -1; // Bottom range is always 0. 527 Sample previous_range = -1; // Bottom range is always 0.
399 int64 count = 0;
400 for (size_t index = 0; index < bucket_count(); ++index) { 528 for (size_t index = 0; index < bucket_count(); ++index) {
401 count += snapshot.counts(index);
402 int new_range = ranges(index); 529 int new_range = ranges(index);
403 if (previous_range >= new_range) 530 if (previous_range >= new_range)
404 inconsistencies |= BUCKET_ORDER_ERROR; 531 inconsistencies |= BUCKET_ORDER_ERROR;
405 previous_range = new_range; 532 previous_range = new_range;
406 } 533 }
407 534
408 if (!bucket_ranges()->HasValidChecksum()) 535 if (!bucket_ranges()->HasValidChecksum())
409 inconsistencies |= RANGE_CHECKSUM_ERROR; 536 inconsistencies |= RANGE_CHECKSUM_ERROR;
410 537
411 int64 delta64 = snapshot.redundant_count() - count; 538 int64 delta64 = samples.redundant_count() - samples.TotalCount();
412 if (delta64 != 0) { 539 if (delta64 != 0) {
413 int delta = static_cast<int>(delta64); 540 int delta = static_cast<int>(delta64);
414 if (delta != delta64) 541 if (delta != delta64)
415 delta = INT_MAX; // Flag all giant errors as INT_MAX. 542 delta = INT_MAX; // Flag all giant errors as INT_MAX.
416 // Since snapshots of histograms are taken asynchronously relative to
417 // sampling (and snapped from different threads), it is pretty likely that
418 // we'll catch a redundant count that doesn't match the sample count. We
419 // allow for a certain amount of slop before flagging this as an
420 // inconsistency. Even with an inconsistency, we'll snapshot it again (for
421 // UMA in about a half hour, so we'll eventually get the data, if it was
422 // not the result of a corruption. If histograms show that 1 is "too tight"
423 // then we may try to use 2 or 3 for this slop value.
424 const int kCommonRaceBasedCountMismatch = 5;
425 if (delta > 0) { 543 if (delta > 0) {
426 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta); 544 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta);
427 if (delta > kCommonRaceBasedCountMismatch) 545 if (delta > kCommonRaceBasedCountMismatch)
428 inconsistencies |= COUNT_HIGH_ERROR; 546 inconsistencies |= COUNT_HIGH_ERROR;
429 } else { 547 } else {
430 DCHECK_GT(0, delta); 548 DCHECK_GT(0, delta);
431 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta); 549 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta);
432 if (-delta > kCommonRaceBasedCountMismatch) 550 if (-delta > kCommonRaceBasedCountMismatch)
433 inconsistencies |= COUNT_LOW_ERROR; 551 inconsistencies |= COUNT_LOW_ERROR;
434 } 552 }
435 } 553 }
436 return static_cast<Inconsistencies>(inconsistencies); 554 return static_cast<Inconsistencies>(inconsistencies);
437 } 555 }
438 556
439 Histogram::ClassType Histogram::histogram_type() const { 557 Histogram::ClassType Histogram::histogram_type() const {
440 return HISTOGRAM; 558 return HISTOGRAM;
441 } 559 }
442 560
443 Sample Histogram::ranges(size_t i) const { 561 Sample Histogram::ranges(size_t i) const {
444 return bucket_ranges_->range(i); 562 return bucket_ranges_->range(i);
445 } 563 }
446 564
447 size_t Histogram::bucket_count() const { 565 size_t Histogram::bucket_count() const {
448 return bucket_count_; 566 return bucket_count_;
449 } 567 }
450 568
451 // Do a safe atomic snapshot of sample data. 569 scoped_ptr<BucketHistogramSamples> Histogram::SnapshotSamples() const {
452 // This implementation assumes we are on a safe single thread. 570 scoped_ptr<BucketHistogramSamples> samples(
453 void Histogram::SnapshotSample(SampleSet* sample) const { 571 new BucketHistogramSamples(bucket_ranges()));
454 // Note locking not done in this version!!! 572 samples->Add(*samples_);
455 *sample = sample_; 573 return samples.Pass();
456 } 574 }
457 575
458 bool Histogram::HasConstructionArguments(Sample minimum, 576 bool Histogram::HasConstructionArguments(Sample minimum,
459 Sample maximum, 577 Sample maximum,
460 size_t bucket_count) { 578 size_t bucket_count) {
461 return ((minimum == declared_min_) && (maximum == declared_max_) && 579 return ((minimum == declared_min_) && (maximum == declared_max_) &&
462 (bucket_count == bucket_count_)); 580 (bucket_count == bucket_count_));
463 } 581 }
464 582
465 Histogram::Histogram(const string& name, 583 Histogram::Histogram(const string& name,
466 Sample minimum, 584 Sample minimum,
467 Sample maximum, 585 Sample maximum,
468 size_t bucket_count, 586 size_t bucket_count,
469 const BucketRanges* ranges) 587 const BucketRanges* ranges)
470 : HistogramBase(name), 588 : HistogramBase(name),
471 bucket_ranges_(ranges), 589 bucket_ranges_(ranges),
472 declared_min_(minimum), 590 declared_min_(minimum),
473 declared_max_(maximum), 591 declared_max_(maximum),
474 bucket_count_(bucket_count), 592 bucket_count_(bucket_count) {
475 sample_(bucket_count) {} 593 if (ranges) {
594 samples_.reset(new BucketHistogramSamples(ranges));
595 }
Ilya Sherman 2012/08/23 07:50:54 nit: No need for curly braces
kaiwang 2012/08/24 04:17:58 Done.
596 }
476 597
477 Histogram::~Histogram() { 598 Histogram::~Histogram() {
478 if (StatisticsRecorder::dump_on_exit()) { 599 if (StatisticsRecorder::dump_on_exit()) {
479 string output; 600 string output;
480 WriteAsciiImpl(true, "\n", &output); 601 WriteAsciiImpl(true, "\n", &output);
481 DLOG(INFO) << output; 602 DLOG(INFO) << output;
482 } 603 }
483 } 604 }
484 605
485 // static 606 // static
(...skipping 26 matching lines...) Expand all
512 } 633 }
513 634
514 bool Histogram::SerializeRanges(Pickle* pickle) const { 635 bool Histogram::SerializeRanges(Pickle* pickle) const {
515 return true; 636 return true;
516 } 637 }
517 638
518 bool Histogram::PrintEmptyBucket(size_t index) const { 639 bool Histogram::PrintEmptyBucket(size_t index) const {
519 return true; 640 return true;
520 } 641 }
521 642
522 size_t Histogram::BucketIndex(Sample value) const {
523 // Use simple binary search. This is very general, but there are better
524 // approaches if we knew that the buckets were linearly distributed.
525 DCHECK_LE(ranges(0), value);
526 DCHECK_GT(ranges(bucket_count()), value);
527 size_t under = 0;
528 size_t over = bucket_count();
529 size_t mid;
530
531 do {
532 DCHECK_GE(over, under);
533 mid = under + (over - under)/2;
534 if (mid == under)
535 break;
536 if (ranges(mid) <= value)
537 under = mid;
538 else
539 over = mid;
540 } while (true);
541
542 DCHECK_LE(ranges(mid), value);
543 CHECK_GT(ranges(mid+1), value);
544 return mid;
545 }
546
547 // Use the actual bucket widths (like a linear histogram) until the widths get 643 // Use the actual bucket widths (like a linear histogram) until the widths get
548 // over some transition value, and then use that transition width. Exponentials 644 // over some transition value, and then use that transition width. Exponentials
549 // get so big so fast (and we don't expect to see a lot of entries in the large 645 // get so big so fast (and we don't expect to see a lot of entries in the large
550 // buckets), so we need this to make it possible to see what is going on and 646 // buckets), so we need this to make it possible to see what is going on and
551 // not have 0-graphical-height buckets. 647 // not have 0-graphical-height buckets.
552 double Histogram::GetBucketSize(Count current, size_t i) const { 648 double Histogram::GetBucketSize(Count current, size_t i) const {
553 DCHECK_GT(ranges(i + 1), ranges(i)); 649 DCHECK_GT(ranges(i + 1), ranges(i));
554 static const double kTransitionWidth = 5; 650 static const double kTransitionWidth = 5;
555 double denominator = ranges(i + 1) - ranges(i); 651 double denominator = ranges(i + 1) - ranges(i);
556 if (denominator > kTransitionWidth) 652 if (denominator > kTransitionWidth)
557 denominator = kTransitionWidth; // Stop trying to normalize. 653 denominator = kTransitionWidth; // Stop trying to normalize.
558 return current/denominator; 654 return current/denominator;
559 } 655 }
560 656
561 const string Histogram::GetAsciiBucketRange(size_t i) const { 657 const string Histogram::GetAsciiBucketRange(size_t i) const {
562 string result; 658 string result;
563 if (kHexRangePrintingFlag & flags()) 659 if (kHexRangePrintingFlag & flags())
564 StringAppendF(&result, "%#x", ranges(i)); 660 StringAppendF(&result, "%#x", ranges(i));
565 else 661 else
566 StringAppendF(&result, "%d", ranges(i)); 662 StringAppendF(&result, "%d", ranges(i));
567 return result; 663 return result;
568 } 664 }
569 665
570 // Update histogram data with new sample.
571 void Histogram::Accumulate(Sample value, Count count, size_t index) {
572 // Note locking not done in this version!!!
Ilya Sherman 2012/08/23 07:50:54 nit: Please keep this comment around by the releva
kaiwang 2012/08/24 04:17:58 this function is not needed any more. All Histogra
573 sample_.Accumulate(value, count, index);
574 }
575
576 //------------------------------------------------------------------------------ 666 //------------------------------------------------------------------------------
577 // Private methods 667 // Private methods
578 668
579 void Histogram::WriteAsciiImpl(bool graph_it, 669 void Histogram::WriteAsciiImpl(bool graph_it,
580 const string& newline, 670 const string& newline,
581 string* output) const { 671 string* output) const {
582 // Get local (stack) copies of all effectively volatile class data so that we 672 // Get local (stack) copies of all effectively volatile class data so that we
583 // are consistent across our output activities. 673 // are consistent across our output activities.
584 SampleSet snapshot; 674 scoped_ptr<BucketHistogramSamples> snapshot = SnapshotSamples();
585 SnapshotSample(&snapshot); 675 Count sample_count = snapshot->TotalCount();
586 Count sample_count = snapshot.TotalCount();
587 676
588 WriteAsciiHeader(snapshot, sample_count, output); 677 WriteAsciiHeader(*snapshot, sample_count, output);
589 output->append(newline); 678 output->append(newline);
590 679
591 // Prepare to normalize graphical rendering of bucket contents. 680 // Prepare to normalize graphical rendering of bucket contents.
592 double max_size = 0; 681 double max_size = 0;
593 if (graph_it) 682 if (graph_it)
594 max_size = GetPeakBucketSize(snapshot); 683 max_size = GetPeakBucketSize(*snapshot);
595 684
596 // Calculate space needed to print bucket range numbers. Leave room to print 685 // Calculate space needed to print bucket range numbers. Leave room to print
597 // nearly the largest bucket range without sliding over the histogram. 686 // nearly the largest bucket range without sliding over the histogram.
598 size_t largest_non_empty_bucket = bucket_count() - 1; 687 size_t largest_non_empty_bucket = bucket_count() - 1;
599 while (0 == snapshot.counts(largest_non_empty_bucket)) { 688 while (0 == snapshot->GetCountFromBucketIndex(largest_non_empty_bucket)) {
600 if (0 == largest_non_empty_bucket) 689 if (0 == largest_non_empty_bucket)
601 break; // All buckets are empty. 690 break; // All buckets are empty.
602 --largest_non_empty_bucket; 691 --largest_non_empty_bucket;
603 } 692 }
604 693
605 // Calculate largest print width needed for any of our bucket range displays. 694 // Calculate largest print width needed for any of our bucket range displays.
606 size_t print_width = 1; 695 size_t print_width = 1;
607 for (size_t i = 0; i < bucket_count(); ++i) { 696 for (size_t i = 0; i < bucket_count(); ++i) {
608 if (snapshot.counts(i)) { 697 if (snapshot->GetCountFromBucketIndex(i)) {
609 size_t width = GetAsciiBucketRange(i).size() + 1; 698 size_t width = GetAsciiBucketRange(i).size() + 1;
610 if (width > print_width) 699 if (width > print_width)
611 print_width = width; 700 print_width = width;
612 } 701 }
613 } 702 }
614 703
615 int64 remaining = sample_count; 704 int64 remaining = sample_count;
616 int64 past = 0; 705 int64 past = 0;
617 // Output the actual histogram graph. 706 // Output the actual histogram graph.
618 for (size_t i = 0; i < bucket_count(); ++i) { 707 for (size_t i = 0; i < bucket_count(); ++i) {
619 Count current = snapshot.counts(i); 708 Count current = snapshot->GetCountFromBucketIndex(i);
620 if (!current && !PrintEmptyBucket(i)) 709 if (!current && !PrintEmptyBucket(i))
621 continue; 710 continue;
622 remaining -= current; 711 remaining -= current;
623 string range = GetAsciiBucketRange(i); 712 string range = GetAsciiBucketRange(i);
624 output->append(range); 713 output->append(range);
625 for (size_t j = 0; range.size() + j < print_width + 1; ++j) 714 for (size_t j = 0; range.size() + j < print_width + 1; ++j)
626 output->push_back(' '); 715 output->push_back(' ');
627 if (0 == current && i < bucket_count() - 1 && 0 == snapshot.counts(i + 1)) { 716 if (0 == current && i < bucket_count() - 1 &&
628 while (i < bucket_count() - 1 && 0 == snapshot.counts(i + 1)) 717 0 == snapshot->GetCountFromBucketIndex(i + 1)) {
718 while (i < bucket_count() - 1 &&
719 0 == snapshot->GetCountFromBucketIndex(i + 1)) {
629 ++i; 720 ++i;
721 }
630 output->append("... "); 722 output->append("... ");
631 output->append(newline); 723 output->append(newline);
632 continue; // No reason to plot emptiness. 724 continue; // No reason to plot emptiness.
633 } 725 }
634 double current_size = GetBucketSize(current, i); 726 double current_size = GetBucketSize(current, i);
635 if (graph_it) 727 if (graph_it)
636 WriteAsciiBucketGraph(current_size, max_size, output); 728 WriteAsciiBucketGraph(current_size, max_size, output);
637 WriteAsciiBucketContext(past, current, remaining, i, output); 729 WriteAsciiBucketContext(past, current, remaining, i, output);
638 output->append(newline); 730 output->append(newline);
639 past += current; 731 past += current;
640 } 732 }
641 DCHECK_EQ(sample_count, past); 733 DCHECK_EQ(sample_count, past);
642 } 734 }
643 735
644 double Histogram::GetPeakBucketSize(const SampleSet& snapshot) const { 736 double Histogram::GetPeakBucketSize(
737 const BucketHistogramSamples& samples) const {
645 double max = 0; 738 double max = 0;
646 for (size_t i = 0; i < bucket_count() ; ++i) { 739 for (size_t i = 0; i < bucket_count() ; ++i) {
647 double current_size = GetBucketSize(snapshot.counts(i), i); 740 double current_size = GetBucketSize(samples.GetCountFromBucketIndex(i), i);
648 if (current_size > max) 741 if (current_size > max)
649 max = current_size; 742 max = current_size;
650 } 743 }
651 return max; 744 return max;
652 } 745 }
653 746
654 void Histogram::WriteAsciiHeader(const SampleSet& snapshot, 747 void Histogram::WriteAsciiHeader(const BucketHistogramSamples& samples,
655 Count sample_count, 748 Count sample_count,
656 string* output) const { 749 string* output) const {
657 StringAppendF(output, 750 StringAppendF(output,
658 "Histogram: %s recorded %d samples", 751 "Histogram: %s recorded %d samples",
659 histogram_name().c_str(), 752 histogram_name().c_str(),
660 sample_count); 753 sample_count);
661 if (0 == sample_count) { 754 if (0 == sample_count) {
662 DCHECK_EQ(snapshot.sum(), 0); 755 DCHECK_EQ(samples.sum(), 0);
663 } else { 756 } else {
664 double average = static_cast<float>(snapshot.sum()) / sample_count; 757 double average = static_cast<float>(samples.sum()) / sample_count;
665 758
666 StringAppendF(output, ", average = %.1f", average); 759 StringAppendF(output, ", average = %.1f", average);
667 } 760 }
668 if (flags() & ~kHexRangePrintingFlag) 761 if (flags() & ~kHexRangePrintingFlag)
669 StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag); 762 StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag);
670 } 763 }
671 764
672 void Histogram::WriteAsciiBucketContext(const int64 past, 765 void Histogram::WriteAsciiBucketContext(const int64 past,
673 const Count current, 766 const Count current,
674 const int64 remaining, 767 const int64 remaining,
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after
957 1050
958 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); 1051 BucketRanges* bucket_ranges = new BucketRanges(ranges.size());
959 for (size_t i = 0; i < ranges.size(); i++) { 1052 for (size_t i = 0; i < ranges.size(); i++) {
960 bucket_ranges->set_range(i, ranges[i]); 1053 bucket_ranges->set_range(i, ranges[i]);
961 } 1054 }
962 bucket_ranges->ResetChecksum(); 1055 bucket_ranges->ResetChecksum();
963 return bucket_ranges; 1056 return bucket_ranges;
964 } 1057 }
965 1058
966 } // namespace base 1059 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698