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

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, 3 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
« no previous file with comments | « base/metrics/histogram.h ('k') | base/metrics/histogram_flattener.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 16 matching lines...) Expand all
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 // static 34 // static
35 const size_t Histogram::kBucketCount_MAX = 16384u; 35 const size_t Histogram::kBucketCount_MAX = 16384u;
36 36
37 Histogram::SampleSet::SampleSet(size_t size)
38 : counts_(size, 0),
39 sum_(0),
40 redundant_count_(0) {}
41
42 Histogram::SampleSet::SampleSet()
43 : counts_(),
44 sum_(0),
45 redundant_count_(0) {}
46
47 Histogram::SampleSet::~SampleSet() {}
48
49 void Histogram::SampleSet::Resize(size_t size) {
50 counts_.resize(size, 0);
51 }
52
53 void Histogram::SampleSet::Accumulate(Sample value, Count count,
54 size_t index) {
55 DCHECK(count == 1 || count == -1);
56 counts_[index] += count;
57 sum_ += count * value;
58 redundant_count_ += count;
59 DCHECK_GE(counts_[index], 0);
60 DCHECK_GE(sum_, 0);
61 DCHECK_GE(redundant_count_, 0);
62 }
63
64 Count Histogram::SampleSet::TotalCount() const {
65 Count total = 0;
66 for (Counts::const_iterator it = counts_.begin();
67 it != counts_.end();
68 ++it) {
69 total += *it;
70 }
71 return total;
72 }
73
74 void Histogram::SampleSet::Add(const SampleSet& other) {
75 DCHECK_EQ(counts_.size(), other.counts_.size());
76 sum_ += other.sum_;
77 redundant_count_ += other.redundant_count_;
78 for (size_t index = 0; index < counts_.size(); ++index)
79 counts_[index] += other.counts_[index];
80 }
81
82 void Histogram::SampleSet::Subtract(const SampleSet& other) {
83 DCHECK_EQ(counts_.size(), other.counts_.size());
84 // Note: Race conditions in snapshotting a sum may lead to (temporary)
85 // negative values when snapshots are later combined (and deltas calculated).
86 // As a result, we don't currently CHCEK() for positive values.
87 sum_ -= other.sum_;
88 redundant_count_ -= other.redundant_count_;
89 for (size_t index = 0; index < counts_.size(); ++index) {
90 counts_[index] -= other.counts_[index];
91 DCHECK_GE(counts_[index], 0);
92 }
93 }
94
95 bool Histogram::SampleSet::Serialize(Pickle* pickle) const {
96 pickle->WriteInt64(sum_);
97 pickle->WriteInt64(redundant_count_);
98 pickle->WriteUInt64(counts_.size());
99
100 for (size_t index = 0; index < counts_.size(); ++index) {
101 pickle->WriteInt(counts_[index]);
102 }
103
104 return true;
105 }
106
107 bool Histogram::SampleSet::Deserialize(PickleIterator* iter) {
108 DCHECK_EQ(counts_.size(), 0u);
109 DCHECK_EQ(sum_, 0);
110 DCHECK_EQ(redundant_count_, 0);
111
112 uint64 counts_size;
113
114 if (!iter->ReadInt64(&sum_) ||
115 !iter->ReadInt64(&redundant_count_) ||
116 !iter->ReadUInt64(&counts_size)) {
117 return false;
118 }
119
120 if (counts_size == 0)
121 return false;
122
123 int count = 0;
124 for (uint64 index = 0; index < counts_size; ++index) {
125 int i;
126 if (!iter->ReadInt(&i))
127 return false;
128 counts_.push_back(i);
129 count += i;
130 }
131 DCHECK_EQ(count, redundant_count_);
132 return count == redundant_count_;
133 }
134
135 // TODO(rtenneti): delete this code after debugging. 37 // TODO(rtenneti): delete this code after debugging.
136 void CheckCorruption(const Histogram& histogram, bool new_histogram) { 38 void CheckCorruption(const Histogram& histogram, bool new_histogram) {
137 const std::string& histogram_name = histogram.histogram_name(); 39 const std::string& histogram_name = histogram.histogram_name();
138 char histogram_name_buf[128]; 40 char histogram_name_buf[128];
139 base::strlcpy(histogram_name_buf, 41 base::strlcpy(histogram_name_buf,
140 histogram_name.c_str(), 42 histogram_name.c_str(),
141 arraysize(histogram_name_buf)); 43 arraysize(histogram_name_buf));
142 base::debug::Alias(histogram_name_buf); 44 base::debug::Alias(histogram_name_buf);
143 45
144 bool debug_new_histogram[1]; 46 bool debug_new_histogram[1];
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
238 if (next > current) 140 if (next > current)
239 current = next; 141 current = next;
240 else 142 else
241 ++current; // Just do a narrow bucket, and keep trying. 143 ++current; // Just do a narrow bucket, and keep trying.
242 ranges->set_range(bucket_index, current); 144 ranges->set_range(bucket_index, current);
243 } 145 }
244 ranges->set_range(ranges->size() - 1, HistogramBase::kSampleType_MAX); 146 ranges->set_range(ranges->size() - 1, HistogramBase::kSampleType_MAX);
245 ranges->ResetChecksum(); 147 ranges->ResetChecksum();
246 } 148 }
247 149
248 // static
249 void Histogram::Add(int value) { 150 void Histogram::Add(int value) {
151 DCHECK_EQ(0, ranges(0));
152 DCHECK_EQ(kSampleType_MAX, ranges(bucket_count_));
153
250 if (value > kSampleType_MAX - 1) 154 if (value > kSampleType_MAX - 1)
251 value = kSampleType_MAX - 1; 155 value = kSampleType_MAX - 1;
252 if (value < 0) 156 if (value < 0)
253 value = 0; 157 value = 0;
254 size_t index = BucketIndex(value); 158 samples_->Accumulate(value, 1);
255 DCHECK_GE(value, ranges(index));
256 DCHECK_LT(value, ranges(index + 1));
257 Accumulate(value, 1, index);
258 } 159 }
259 160
260 void Histogram::AddBoolean(bool value) { 161 void Histogram::AddBoolean(bool value) {
261 DCHECK(false); 162 DCHECK(false);
262 } 163 }
263 164
264 void Histogram::AddSampleSet(const SampleSet& sample) { 165 void Histogram::AddSamples(const HistogramSamples& samples) {
265 sample_.Add(sample); 166 samples_->Add(samples);
167 }
168
169 bool Histogram::AddSamplesFromPickle(PickleIterator* iter) {
170 return samples_->AddFromPickle(iter);
266 } 171 }
267 172
268 void Histogram::SetRangeDescriptions(const DescriptionPair descriptions[]) { 173 void Histogram::SetRangeDescriptions(const DescriptionPair descriptions[]) {
269 DCHECK(false); 174 DCHECK(false);
270 } 175 }
271 176
272 // The following methods provide a graphical histogram display. 177 // The following methods provide a graphical histogram display.
273 void Histogram::WriteHTMLGraph(string* output) const { 178 void Histogram::WriteHTMLGraph(string* output) const {
274 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc. 179 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
275 output->append("<PRE>"); 180 output->append("<PRE>");
276 WriteAsciiImpl(true, "<br>", output); 181 WriteAsciiImpl(true, "<br>", output);
277 output->append("</PRE>"); 182 output->append("</PRE>");
278 } 183 }
279 184
280 void Histogram::WriteAscii(string* output) const { 185 void Histogram::WriteAscii(string* output) const {
281 WriteAsciiImpl(true, "\n", output); 186 WriteAsciiImpl(true, "\n", output);
282 } 187 }
283 188
284 // static 189 // static
285 string Histogram::SerializeHistogramInfo(const Histogram& histogram, 190 string Histogram::SerializeHistogramInfo(const Histogram& histogram,
286 const SampleSet& snapshot) { 191 const HistogramSamples& snapshot) {
287 DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type()); 192 DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type());
288 DCHECK(histogram.bucket_ranges()->HasValidChecksum()); 193 DCHECK(histogram.bucket_ranges()->HasValidChecksum());
289 194
290 Pickle pickle; 195 Pickle pickle;
291 pickle.WriteString(histogram.histogram_name()); 196 pickle.WriteString(histogram.histogram_name());
292 pickle.WriteInt(histogram.declared_min()); 197 pickle.WriteInt(histogram.declared_min());
293 pickle.WriteInt(histogram.declared_max()); 198 pickle.WriteInt(histogram.declared_max());
294 pickle.WriteUInt64(histogram.bucket_count()); 199 pickle.WriteUInt64(histogram.bucket_count());
295 pickle.WriteUInt32(histogram.bucket_ranges()->checksum()); 200 pickle.WriteUInt32(histogram.bucket_ranges()->checksum());
296 pickle.WriteInt(histogram.histogram_type()); 201 pickle.WriteInt(histogram.histogram_type());
297 pickle.WriteInt(histogram.flags()); 202 pickle.WriteInt(histogram.flags());
298 203
204 histogram.SerializeRanges(&pickle);
205
299 snapshot.Serialize(&pickle); 206 snapshot.Serialize(&pickle);
300 207
301 histogram.SerializeRanges(&pickle);
302
303 return string(static_cast<const char*>(pickle.data()), pickle.size()); 208 return string(static_cast<const char*>(pickle.data()), pickle.size());
304 } 209 }
305 210
306 // static 211 // static
307 bool Histogram::DeserializeHistogramInfo(const string& histogram_info) { 212 bool Histogram::DeserializeHistogramInfo(const string& histogram_info) {
308 if (histogram_info.empty()) { 213 if (histogram_info.empty()) {
309 return false; 214 return false;
310 } 215 }
311 216
312 Pickle pickle(histogram_info.data(), 217 Pickle pickle(histogram_info.data(),
313 static_cast<int>(histogram_info.size())); 218 static_cast<int>(histogram_info.size()));
314 string histogram_name; 219 string histogram_name;
315 int declared_min; 220 int declared_min;
316 int declared_max; 221 int declared_max;
317 uint64 bucket_count; 222 uint64 bucket_count;
318 uint32 range_checksum; 223 uint32 range_checksum;
319 int histogram_type; 224 int histogram_type;
320 int pickle_flags; 225 int pickle_flags;
321 SampleSet sample;
322 226
323 PickleIterator iter(pickle); 227 PickleIterator iter(pickle);
324 if (!iter.ReadString(&histogram_name) || 228 if (!iter.ReadString(&histogram_name) ||
325 !iter.ReadInt(&declared_min) || 229 !iter.ReadInt(&declared_min) ||
326 !iter.ReadInt(&declared_max) || 230 !iter.ReadInt(&declared_max) ||
327 !iter.ReadUInt64(&bucket_count) || 231 !iter.ReadUInt64(&bucket_count) ||
328 !iter.ReadUInt32(&range_checksum) || 232 !iter.ReadUInt32(&range_checksum) ||
329 !iter.ReadInt(&histogram_type) || 233 !iter.ReadInt(&histogram_type) ||
330 !iter.ReadInt(&pickle_flags) || 234 !iter.ReadInt(&pickle_flags)) {
331 !sample.Histogram::SampleSet::Deserialize(&iter)) {
332 DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name; 235 DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
333 return false; 236 return false;
334 } 237 }
335 238
336 DCHECK(pickle_flags & kIPCSerializationSourceFlag); 239 DCHECK(pickle_flags & kIPCSerializationSourceFlag);
337 // Since these fields may have come from an untrusted renderer, do additional 240 // Since these fields may have come from an untrusted renderer, do additional
338 // checks above and beyond those in Histogram::Initialize() 241 // checks above and beyond those in Histogram::Initialize()
339 if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min || 242 if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min ||
340 INT_MAX / sizeof(Count) <= bucket_count || bucket_count < 2) { 243 INT_MAX / sizeof(Count) <= bucket_count || bucket_count < 2) {
341 DLOG(ERROR) << "Values error decoding Histogram: " << histogram_name; 244 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); 278 DCHECK_EQ(render_histogram->bucket_count(), bucket_count);
376 DCHECK_EQ(render_histogram->histogram_type(), histogram_type); 279 DCHECK_EQ(render_histogram->histogram_type(), histogram_type);
377 280
378 if (render_histogram->bucket_ranges()->checksum() != range_checksum) { 281 if (render_histogram->bucket_ranges()->checksum() != range_checksum) {
379 return false; 282 return false;
380 } 283 }
381 284
382 if (render_histogram->flags() & kIPCSerializationSourceFlag) { 285 if (render_histogram->flags() & kIPCSerializationSourceFlag) {
383 DVLOG(1) << "Single process mode, histogram observed and not copied: " 286 DVLOG(1) << "Single process mode, histogram observed and not copied: "
384 << histogram_name; 287 << histogram_name;
385 } else { 288 return true;
386 DCHECK_EQ(flags & render_histogram->flags(), flags);
387 render_histogram->AddSampleSet(sample);
388 } 289 }
389 290
390 return true; 291 DCHECK_EQ(flags & render_histogram->flags(), flags);
292 return render_histogram->AddSamplesFromPickle(&iter);
391 } 293 }
392 294
295 // static
296 const int Histogram::kCommonRaceBasedCountMismatch = 5;
393 297
394 // Validate a sample and related histogram.
395 Histogram::Inconsistencies Histogram::FindCorruption( 298 Histogram::Inconsistencies Histogram::FindCorruption(
396 const SampleSet& snapshot) const { 299 const HistogramSamples& samples) const {
397 int inconsistencies = NO_INCONSISTENCIES; 300 int inconsistencies = NO_INCONSISTENCIES;
398 Sample previous_range = -1; // Bottom range is always 0. 301 Sample previous_range = -1; // Bottom range is always 0.
399 int64 count = 0;
400 for (size_t index = 0; index < bucket_count(); ++index) { 302 for (size_t index = 0; index < bucket_count(); ++index) {
401 count += snapshot.counts(index);
402 int new_range = ranges(index); 303 int new_range = ranges(index);
403 if (previous_range >= new_range) 304 if (previous_range >= new_range)
404 inconsistencies |= BUCKET_ORDER_ERROR; 305 inconsistencies |= BUCKET_ORDER_ERROR;
405 previous_range = new_range; 306 previous_range = new_range;
406 } 307 }
407 308
408 if (!bucket_ranges()->HasValidChecksum()) 309 if (!bucket_ranges()->HasValidChecksum())
409 inconsistencies |= RANGE_CHECKSUM_ERROR; 310 inconsistencies |= RANGE_CHECKSUM_ERROR;
410 311
411 int64 delta64 = snapshot.redundant_count() - count; 312 int64 delta64 = samples.redundant_count() - samples.TotalCount();
412 if (delta64 != 0) { 313 if (delta64 != 0) {
413 int delta = static_cast<int>(delta64); 314 int delta = static_cast<int>(delta64);
414 if (delta != delta64) 315 if (delta != delta64)
415 delta = INT_MAX; // Flag all giant errors as INT_MAX. 316 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) { 317 if (delta > 0) {
426 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta); 318 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta);
427 if (delta > kCommonRaceBasedCountMismatch) 319 if (delta > kCommonRaceBasedCountMismatch)
428 inconsistencies |= COUNT_HIGH_ERROR; 320 inconsistencies |= COUNT_HIGH_ERROR;
429 } else { 321 } else {
430 DCHECK_GT(0, delta); 322 DCHECK_GT(0, delta);
431 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta); 323 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta);
432 if (-delta > kCommonRaceBasedCountMismatch) 324 if (-delta > kCommonRaceBasedCountMismatch)
433 inconsistencies |= COUNT_LOW_ERROR; 325 inconsistencies |= COUNT_LOW_ERROR;
434 } 326 }
435 } 327 }
436 return static_cast<Inconsistencies>(inconsistencies); 328 return static_cast<Inconsistencies>(inconsistencies);
437 } 329 }
438 330
439 Histogram::ClassType Histogram::histogram_type() const { 331 Histogram::ClassType Histogram::histogram_type() const {
440 return HISTOGRAM; 332 return HISTOGRAM;
441 } 333 }
442 334
443 Sample Histogram::ranges(size_t i) const { 335 Sample Histogram::ranges(size_t i) const {
444 return bucket_ranges_->range(i); 336 return bucket_ranges_->range(i);
445 } 337 }
446 338
447 size_t Histogram::bucket_count() const { 339 size_t Histogram::bucket_count() const {
448 return bucket_count_; 340 return bucket_count_;
449 } 341 }
450 342
451 // Do a safe atomic snapshot of sample data. 343 scoped_ptr<SampleVector> Histogram::SnapshotSamples() const {
452 // This implementation assumes we are on a safe single thread. 344 scoped_ptr<SampleVector> samples(new SampleVector(bucket_ranges()));
453 void Histogram::SnapshotSample(SampleSet* sample) const { 345 samples->Add(*samples_);
454 // Note locking not done in this version!!! 346 return samples.Pass();
455 *sample = sample_;
456 } 347 }
457 348
458 bool Histogram::HasConstructionArguments(Sample minimum, 349 bool Histogram::HasConstructionArguments(Sample minimum,
459 Sample maximum, 350 Sample maximum,
460 size_t bucket_count) { 351 size_t bucket_count) {
461 return ((minimum == declared_min_) && (maximum == declared_max_) && 352 return ((minimum == declared_min_) && (maximum == declared_max_) &&
462 (bucket_count == bucket_count_)); 353 (bucket_count == bucket_count_));
463 } 354 }
464 355
465 Histogram::Histogram(const string& name, 356 Histogram::Histogram(const string& name,
466 Sample minimum, 357 Sample minimum,
467 Sample maximum, 358 Sample maximum,
468 size_t bucket_count, 359 size_t bucket_count,
469 const BucketRanges* ranges) 360 const BucketRanges* ranges)
470 : HistogramBase(name), 361 : HistogramBase(name),
471 bucket_ranges_(ranges), 362 bucket_ranges_(ranges),
472 declared_min_(minimum), 363 declared_min_(minimum),
473 declared_max_(maximum), 364 declared_max_(maximum),
474 bucket_count_(bucket_count), 365 bucket_count_(bucket_count) {
475 sample_(bucket_count) {} 366 if (ranges)
367 samples_.reset(new SampleVector(ranges));
368 }
476 369
477 Histogram::~Histogram() { 370 Histogram::~Histogram() {
478 if (StatisticsRecorder::dump_on_exit()) { 371 if (StatisticsRecorder::dump_on_exit()) {
479 string output; 372 string output;
480 WriteAsciiImpl(true, "\n", &output); 373 WriteAsciiImpl(true, "\n", &output);
481 DLOG(INFO) << output; 374 DLOG(INFO) << output;
482 } 375 }
483 } 376 }
484 377
485 // static 378 // static
(...skipping 26 matching lines...) Expand all
512 } 405 }
513 406
514 bool Histogram::SerializeRanges(Pickle* pickle) const { 407 bool Histogram::SerializeRanges(Pickle* pickle) const {
515 return true; 408 return true;
516 } 409 }
517 410
518 bool Histogram::PrintEmptyBucket(size_t index) const { 411 bool Histogram::PrintEmptyBucket(size_t index) const {
519 return true; 412 return true;
520 } 413 }
521 414
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 415 // 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 416 // 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 417 // 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 418 // buckets), so we need this to make it possible to see what is going on and
551 // not have 0-graphical-height buckets. 419 // not have 0-graphical-height buckets.
552 double Histogram::GetBucketSize(Count current, size_t i) const { 420 double Histogram::GetBucketSize(Count current, size_t i) const {
553 DCHECK_GT(ranges(i + 1), ranges(i)); 421 DCHECK_GT(ranges(i + 1), ranges(i));
554 static const double kTransitionWidth = 5; 422 static const double kTransitionWidth = 5;
555 double denominator = ranges(i + 1) - ranges(i); 423 double denominator = ranges(i + 1) - ranges(i);
556 if (denominator > kTransitionWidth) 424 if (denominator > kTransitionWidth)
557 denominator = kTransitionWidth; // Stop trying to normalize. 425 denominator = kTransitionWidth; // Stop trying to normalize.
558 return current/denominator; 426 return current/denominator;
559 } 427 }
560 428
561 const string Histogram::GetAsciiBucketRange(size_t i) const { 429 const string Histogram::GetAsciiBucketRange(size_t i) const {
562 string result; 430 string result;
563 if (kHexRangePrintingFlag & flags()) 431 if (kHexRangePrintingFlag & flags())
564 StringAppendF(&result, "%#x", ranges(i)); 432 StringAppendF(&result, "%#x", ranges(i));
565 else 433 else
566 StringAppendF(&result, "%d", ranges(i)); 434 StringAppendF(&result, "%d", ranges(i));
567 return result; 435 return result;
568 } 436 }
569 437
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!!!
573 sample_.Accumulate(value, count, index);
574 }
575
576 //------------------------------------------------------------------------------ 438 //------------------------------------------------------------------------------
577 // Private methods 439 // Private methods
578 440
579 void Histogram::WriteAsciiImpl(bool graph_it, 441 void Histogram::WriteAsciiImpl(bool graph_it,
580 const string& newline, 442 const string& newline,
581 string* output) const { 443 string* output) const {
582 // Get local (stack) copies of all effectively volatile class data so that we 444 // Get local (stack) copies of all effectively volatile class data so that we
583 // are consistent across our output activities. 445 // are consistent across our output activities.
584 SampleSet snapshot; 446 scoped_ptr<SampleVector> snapshot = SnapshotSamples();
585 SnapshotSample(&snapshot); 447 Count sample_count = snapshot->TotalCount();
586 Count sample_count = snapshot.TotalCount();
587 448
588 WriteAsciiHeader(snapshot, sample_count, output); 449 WriteAsciiHeader(*snapshot, sample_count, output);
589 output->append(newline); 450 output->append(newline);
590 451
591 // Prepare to normalize graphical rendering of bucket contents. 452 // Prepare to normalize graphical rendering of bucket contents.
592 double max_size = 0; 453 double max_size = 0;
593 if (graph_it) 454 if (graph_it)
594 max_size = GetPeakBucketSize(snapshot); 455 max_size = GetPeakBucketSize(*snapshot);
595 456
596 // Calculate space needed to print bucket range numbers. Leave room to print 457 // Calculate space needed to print bucket range numbers. Leave room to print
597 // nearly the largest bucket range without sliding over the histogram. 458 // nearly the largest bucket range without sliding over the histogram.
598 size_t largest_non_empty_bucket = bucket_count() - 1; 459 size_t largest_non_empty_bucket = bucket_count() - 1;
599 while (0 == snapshot.counts(largest_non_empty_bucket)) { 460 while (0 == snapshot->GetCountAtIndex(largest_non_empty_bucket)) {
600 if (0 == largest_non_empty_bucket) 461 if (0 == largest_non_empty_bucket)
601 break; // All buckets are empty. 462 break; // All buckets are empty.
602 --largest_non_empty_bucket; 463 --largest_non_empty_bucket;
603 } 464 }
604 465
605 // Calculate largest print width needed for any of our bucket range displays. 466 // Calculate largest print width needed for any of our bucket range displays.
606 size_t print_width = 1; 467 size_t print_width = 1;
607 for (size_t i = 0; i < bucket_count(); ++i) { 468 for (size_t i = 0; i < bucket_count(); ++i) {
608 if (snapshot.counts(i)) { 469 if (snapshot->GetCountAtIndex(i)) {
609 size_t width = GetAsciiBucketRange(i).size() + 1; 470 size_t width = GetAsciiBucketRange(i).size() + 1;
610 if (width > print_width) 471 if (width > print_width)
611 print_width = width; 472 print_width = width;
612 } 473 }
613 } 474 }
614 475
615 int64 remaining = sample_count; 476 int64 remaining = sample_count;
616 int64 past = 0; 477 int64 past = 0;
617 // Output the actual histogram graph. 478 // Output the actual histogram graph.
618 for (size_t i = 0; i < bucket_count(); ++i) { 479 for (size_t i = 0; i < bucket_count(); ++i) {
619 Count current = snapshot.counts(i); 480 Count current = snapshot->GetCountAtIndex(i);
620 if (!current && !PrintEmptyBucket(i)) 481 if (!current && !PrintEmptyBucket(i))
621 continue; 482 continue;
622 remaining -= current; 483 remaining -= current;
623 string range = GetAsciiBucketRange(i); 484 string range = GetAsciiBucketRange(i);
624 output->append(range); 485 output->append(range);
625 for (size_t j = 0; range.size() + j < print_width + 1; ++j) 486 for (size_t j = 0; range.size() + j < print_width + 1; ++j)
626 output->push_back(' '); 487 output->push_back(' ');
627 if (0 == current && i < bucket_count() - 1 && 0 == snapshot.counts(i + 1)) { 488 if (0 == current && i < bucket_count() - 1 &&
628 while (i < bucket_count() - 1 && 0 == snapshot.counts(i + 1)) 489 0 == snapshot->GetCountAtIndex(i + 1)) {
490 while (i < bucket_count() - 1 &&
491 0 == snapshot->GetCountAtIndex(i + 1)) {
629 ++i; 492 ++i;
493 }
630 output->append("... "); 494 output->append("... ");
631 output->append(newline); 495 output->append(newline);
632 continue; // No reason to plot emptiness. 496 continue; // No reason to plot emptiness.
633 } 497 }
634 double current_size = GetBucketSize(current, i); 498 double current_size = GetBucketSize(current, i);
635 if (graph_it) 499 if (graph_it)
636 WriteAsciiBucketGraph(current_size, max_size, output); 500 WriteAsciiBucketGraph(current_size, max_size, output);
637 WriteAsciiBucketContext(past, current, remaining, i, output); 501 WriteAsciiBucketContext(past, current, remaining, i, output);
638 output->append(newline); 502 output->append(newline);
639 past += current; 503 past += current;
640 } 504 }
641 DCHECK_EQ(sample_count, past); 505 DCHECK_EQ(sample_count, past);
642 } 506 }
643 507
644 double Histogram::GetPeakBucketSize(const SampleSet& snapshot) const { 508 double Histogram::GetPeakBucketSize(const SampleVector& samples) const {
645 double max = 0; 509 double max = 0;
646 for (size_t i = 0; i < bucket_count() ; ++i) { 510 for (size_t i = 0; i < bucket_count() ; ++i) {
647 double current_size = GetBucketSize(snapshot.counts(i), i); 511 double current_size = GetBucketSize(samples.GetCountAtIndex(i), i);
648 if (current_size > max) 512 if (current_size > max)
649 max = current_size; 513 max = current_size;
650 } 514 }
651 return max; 515 return max;
652 } 516 }
653 517
654 void Histogram::WriteAsciiHeader(const SampleSet& snapshot, 518 void Histogram::WriteAsciiHeader(const SampleVector& samples,
655 Count sample_count, 519 Count sample_count,
656 string* output) const { 520 string* output) const {
657 StringAppendF(output, 521 StringAppendF(output,
658 "Histogram: %s recorded %d samples", 522 "Histogram: %s recorded %d samples",
659 histogram_name().c_str(), 523 histogram_name().c_str(),
660 sample_count); 524 sample_count);
661 if (0 == sample_count) { 525 if (0 == sample_count) {
662 DCHECK_EQ(snapshot.sum(), 0); 526 DCHECK_EQ(samples.sum(), 0);
663 } else { 527 } else {
664 double average = static_cast<float>(snapshot.sum()) / sample_count; 528 double average = static_cast<float>(samples.sum()) / sample_count;
665 529
666 StringAppendF(output, ", average = %.1f", average); 530 StringAppendF(output, ", average = %.1f", average);
667 } 531 }
668 if (flags() & ~kHexRangePrintingFlag) 532 if (flags() & ~kHexRangePrintingFlag)
669 StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag); 533 StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag);
670 } 534 }
671 535
672 void Histogram::WriteAsciiBucketContext(const int64 past, 536 void Histogram::WriteAsciiBucketContext(const int64 past,
673 const Count current, 537 const Count current,
674 const int64 remaining, 538 const int64 remaining,
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after
957 821
958 BucketRanges* bucket_ranges = new BucketRanges(ranges.size()); 822 BucketRanges* bucket_ranges = new BucketRanges(ranges.size());
959 for (size_t i = 0; i < ranges.size(); i++) { 823 for (size_t i = 0; i < ranges.size(); i++) {
960 bucket_ranges->set_range(i, ranges[i]); 824 bucket_ranges->set_range(i, ranges[i]);
961 } 825 }
962 bucket_ranges->ResetChecksum(); 826 bucket_ranges->ResetChecksum();
963 return bucket_ranges; 827 return bucket_ranges;
964 } 828 }
965 829
966 } // namespace base 830 } // namespace base
OLDNEW
« no previous file with comments | « base/metrics/histogram.h ('k') | base/metrics/histogram_flattener.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698