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

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

Issue 6385003: Properly order the cc files based off the h files in base/. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 11 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/field_trial.cc ('k') | base/process_posix.cc » ('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) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 46
47 scoped_refptr<Histogram> Histogram::FactoryTimeGet(const std::string& name, 47 scoped_refptr<Histogram> Histogram::FactoryTimeGet(const std::string& name,
48 TimeDelta minimum, 48 TimeDelta minimum,
49 TimeDelta maximum, 49 TimeDelta maximum,
50 size_t bucket_count, 50 size_t bucket_count,
51 Flags flags) { 51 Flags flags) {
52 return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(), 52 return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(),
53 bucket_count, flags); 53 bucket_count, flags);
54 } 54 }
55 55
56 Histogram::Histogram(const std::string& name, Sample minimum,
57 Sample maximum, size_t bucket_count)
58 : histogram_name_(name),
59 declared_min_(minimum),
60 declared_max_(maximum),
61 bucket_count_(bucket_count),
62 flags_(kNoFlags),
63 ranges_(bucket_count + 1, 0),
64 range_checksum_(0),
65 sample_() {
66 Initialize();
67 }
68
69 Histogram::Histogram(const std::string& name, TimeDelta minimum,
70 TimeDelta maximum, size_t bucket_count)
71 : histogram_name_(name),
72 declared_min_(static_cast<int> (minimum.InMilliseconds())),
73 declared_max_(static_cast<int> (maximum.InMilliseconds())),
74 bucket_count_(bucket_count),
75 flags_(kNoFlags),
76 ranges_(bucket_count + 1, 0),
77 range_checksum_(0),
78 sample_() {
79 Initialize();
80 }
81
82 Histogram::~Histogram() {
83 if (StatisticsRecorder::dump_on_exit()) {
84 std::string output;
85 WriteAscii(true, "\n", &output);
86 LOG(INFO) << output;
87 }
88
89 // Just to make sure most derived class did this properly...
90 DCHECK(ValidateBucketRanges());
91 DCHECK(HasValidRangeChecksum());
92 }
93
94 bool Histogram::PrintEmptyBucket(size_t index) const {
95 return true;
96 }
97
98 void Histogram::Add(int value) { 56 void Histogram::Add(int value) {
99 if (value > kSampleType_MAX - 1) 57 if (value > kSampleType_MAX - 1)
100 value = kSampleType_MAX - 1; 58 value = kSampleType_MAX - 1;
101 if (value < 0) 59 if (value < 0)
102 value = 0; 60 value = 0;
103 size_t index = BucketIndex(value); 61 size_t index = BucketIndex(value);
104 DCHECK_GE(value, ranges(index)); 62 DCHECK_GE(value, ranges(index));
105 DCHECK_LT(value, ranges(index + 1)); 63 DCHECK_LT(value, ranges(index + 1));
106 Accumulate(value, 1, index); 64 Accumulate(value, 1, index);
107 } 65 }
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 double current_size = GetBucketSize(current, i); 141 double current_size = GetBucketSize(current, i);
184 if (graph_it) 142 if (graph_it)
185 WriteAsciiBucketGraph(current_size, max_size, output); 143 WriteAsciiBucketGraph(current_size, max_size, output);
186 WriteAsciiBucketContext(past, current, remaining, i, output); 144 WriteAsciiBucketContext(past, current, remaining, i, output);
187 output->append(newline); 145 output->append(newline);
188 past += current; 146 past += current;
189 } 147 }
190 DCHECK_EQ(sample_count, past); 148 DCHECK_EQ(sample_count, past);
191 } 149 }
192 150
193 bool Histogram::ValidateBucketRanges() const { 151 // static
194 // Standard assertions that all bucket ranges should satisfy. 152 std::string Histogram::SerializeHistogramInfo(const Histogram& histogram,
195 DCHECK_EQ(bucket_count_ + 1, ranges_.size()); 153 const SampleSet& snapshot) {
196 DCHECK_EQ(0, ranges_[0]); 154 DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type());
197 DCHECK_EQ(declared_min(), ranges_[1]); 155
198 DCHECK_EQ(declared_max(), ranges_[bucket_count_ - 1]); 156 Pickle pickle;
199 DCHECK_EQ(kSampleType_MAX, ranges_[bucket_count_]); 157 pickle.WriteString(histogram.histogram_name());
158 pickle.WriteInt(histogram.declared_min());
159 pickle.WriteInt(histogram.declared_max());
160 pickle.WriteSize(histogram.bucket_count());
161 pickle.WriteInt(histogram.range_checksum());
162 pickle.WriteInt(histogram.histogram_type());
163 pickle.WriteInt(histogram.flags());
164
165 snapshot.Serialize(&pickle);
166 return std::string(static_cast<const char*>(pickle.data()), pickle.size());
167 }
168
169 // static
170 bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) {
171 if (histogram_info.empty()) {
172 return false;
173 }
174
175 Pickle pickle(histogram_info.data(),
176 static_cast<int>(histogram_info.size()));
177 std::string histogram_name;
178 int declared_min;
179 int declared_max;
180 size_t bucket_count;
181 int range_checksum;
182 int histogram_type;
183 int pickle_flags;
184 SampleSet sample;
185
186 void* iter = NULL;
187 if (!pickle.ReadString(&iter, &histogram_name) ||
188 !pickle.ReadInt(&iter, &declared_min) ||
189 !pickle.ReadInt(&iter, &declared_max) ||
190 !pickle.ReadSize(&iter, &bucket_count) ||
191 !pickle.ReadInt(&iter, &range_checksum) ||
192 !pickle.ReadInt(&iter, &histogram_type) ||
193 !pickle.ReadInt(&iter, &pickle_flags) ||
194 !sample.Histogram::SampleSet::Deserialize(&iter, pickle)) {
195 LOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
196 return false;
197 }
198 DCHECK(pickle_flags & kIPCSerializationSourceFlag);
199 // Since these fields may have come from an untrusted renderer, do additional
200 // checks above and beyond those in Histogram::Initialize()
201 if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min ||
202 INT_MAX / sizeof(Count) <= bucket_count || bucket_count < 2) {
203 LOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
204 return false;
205 }
206
207 Flags flags = static_cast<Flags>(pickle_flags & ~kIPCSerializationSourceFlag);
208
209 DCHECK_NE(NOT_VALID_IN_RENDERER, histogram_type);
210
211 scoped_refptr<Histogram> render_histogram(NULL);
212
213 if (histogram_type == HISTOGRAM) {
214 render_histogram = Histogram::FactoryGet(
215 histogram_name, declared_min, declared_max, bucket_count, flags);
216 } else if (histogram_type == LINEAR_HISTOGRAM) {
217 render_histogram = LinearHistogram::FactoryGet(
218 histogram_name, declared_min, declared_max, bucket_count, flags);
219 } else if (histogram_type == BOOLEAN_HISTOGRAM) {
220 render_histogram = BooleanHistogram::FactoryGet(histogram_name, flags);
221 } else {
222 LOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: "
223 << histogram_type;
224 return false;
225 }
226
227 DCHECK_EQ(render_histogram->declared_min(), declared_min);
228 DCHECK_EQ(render_histogram->declared_max(), declared_max);
229 DCHECK_EQ(render_histogram->bucket_count(), bucket_count);
230 DCHECK_EQ(render_histogram->range_checksum(), range_checksum);
231 DCHECK_EQ(render_histogram->histogram_type(), histogram_type);
232
233 if (render_histogram->flags() & kIPCSerializationSourceFlag) {
234 DVLOG(1) << "Single process mode, histogram observed and not copied: "
235 << histogram_name;
236 } else {
237 DCHECK_EQ(flags & render_histogram->flags(), flags);
238 render_histogram->AddSampleSet(sample);
239 }
240
200 return true; 241 return true;
201 } 242 }
202 243
203 void Histogram::Initialize() { 244 //------------------------------------------------------------------------------
204 sample_.Resize(*this); 245 // Methods for the validating a sample and a related histogram.
205 if (declared_min_ < 1) 246 //------------------------------------------------------------------------------
206 declared_min_ = 1; 247
207 if (declared_max_ > kSampleType_MAX - 1) 248 Histogram::Inconsistencies Histogram::FindCorruption(
208 declared_max_ = kSampleType_MAX - 1; 249 const SampleSet& snapshot) const {
209 DCHECK_LE(declared_min_, declared_max_); 250 int inconsistencies = NO_INCONSISTENCIES;
210 DCHECK_GT(bucket_count_, 1u); 251 Sample previous_range = -1; // Bottom range is always 0.
211 size_t maximal_bucket_count = declared_max_ - declared_min_ + 2; 252 Sample checksum = 0;
212 DCHECK_LE(bucket_count_, maximal_bucket_count); 253 int64 count = 0;
213 DCHECK_EQ(0, ranges_[0]); 254 for (size_t index = 0; index < bucket_count(); ++index) {
214 ranges_[bucket_count_] = kSampleType_MAX; 255 count += snapshot.counts(index);
215 InitializeBucketRange(); 256 int new_range = ranges(index);
257 checksum += new_range;
258 if (previous_range >= new_range)
259 inconsistencies |= BUCKET_ORDER_ERROR;
260 previous_range = new_range;
261 }
262
263 if (checksum != range_checksum_)
264 inconsistencies |= RANGE_CHECKSUM_ERROR;
265
266 int64 delta64 = snapshot.redundant_count() - count;
267 if (delta64 != 0) {
268 int delta = static_cast<int>(delta64);
269 if (delta != delta64)
270 delta = INT_MAX; // Flag all giant errors as INT_MAX.
271 // Since snapshots of histograms are taken asynchronously relative to
272 // sampling (and snapped from different threads), it is pretty likely that
273 // we'll catch a redundant count that doesn't match the sample count. We
274 // allow for a certain amount of slop before flagging this as an
275 // inconsistency. Even with an inconsistency, we'll snapshot it again (for
276 // UMA in about a half hour, so we'll eventually get the data, if it was
277 // not the result of a corruption. If histograms show that 1 is "too tight"
278 // then we may try to use 2 or 3 for this slop value.
279 const int kCommonRaceBasedCountMismatch = 1;
280 if (delta > 0) {
281 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta);
282 if (delta > kCommonRaceBasedCountMismatch)
283 inconsistencies |= COUNT_HIGH_ERROR;
284 } else {
285 DCHECK_GT(0, delta);
286 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta);
287 if (-delta > kCommonRaceBasedCountMismatch)
288 inconsistencies |= COUNT_LOW_ERROR;
289 }
290 }
291 return static_cast<Inconsistencies>(inconsistencies);
292 }
293
294 Histogram::ClassType Histogram::histogram_type() const {
295 return HISTOGRAM;
296 }
297
298 Histogram::Sample Histogram::ranges(size_t i) const {
299 return ranges_[i];
300 }
301
302 size_t Histogram::bucket_count() const {
303 return bucket_count_;
304 }
305
306 // Do a safe atomic snapshot of sample data.
307 // This implementation assumes we are on a safe single thread.
308 void Histogram::SnapshotSample(SampleSet* sample) const {
309 // Note locking not done in this version!!!
310 *sample = sample_;
311 }
312
313 bool Histogram::HasConstructorArguments(Sample minimum,
314 Sample maximum,
315 size_t bucket_count) {
316 return ((minimum == declared_min_) && (maximum == declared_max_) &&
317 (bucket_count == bucket_count_));
318 }
319
320 bool Histogram::HasConstructorTimeDeltaArguments(TimeDelta minimum,
321 TimeDelta maximum,
322 size_t bucket_count) {
323 return ((minimum.InMilliseconds() == declared_min_) &&
324 (maximum.InMilliseconds() == declared_max_) &&
325 (bucket_count == bucket_count_));
326 }
327
328 Histogram::Histogram(const std::string& name, Sample minimum,
329 Sample maximum, size_t bucket_count)
330 : histogram_name_(name),
331 declared_min_(minimum),
332 declared_max_(maximum),
333 bucket_count_(bucket_count),
334 flags_(kNoFlags),
335 ranges_(bucket_count + 1, 0),
336 range_checksum_(0),
337 sample_() {
338 Initialize();
339 }
340
341 Histogram::Histogram(const std::string& name, TimeDelta minimum,
342 TimeDelta maximum, size_t bucket_count)
343 : histogram_name_(name),
344 declared_min_(static_cast<int> (minimum.InMilliseconds())),
345 declared_max_(static_cast<int> (maximum.InMilliseconds())),
346 bucket_count_(bucket_count),
347 flags_(kNoFlags),
348 ranges_(bucket_count + 1, 0),
349 range_checksum_(0),
350 sample_() {
351 Initialize();
352 }
353
354 Histogram::~Histogram() {
355 if (StatisticsRecorder::dump_on_exit()) {
356 std::string output;
357 WriteAscii(true, "\n", &output);
358 LOG(INFO) << output;
359 }
360
361 // Just to make sure most derived class did this properly...
216 DCHECK(ValidateBucketRanges()); 362 DCHECK(ValidateBucketRanges());
217 StatisticsRecorder::Register(this); 363 DCHECK(HasValidRangeChecksum());
364 }
365
366 bool Histogram::PrintEmptyBucket(size_t index) const {
367 return true;
218 } 368 }
219 369
220 // Calculate what range of values are held in each bucket. 370 // Calculate what range of values are held in each bucket.
221 // We have to be careful that we don't pick a ratio between starting points in 371 // We have to be careful that we don't pick a ratio between starting points in
222 // consecutive buckets that is sooo small, that the integer bounds are the same 372 // consecutive buckets that is sooo small, that the integer bounds are the same
223 // (effectively making one bucket get no values). We need to avoid: 373 // (effectively making one bucket get no values). We need to avoid:
224 // ranges_[i] == ranges_[i + 1] 374 // ranges_[i] == ranges_[i + 1]
225 // To avoid that, we just do a fine-grained bucket width as far as we need to 375 // To avoid that, we just do a fine-grained bucket width as far as we need to
226 // until we get a ratio that moves us along at least 2 units at a time. From 376 // until we get a ratio that moves us along at least 2 units at a time. From
227 // that bucket onward we do use the exponential growth of buckets. 377 // that bucket onward we do use the exponential growth of buckets.
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 double denominator = ranges(i + 1) - ranges(i); 438 double denominator = ranges(i + 1) - ranges(i);
289 if (denominator > kTransitionWidth) 439 if (denominator > kTransitionWidth)
290 denominator = kTransitionWidth; // Stop trying to normalize. 440 denominator = kTransitionWidth; // Stop trying to normalize.
291 return current/denominator; 441 return current/denominator;
292 } 442 }
293 443
294 void Histogram::ResetRangeChecksum() { 444 void Histogram::ResetRangeChecksum() {
295 range_checksum_ = CalculateRangeChecksum(); 445 range_checksum_ = CalculateRangeChecksum();
296 } 446 }
297 447
448 const std::string Histogram::GetAsciiBucketRange(size_t i) const {
449 std::string result;
450 if (kHexRangePrintingFlag & flags_)
451 StringAppendF(&result, "%#x", ranges(i));
452 else
453 StringAppendF(&result, "%d", ranges(i));
454 return result;
455 }
456
457 // Update histogram data with new sample.
458 void Histogram::Accumulate(Sample value, Count count, size_t index) {
459 // Note locking not done in this version!!!
460 sample_.Accumulate(value, count, index);
461 }
462
463 void Histogram::SetBucketRange(size_t i, Sample value) {
464 DCHECK_GT(bucket_count_, i);
465 ranges_[i] = value;
466 }
467
468 bool Histogram::ValidateBucketRanges() const {
469 // Standard assertions that all bucket ranges should satisfy.
470 DCHECK_EQ(bucket_count_ + 1, ranges_.size());
471 DCHECK_EQ(0, ranges_[0]);
472 DCHECK_EQ(declared_min(), ranges_[1]);
473 DCHECK_EQ(declared_max(), ranges_[bucket_count_ - 1]);
474 DCHECK_EQ(kSampleType_MAX, ranges_[bucket_count_]);
475 return true;
476 }
477
478 void Histogram::Initialize() {
479 sample_.Resize(*this);
480 if (declared_min_ < 1)
481 declared_min_ = 1;
482 if (declared_max_ > kSampleType_MAX - 1)
483 declared_max_ = kSampleType_MAX - 1;
484 DCHECK_LE(declared_min_, declared_max_);
485 DCHECK_GT(bucket_count_, 1u);
486 size_t maximal_bucket_count = declared_max_ - declared_min_ + 2;
487 DCHECK_LE(bucket_count_, maximal_bucket_count);
488 DCHECK_EQ(0, ranges_[0]);
489 ranges_[bucket_count_] = kSampleType_MAX;
490 InitializeBucketRange();
491 DCHECK(ValidateBucketRanges());
492 StatisticsRecorder::Register(this);
493 }
494
298 bool Histogram::HasValidRangeChecksum() const { 495 bool Histogram::HasValidRangeChecksum() const {
299 return CalculateRangeChecksum() == range_checksum_; 496 return CalculateRangeChecksum() == range_checksum_;
300 } 497 }
301 498
302 Histogram::Sample Histogram::CalculateRangeChecksum() const { 499 Histogram::Sample Histogram::CalculateRangeChecksum() const {
303 DCHECK_EQ(ranges_.size(), bucket_count() + 1); 500 DCHECK_EQ(ranges_.size(), bucket_count() + 1);
304 Sample checksum = 0; 501 Sample checksum = 0;
305 for (size_t index = 0; index < bucket_count(); ++index) { 502 for (size_t index = 0; index < bucket_count(); ++index) {
306 checksum += ranges(index); 503 checksum += ranges(index);
307 } 504 }
308 return checksum; 505 return checksum;
309 } 506 }
310 507
311 //------------------------------------------------------------------------------ 508 //------------------------------------------------------------------------------
312 // The following two methods can be overridden to provide a thread safe
313 // version of this class. The cost of locking is low... but an error in each
314 // of these methods has minimal impact. For now, I'll leave this unlocked,
315 // and I don't believe I can loose more than a count or two.
316 // The vectors are NOT reallocated, so there is no risk of them moving around.
317
318 // Update histogram data with new sample.
319 void Histogram::Accumulate(Sample value, Count count, size_t index) {
320 // Note locking not done in this version!!!
321 sample_.Accumulate(value, count, index);
322 }
323
324 // Do a safe atomic snapshot of sample data.
325 // This implementation assumes we are on a safe single thread.
326 void Histogram::SnapshotSample(SampleSet* sample) const {
327 // Note locking not done in this version!!!
328 *sample = sample_;
329 }
330
331 bool Histogram::HasConstructorArguments(Sample minimum,
332 Sample maximum,
333 size_t bucket_count) {
334 return ((minimum == declared_min_) && (maximum == declared_max_) &&
335 (bucket_count == bucket_count_));
336 }
337
338 bool Histogram::HasConstructorTimeDeltaArguments(TimeDelta minimum,
339 TimeDelta maximum,
340 size_t bucket_count) {
341 return ((minimum.InMilliseconds() == declared_min_) &&
342 (maximum.InMilliseconds() == declared_max_) &&
343 (bucket_count == bucket_count_));
344 }
345
346 //------------------------------------------------------------------------------
347 // Accessor methods
348
349 void Histogram::SetBucketRange(size_t i, Sample value) {
350 DCHECK_GT(bucket_count_, i);
351 ranges_[i] = value;
352 }
353
354 //------------------------------------------------------------------------------
355 // Private methods 509 // Private methods
356 510
357 double Histogram::GetPeakBucketSize(const SampleSet& snapshot) const { 511 double Histogram::GetPeakBucketSize(const SampleSet& snapshot) const {
358 double max = 0; 512 double max = 0;
359 for (size_t i = 0; i < bucket_count() ; ++i) { 513 for (size_t i = 0; i < bucket_count() ; ++i) {
360 double current_size = GetBucketSize(snapshot.counts(i), i); 514 double current_size = GetBucketSize(snapshot.counts(i), i);
361 if (current_size > max) 515 if (current_size > max)
362 max = current_size; 516 max = current_size;
363 } 517 }
364 return max; 518 return max;
(...skipping 28 matching lines...) Expand all
393 const size_t i, 547 const size_t i,
394 std::string* output) const { 548 std::string* output) const {
395 double scaled_sum = (past + current + remaining) / 100.0; 549 double scaled_sum = (past + current + remaining) / 100.0;
396 WriteAsciiBucketValue(current, scaled_sum, output); 550 WriteAsciiBucketValue(current, scaled_sum, output);
397 if (0 < i) { 551 if (0 < i) {
398 double percentage = past / scaled_sum; 552 double percentage = past / scaled_sum;
399 StringAppendF(output, " {%3.1f%%}", percentage); 553 StringAppendF(output, " {%3.1f%%}", percentage);
400 } 554 }
401 } 555 }
402 556
403 const std::string Histogram::GetAsciiBucketRange(size_t i) const {
404 std::string result;
405 if (kHexRangePrintingFlag & flags_)
406 StringAppendF(&result, "%#x", ranges(i));
407 else
408 StringAppendF(&result, "%d", ranges(i));
409 return result;
410 }
411
412 void Histogram::WriteAsciiBucketValue(Count current, double scaled_sum, 557 void Histogram::WriteAsciiBucketValue(Count current, double scaled_sum,
413 std::string* output) const { 558 std::string* output) const {
414 StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum); 559 StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum);
415 } 560 }
416 561
417 void Histogram::WriteAsciiBucketGraph(double current_size, double max_size, 562 void Histogram::WriteAsciiBucketGraph(double current_size, double max_size,
418 std::string* output) const { 563 std::string* output) const {
419 const int k_line_length = 72; // Maximal horizontal width of graph. 564 const int k_line_length = 72; // Maximal horizontal width of graph.
420 int x_count = static_cast<int>(k_line_length * (current_size / max_size) 565 int x_count = static_cast<int>(k_line_length * (current_size / max_size)
421 + 0.5); 566 + 0.5);
422 int x_remainder = k_line_length - x_count; 567 int x_remainder = k_line_length - x_count;
423 568
424 while (0 < x_count--) 569 while (0 < x_count--)
425 output->append("-"); 570 output->append("-");
426 output->append("O"); 571 output->append("O");
427 while (0 < x_remainder--) 572 while (0 < x_remainder--)
428 output->append(" "); 573 output->append(" ");
429 } 574 }
430 575
431 // static
432 std::string Histogram::SerializeHistogramInfo(const Histogram& histogram,
433 const SampleSet& snapshot) {
434 DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type());
435
436 Pickle pickle;
437 pickle.WriteString(histogram.histogram_name());
438 pickle.WriteInt(histogram.declared_min());
439 pickle.WriteInt(histogram.declared_max());
440 pickle.WriteSize(histogram.bucket_count());
441 pickle.WriteInt(histogram.range_checksum());
442 pickle.WriteInt(histogram.histogram_type());
443 pickle.WriteInt(histogram.flags());
444
445 snapshot.Serialize(&pickle);
446 return std::string(static_cast<const char*>(pickle.data()), pickle.size());
447 }
448
449 // static
450 bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) {
451 if (histogram_info.empty()) {
452 return false;
453 }
454
455 Pickle pickle(histogram_info.data(),
456 static_cast<int>(histogram_info.size()));
457 std::string histogram_name;
458 int declared_min;
459 int declared_max;
460 size_t bucket_count;
461 int range_checksum;
462 int histogram_type;
463 int pickle_flags;
464 SampleSet sample;
465
466 void* iter = NULL;
467 if (!pickle.ReadString(&iter, &histogram_name) ||
468 !pickle.ReadInt(&iter, &declared_min) ||
469 !pickle.ReadInt(&iter, &declared_max) ||
470 !pickle.ReadSize(&iter, &bucket_count) ||
471 !pickle.ReadInt(&iter, &range_checksum) ||
472 !pickle.ReadInt(&iter, &histogram_type) ||
473 !pickle.ReadInt(&iter, &pickle_flags) ||
474 !sample.Histogram::SampleSet::Deserialize(&iter, pickle)) {
475 LOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
476 return false;
477 }
478 DCHECK(pickle_flags & kIPCSerializationSourceFlag);
479 // Since these fields may have come from an untrusted renderer, do additional
480 // checks above and beyond those in Histogram::Initialize()
481 if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min ||
482 INT_MAX / sizeof(Count) <= bucket_count || bucket_count < 2) {
483 LOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
484 return false;
485 }
486
487 Flags flags = static_cast<Flags>(pickle_flags & ~kIPCSerializationSourceFlag);
488
489 DCHECK_NE(NOT_VALID_IN_RENDERER, histogram_type);
490
491 scoped_refptr<Histogram> render_histogram(NULL);
492
493 if (histogram_type == HISTOGRAM) {
494 render_histogram = Histogram::FactoryGet(
495 histogram_name, declared_min, declared_max, bucket_count, flags);
496 } else if (histogram_type == LINEAR_HISTOGRAM) {
497 render_histogram = LinearHistogram::FactoryGet(
498 histogram_name, declared_min, declared_max, bucket_count, flags);
499 } else if (histogram_type == BOOLEAN_HISTOGRAM) {
500 render_histogram = BooleanHistogram::FactoryGet(histogram_name, flags);
501 } else {
502 LOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: "
503 << histogram_type;
504 return false;
505 }
506
507 DCHECK_EQ(render_histogram->declared_min(), declared_min);
508 DCHECK_EQ(render_histogram->declared_max(), declared_max);
509 DCHECK_EQ(render_histogram->bucket_count(), bucket_count);
510 DCHECK_EQ(render_histogram->range_checksum(), range_checksum);
511 DCHECK_EQ(render_histogram->histogram_type(), histogram_type);
512
513 if (render_histogram->flags() & kIPCSerializationSourceFlag) {
514 DVLOG(1) << "Single process mode, histogram observed and not copied: "
515 << histogram_name;
516 } else {
517 DCHECK_EQ(flags & render_histogram->flags(), flags);
518 render_histogram->AddSampleSet(sample);
519 }
520
521 return true;
522 }
523
524 //------------------------------------------------------------------------------
525 // Methods for the validating a sample and a related histogram.
526 //------------------------------------------------------------------------------
527
528 Histogram::Inconsistencies Histogram::FindCorruption(
529 const SampleSet& snapshot) const {
530 int inconsistencies = NO_INCONSISTENCIES;
531 Sample previous_range = -1; // Bottom range is always 0.
532 Sample checksum = 0;
533 int64 count = 0;
534 for (size_t index = 0; index < bucket_count(); ++index) {
535 count += snapshot.counts(index);
536 int new_range = ranges(index);
537 checksum += new_range;
538 if (previous_range >= new_range)
539 inconsistencies |= BUCKET_ORDER_ERROR;
540 previous_range = new_range;
541 }
542
543 if (checksum != range_checksum_)
544 inconsistencies |= RANGE_CHECKSUM_ERROR;
545
546 int64 delta64 = snapshot.redundant_count() - count;
547 if (delta64 != 0) {
548 int delta = static_cast<int>(delta64);
549 if (delta != delta64)
550 delta = INT_MAX; // Flag all giant errors as INT_MAX.
551 // Since snapshots of histograms are taken asynchronously relative to
552 // sampling (and snapped from different threads), it is pretty likely that
553 // we'll catch a redundant count that doesn't match the sample count. We
554 // allow for a certain amount of slop before flagging this as an
555 // inconsistency. Even with an inconsistency, we'll snapshot it again (for
556 // UMA in about a half hour, so we'll eventually get the data, if it was
557 // not the result of a corruption. If histograms show that 1 is "too tight"
558 // then we may try to use 2 or 3 for this slop value.
559 const int kCommonRaceBasedCountMismatch = 1;
560 if (delta > 0) {
561 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta);
562 if (delta > kCommonRaceBasedCountMismatch)
563 inconsistencies |= COUNT_HIGH_ERROR;
564 } else {
565 DCHECK_GT(0, delta);
566 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta);
567 if (-delta > kCommonRaceBasedCountMismatch)
568 inconsistencies |= COUNT_LOW_ERROR;
569 }
570 }
571 return static_cast<Inconsistencies>(inconsistencies);
572 }
573
574 Histogram::ClassType Histogram::histogram_type() const {
575 return HISTOGRAM;
576 }
577
578 Histogram::Sample Histogram::ranges(size_t i) const {
579 return ranges_[i];
580 }
581
582 size_t Histogram::bucket_count() const {
583 return bucket_count_;
584 }
585
586 //------------------------------------------------------------------------------ 576 //------------------------------------------------------------------------------
587 // Methods for the Histogram::SampleSet class 577 // Methods for the Histogram::SampleSet class
588 //------------------------------------------------------------------------------ 578 //------------------------------------------------------------------------------
589 579
590 Histogram::SampleSet::SampleSet() 580 Histogram::SampleSet::SampleSet()
591 : counts_(), 581 : counts_(),
592 sum_(0), 582 sum_(0),
593 square_sum_(0), 583 square_sum_(0),
594 redundant_count_(0) { 584 redundant_count_(0) {
595 } 585 }
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
693 } 683 }
694 DCHECK_EQ(count, redundant_count_); 684 DCHECK_EQ(count, redundant_count_);
695 return count == redundant_count_; 685 return count == redundant_count_;
696 } 686 }
697 687
698 //------------------------------------------------------------------------------ 688 //------------------------------------------------------------------------------
699 // LinearHistogram: This histogram uses a traditional set of evenly spaced 689 // LinearHistogram: This histogram uses a traditional set of evenly spaced
700 // buckets. 690 // buckets.
701 //------------------------------------------------------------------------------ 691 //------------------------------------------------------------------------------
702 692
693 LinearHistogram::~LinearHistogram() {
694 }
695
703 scoped_refptr<Histogram> LinearHistogram::FactoryGet(const std::string& name, 696 scoped_refptr<Histogram> LinearHistogram::FactoryGet(const std::string& name,
704 Sample minimum, 697 Sample minimum,
705 Sample maximum, 698 Sample maximum,
706 size_t bucket_count, 699 size_t bucket_count,
707 Flags flags) { 700 Flags flags) {
708 scoped_refptr<Histogram> histogram(NULL); 701 scoped_refptr<Histogram> histogram(NULL);
709 702
710 if (minimum < 1) 703 if (minimum < 1)
711 minimum = 1; 704 minimum = 1;
712 if (maximum > kSampleType_MAX - 1) 705 if (maximum > kSampleType_MAX - 1)
(...skipping 13 matching lines...) Expand all
726 scoped_refptr<Histogram> LinearHistogram::FactoryTimeGet( 719 scoped_refptr<Histogram> LinearHistogram::FactoryTimeGet(
727 const std::string& name, 720 const std::string& name,
728 TimeDelta minimum, 721 TimeDelta minimum,
729 TimeDelta maximum, 722 TimeDelta maximum,
730 size_t bucket_count, 723 size_t bucket_count,
731 Flags flags) { 724 Flags flags) {
732 return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(), 725 return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(),
733 bucket_count, flags); 726 bucket_count, flags);
734 } 727 }
735 728
736 LinearHistogram::~LinearHistogram() { 729 Histogram::ClassType LinearHistogram::histogram_type() const {
730 return LINEAR_HISTOGRAM;
731 }
732
733 void LinearHistogram::SetRangeDescriptions(
734 const DescriptionPair descriptions[]) {
735 for (int i =0; descriptions[i].description; ++i) {
736 bucket_description_[descriptions[i].sample] = descriptions[i].description;
737 }
737 } 738 }
738 739
739 LinearHistogram::LinearHistogram(const std::string& name, 740 LinearHistogram::LinearHistogram(const std::string& name,
740 Sample minimum, 741 Sample minimum,
741 Sample maximum, 742 Sample maximum,
742 size_t bucket_count) 743 size_t bucket_count)
743 : Histogram(name, minimum >= 1 ? minimum : 1, maximum, bucket_count) { 744 : Histogram(name, minimum >= 1 ? minimum : 1, maximum, bucket_count) {
744 InitializeBucketRange(); 745 InitializeBucketRange();
745 DCHECK(ValidateBucketRanges()); 746 DCHECK(ValidateBucketRanges());
746 } 747 }
747 748
748 LinearHistogram::LinearHistogram(const std::string& name, 749 LinearHistogram::LinearHistogram(const std::string& name,
749 TimeDelta minimum, 750 TimeDelta minimum,
750 TimeDelta maximum, 751 TimeDelta maximum,
751 size_t bucket_count) 752 size_t bucket_count)
752 : Histogram(name, minimum >= TimeDelta::FromMilliseconds(1) ? 753 : Histogram(name, minimum >= TimeDelta::FromMilliseconds(1) ?
753 minimum : TimeDelta::FromMilliseconds(1), 754 minimum : TimeDelta::FromMilliseconds(1),
754 maximum, bucket_count) { 755 maximum, bucket_count) {
755 // Do a "better" (different) job at init than a base classes did... 756 // Do a "better" (different) job at init than a base classes did...
756 InitializeBucketRange(); 757 InitializeBucketRange();
757 DCHECK(ValidateBucketRanges()); 758 DCHECK(ValidateBucketRanges());
758 } 759 }
759 760
760 Histogram::ClassType LinearHistogram::histogram_type() const {
761 return LINEAR_HISTOGRAM;
762 }
763
764 void LinearHistogram::SetRangeDescriptions(
765 const DescriptionPair descriptions[]) {
766 for (int i =0; descriptions[i].description; ++i) {
767 bucket_description_[descriptions[i].sample] = descriptions[i].description;
768 }
769 }
770
771 const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const {
772 int range = ranges(i);
773 BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
774 if (it == bucket_description_.end())
775 return Histogram::GetAsciiBucketRange(i);
776 return it->second;
777 }
778
779 bool LinearHistogram::PrintEmptyBucket(size_t index) const {
780 return bucket_description_.find(ranges(index)) == bucket_description_.end();
781 }
782
783
784 void LinearHistogram::InitializeBucketRange() { 761 void LinearHistogram::InitializeBucketRange() {
785 DCHECK_GT(declared_min(), 0); // 0 is the underflow bucket here. 762 DCHECK_GT(declared_min(), 0); // 0 is the underflow bucket here.
786 double min = declared_min(); 763 double min = declared_min();
787 double max = declared_max(); 764 double max = declared_max();
788 size_t i; 765 size_t i;
789 for (i = 1; i < bucket_count(); ++i) { 766 for (i = 1; i < bucket_count(); ++i) {
790 double linear_range = (min * (bucket_count() -1 - i) + max * (i - 1)) / 767 double linear_range = (min * (bucket_count() -1 - i) + max * (i - 1)) /
791 (bucket_count() - 2); 768 (bucket_count() - 2);
792 SetBucketRange(i, static_cast<int> (linear_range + 0.5)); 769 SetBucketRange(i, static_cast<int> (linear_range + 0.5));
793 } 770 }
794 ResetRangeChecksum(); 771 ResetRangeChecksum();
795 } 772 }
796 773
797 double LinearHistogram::GetBucketSize(Count current, size_t i) const { 774 double LinearHistogram::GetBucketSize(Count current, size_t i) const {
798 DCHECK_GT(ranges(i + 1), ranges(i)); 775 DCHECK_GT(ranges(i + 1), ranges(i));
799 // Adjacent buckets with different widths would have "surprisingly" many (few) 776 // Adjacent buckets with different widths would have "surprisingly" many (few)
800 // samples in a histogram if we didn't normalize this way. 777 // samples in a histogram if we didn't normalize this way.
801 double denominator = ranges(i + 1) - ranges(i); 778 double denominator = ranges(i + 1) - ranges(i);
802 return current/denominator; 779 return current/denominator;
803 } 780 }
804 781
782 const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const {
783 int range = ranges(i);
784 BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
785 if (it == bucket_description_.end())
786 return Histogram::GetAsciiBucketRange(i);
787 return it->second;
788 }
789
790 bool LinearHistogram::PrintEmptyBucket(size_t index) const {
791 return bucket_description_.find(ranges(index)) == bucket_description_.end();
792 }
793
794
805 //------------------------------------------------------------------------------ 795 //------------------------------------------------------------------------------
806 // This section provides implementation for BooleanHistogram. 796 // This section provides implementation for BooleanHistogram.
807 //------------------------------------------------------------------------------ 797 //------------------------------------------------------------------------------
808 798
809 scoped_refptr<Histogram> BooleanHistogram::FactoryGet(const std::string& name, 799 scoped_refptr<Histogram> BooleanHistogram::FactoryGet(const std::string& name,
810 Flags flags) { 800 Flags flags) {
811 scoped_refptr<Histogram> histogram(NULL); 801 scoped_refptr<Histogram> histogram(NULL);
812 802
813 if (!StatisticsRecorder::FindHistogram(name, &histogram)) { 803 if (!StatisticsRecorder::FindHistogram(name, &histogram)) {
814 histogram = new BooleanHistogram(name); 804 histogram = new BooleanHistogram(name);
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after
1053 } 1043 }
1054 1044
1055 // static 1045 // static
1056 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL; 1046 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL;
1057 // static 1047 // static
1058 base::Lock* StatisticsRecorder::lock_ = NULL; 1048 base::Lock* StatisticsRecorder::lock_ = NULL;
1059 // static 1049 // static
1060 bool StatisticsRecorder::dump_on_exit_ = false; 1050 bool StatisticsRecorder::dump_on_exit_ = false;
1061 1051
1062 } // namespace base 1052 } // namespace base
OLDNEW
« no previous file with comments | « base/metrics/field_trial.cc ('k') | base/process_posix.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698