| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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/histogram.h" | 10 #include "base/histogram.h" |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 46 bucket_count_(bucket_count), | 46 bucket_count_(bucket_count), |
| 47 flags_(0), | 47 flags_(0), |
| 48 ranges_(bucket_count + 1, 0), | 48 ranges_(bucket_count + 1, 0), |
| 49 sample_(), | 49 sample_(), |
| 50 registered_(false) { | 50 registered_(false) { |
| 51 Initialize(); | 51 Initialize(); |
| 52 } | 52 } |
| 53 | 53 |
| 54 Histogram::~Histogram() { | 54 Histogram::~Histogram() { |
| 55 if (registered_) | 55 if (registered_) |
| 56 StatisticsRecorder::UnRegister(*this); | 56 StatisticsRecorder::UnRegister(this); |
| 57 // Just to make sure most derived class did this properly... | 57 // Just to make sure most derived class did this properly... |
| 58 DCHECK(ValidateBucketRanges()); | 58 DCHECK(ValidateBucketRanges()); |
| 59 } | 59 } |
| 60 | 60 |
| 61 | |
| 62 // Hooks to override stats counter methods. This ensures that we gather all | 61 // Hooks to override stats counter methods. This ensures that we gather all |
| 63 // input the stats counter sees. | 62 // input the stats counter sees. |
| 64 void Histogram::Add(int value) { | 63 void Histogram::Add(int value) { |
| 65 if (!registered_) | 64 if (!registered_) |
| 66 registered_ = StatisticsRecorder::Register(*this); | 65 registered_ = StatisticsRecorder::Register(this); |
| 67 if (value >= kSampleType_MAX) | 66 if (value >= kSampleType_MAX) |
| 68 value = kSampleType_MAX - 1; | 67 value = kSampleType_MAX - 1; |
| 69 StatsRate::Add(value); | 68 StatsRate::Add(value); |
| 70 if (value < 0) | 69 if (value < 0) |
| 71 value = 0; | 70 value = 0; |
| 72 size_t index = BucketIndex(value); | 71 size_t index = BucketIndex(value); |
| 73 DCHECK(value >= ranges(index)); | 72 DCHECK(value >= ranges(index)); |
| 74 DCHECK(value < ranges(index + 1)); | 73 DCHECK(value < ranges(index + 1)); |
| 75 Accumulate(value, 1, index); | 74 Accumulate(value, 1, index); |
| 76 } | 75 } |
| 77 | 76 |
| 77 void Histogram::AddSampleSet(const SampleSet& sample) { |
| 78 sample_.Add(sample); |
| 79 } |
| 80 |
| 78 // The following methods provide a graphical histogram display. | 81 // The following methods provide a graphical histogram display. |
| 79 void Histogram::WriteHTMLGraph(std::string* output) const { | 82 void Histogram::WriteHTMLGraph(std::string* output) const { |
| 80 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc. | 83 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc. |
| 81 output->append("<PRE>"); | 84 output->append("<PRE>"); |
| 82 WriteAscii(true, "<br>", output); | 85 WriteAscii(true, "<br>", output); |
| 83 output->append("</PRE>"); | 86 output->append("</PRE>"); |
| 84 } | 87 } |
| 85 | 88 |
| 86 void Histogram::WriteAscii(bool graph_it, const std::string& newline, | 89 void Histogram::WriteAscii(bool graph_it, const std::string& newline, |
| 87 std::string* output) const { | 90 std::string* output) const { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 98 double max_size = 0; | 101 double max_size = 0; |
| 99 if (graph_it) | 102 if (graph_it) |
| 100 max_size = GetPeakBucketSize(snapshot); | 103 max_size = GetPeakBucketSize(snapshot); |
| 101 | 104 |
| 102 // Calculate space needed to print bucket range numbers. Leave room to print | 105 // Calculate space needed to print bucket range numbers. Leave room to print |
| 103 // nearly the largest bucket range without sliding over the histogram. | 106 // nearly the largest bucket range without sliding over the histogram. |
| 104 size_t largest_non_empty_bucket = bucket_count() - 1; | 107 size_t largest_non_empty_bucket = bucket_count() - 1; |
| 105 while (0 == snapshot.counts(largest_non_empty_bucket)) { | 108 while (0 == snapshot.counts(largest_non_empty_bucket)) { |
| 106 if (0 == largest_non_empty_bucket) | 109 if (0 == largest_non_empty_bucket) |
| 107 break; // All buckets are empty. | 110 break; // All buckets are empty. |
| 108 largest_non_empty_bucket--; | 111 --largest_non_empty_bucket; |
| 109 } | 112 } |
| 110 | 113 |
| 111 // Calculate largest print width needed for any of our bucket range displays. | 114 // Calculate largest print width needed for any of our bucket range displays. |
| 112 size_t print_width = 1; | 115 size_t print_width = 1; |
| 113 for (size_t i = 0; i < bucket_count(); ++i) { | 116 for (size_t i = 0; i < bucket_count(); ++i) { |
| 114 if (snapshot.counts(i)) { | 117 if (snapshot.counts(i)) { |
| 115 size_t width = GetAsciiBucketRange(i).size() + 1; | 118 size_t width = GetAsciiBucketRange(i).size() + 1; |
| 116 if (width > print_width) | 119 if (width > print_width) |
| 117 print_width = width; | 120 print_width = width; |
| 118 } | 121 } |
| 119 } | 122 } |
| 120 | 123 |
| 121 int64 remaining = sample_count; | 124 int64 remaining = sample_count; |
| 122 int64 past = 0; | 125 int64 past = 0; |
| 123 // Output the actual histogram graph. | 126 // Output the actual histogram graph. |
| 124 for (size_t i = 0; i < bucket_count(); i++) { | 127 for (size_t i = 0; i < bucket_count(); ++i) { |
| 125 Count current = snapshot.counts(i); | 128 Count current = snapshot.counts(i); |
| 126 if (!current && !PrintEmptyBucket(i)) | 129 if (!current && !PrintEmptyBucket(i)) |
| 127 continue; | 130 continue; |
| 128 remaining -= current; | 131 remaining -= current; |
| 129 StringAppendF(output, "%#*s ", print_width, GetAsciiBucketRange(i).c_str()); | 132 StringAppendF(output, "%#*s ", print_width, GetAsciiBucketRange(i).c_str()); |
| 130 if (0 == current && i < bucket_count() - 1 && 0 == snapshot.counts(i + 1)) { | 133 if (0 == current && i < bucket_count() - 1 && 0 == snapshot.counts(i + 1)) { |
| 131 while (i < bucket_count() - 1 && 0 == snapshot.counts(i + 1)) | 134 while (i < bucket_count() - 1 && 0 == snapshot.counts(i + 1)) |
| 132 i++; | 135 ++i; |
| 133 output->append("... "); | 136 output->append("... "); |
| 134 output->append(newline); | 137 output->append(newline); |
| 135 continue; // No reason to plot emptiness. | 138 continue; // No reason to plot emptiness. |
| 136 } | 139 } |
| 137 double current_size = GetBucketSize(current, i); | 140 double current_size = GetBucketSize(current, i); |
| 138 if (graph_it) | 141 if (graph_it) |
| 139 WriteAsciiBucketGraph(current_size, max_size, output); | 142 WriteAsciiBucketGraph(current_size, max_size, output); |
| 140 WriteAsciiBucketContext(past, current, remaining, i, output); | 143 WriteAsciiBucketContext(past, current, remaining, i, output); |
| 141 output->append(newline); | 144 output->append(newline); |
| 142 past += current; | 145 past += current; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 162 declared_max_ = kSampleType_MAX - 1; | 165 declared_max_ = kSampleType_MAX - 1; |
| 163 DCHECK(declared_min_ > 0); // We provide underflow bucket. | 166 DCHECK(declared_min_ > 0); // We provide underflow bucket. |
| 164 DCHECK(declared_min_ <= declared_max_); | 167 DCHECK(declared_min_ <= declared_max_); |
| 165 DCHECK(1 < bucket_count_); | 168 DCHECK(1 < bucket_count_); |
| 166 size_t maximal_bucket_count = declared_max_ - declared_min_ + 2; | 169 size_t maximal_bucket_count = declared_max_ - declared_min_ + 2; |
| 167 DCHECK(bucket_count_ <= maximal_bucket_count); | 170 DCHECK(bucket_count_ <= maximal_bucket_count); |
| 168 DCHECK(0 == ranges_[0]); | 171 DCHECK(0 == ranges_[0]); |
| 169 ranges_[bucket_count_] = kSampleType_MAX; | 172 ranges_[bucket_count_] = kSampleType_MAX; |
| 170 InitializeBucketRange(); | 173 InitializeBucketRange(); |
| 171 DCHECK(ValidateBucketRanges()); | 174 DCHECK(ValidateBucketRanges()); |
| 172 registered_ = StatisticsRecorder::Register(*this); | 175 registered_ = StatisticsRecorder::Register(this); |
| 173 } | 176 } |
| 174 | 177 |
| 175 // Calculate what range of values are held in each bucket. | 178 // Calculate what range of values are held in each bucket. |
| 176 // We have to be careful that we don't pick a ratio between starting points in | 179 // We have to be careful that we don't pick a ratio between starting points in |
| 177 // consecutive buckets that is sooo small, that the integer bounds are the same | 180 // consecutive buckets that is sooo small, that the integer bounds are the same |
| 178 // (effectively making one bucket get no values). We need to avoid: | 181 // (effectively making one bucket get no values). We need to avoid: |
| 179 // (ranges_[i] == ranges_[i + 1] | 182 // (ranges_[i] == ranges_[i + 1] |
| 180 // To avoid that, we just do a fine-grained bucket width as far as we need to | 183 // To avoid that, we just do a fine-grained bucket width as far as we need to |
| 181 // until we get a ratio that moves us along at least 2 units at a time. From | 184 // until we get a ratio that moves us along at least 2 units at a time. From |
| 182 // that bucket onward we do use the exponential growth of buckets. | 185 // that bucket onward we do use the exponential growth of buckets. |
| 183 void Histogram::InitializeBucketRange() { | 186 void Histogram::InitializeBucketRange() { |
| 184 double log_max = log(static_cast<double>(declared_max())); | 187 double log_max = log(static_cast<double>(declared_max())); |
| 185 double log_ratio; | 188 double log_ratio; |
| 186 double log_next; | 189 double log_next; |
| 187 size_t bucket_index = 1; | 190 size_t bucket_index = 1; |
| 188 Sample current = declared_min(); | 191 Sample current = declared_min(); |
| 189 SetBucketRange(bucket_index, current); | 192 SetBucketRange(bucket_index, current); |
| 190 while (bucket_count() > ++bucket_index) { | 193 while (bucket_count() > ++bucket_index) { |
| 191 double log_current; | 194 double log_current; |
| 192 log_current = log(static_cast<double>(current)); | 195 log_current = log(static_cast<double>(current)); |
| 193 // Calculate the count'th root of the range. | 196 // Calculate the count'th root of the range. |
| 194 log_ratio = (log_max - log_current) / (bucket_count() - bucket_index); | 197 log_ratio = (log_max - log_current) / (bucket_count() - bucket_index); |
| 195 // See where the next bucket would start. | 198 // See where the next bucket would start. |
| 196 log_next = log_current + log_ratio; | 199 log_next = log_current + log_ratio; |
| 197 int next; | 200 int next; |
| 198 next = static_cast<int>(floor(exp(log_next) + 0.5)); | 201 next = static_cast<int>(floor(exp(log_next) + 0.5)); |
| 199 if (next > current) | 202 if (next > current) |
| 200 current = next; | 203 current = next; |
| 201 else | 204 else |
| 202 current++; // Just do a narrow bucket, and keep trying. | 205 ++current; // Just do a narrow bucket, and keep trying. |
| 203 SetBucketRange(bucket_index, current); | 206 SetBucketRange(bucket_index, current); |
| 204 } | 207 } |
| 205 | 208 |
| 206 DCHECK(bucket_count() == bucket_index); | 209 DCHECK(bucket_count() == bucket_index); |
| 207 } | 210 } |
| 208 | 211 |
| 209 size_t Histogram::BucketIndex(Sample value) const { | 212 size_t Histogram::BucketIndex(Sample value) const { |
| 210 // Use simple binary search. This is very general, but there are better | 213 // Use simple binary search. This is very general, but there are better |
| 211 // approaches if we knew that the buckets were linearly distributed. | 214 // approaches if we knew that the buckets were linearly distributed. |
| 212 DCHECK(ranges(0) <= value); | 215 DCHECK(ranges(0) <= value); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 void Histogram::SetBucketRange(size_t i, Sample value) { | 273 void Histogram::SetBucketRange(size_t i, Sample value) { |
| 271 DCHECK(bucket_count_ > i); | 274 DCHECK(bucket_count_ > i); |
| 272 ranges_[i] = value; | 275 ranges_[i] = value; |
| 273 } | 276 } |
| 274 | 277 |
| 275 //------------------------------------------------------------------------------ | 278 //------------------------------------------------------------------------------ |
| 276 // Private methods | 279 // Private methods |
| 277 | 280 |
| 278 double Histogram::GetPeakBucketSize(const SampleSet& snapshot) const { | 281 double Histogram::GetPeakBucketSize(const SampleSet& snapshot) const { |
| 279 double max = 0; | 282 double max = 0; |
| 280 for (size_t i = 0; i < bucket_count() ; i++) { | 283 for (size_t i = 0; i < bucket_count() ; ++i) { |
| 281 double current_size = GetBucketSize(snapshot.counts(i), i); | 284 double current_size = GetBucketSize(snapshot.counts(i), i); |
| 282 if (current_size > max) | 285 if (current_size > max) |
| 283 max = current_size; | 286 max = current_size; |
| 284 } | 287 } |
| 285 return max; | 288 return max; |
| 286 } | 289 } |
| 287 | 290 |
| 288 void Histogram::WriteAsciiHeader(const SampleSet& snapshot, | 291 void Histogram::WriteAsciiHeader(const SampleSet& snapshot, |
| 289 Count sample_count, | 292 Count sample_count, |
| 290 std::string* output) const { | 293 std::string* output) const { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 + 0.5); | 345 + 0.5); |
| 343 int x_remainder = k_line_length - x_count; | 346 int x_remainder = k_line_length - x_count; |
| 344 | 347 |
| 345 while (0 < x_count--) | 348 while (0 < x_count--) |
| 346 output->append("-"); | 349 output->append("-"); |
| 347 output->append("O"); | 350 output->append("O"); |
| 348 while (0 < x_remainder--) | 351 while (0 < x_remainder--) |
| 349 output->append(" "); | 352 output->append(" "); |
| 350 } | 353 } |
| 351 | 354 |
| 355 // static |
| 356 std::string Histogram::SerializeHistogramInfo(const Histogram& histogram, |
| 357 const SampleSet& snapshot) { |
| 358 Pickle pickle; |
| 359 |
| 360 pickle.WriteString(histogram.histogram_name()); |
| 361 pickle.WriteInt(histogram.declared_min()); |
| 362 pickle.WriteInt(histogram.declared_max()); |
| 363 pickle.WriteSize(histogram.bucket_count()); |
| 364 pickle.WriteInt(histogram.histogram_type()); |
| 365 pickle.WriteInt(histogram.flags()); |
| 366 |
| 367 snapshot.Serialize(&pickle); |
| 368 return std::string(static_cast<const char*>(pickle.data()), pickle.size()); |
| 369 } |
| 370 |
| 371 // static |
| 372 void Histogram::DeserializeHistogramList( |
| 373 const std::vector<std::string>& histograms) { |
| 374 for (std::vector<std::string>::const_iterator it = histograms.begin(); |
| 375 it < histograms.end(); |
| 376 ++it) { |
| 377 DeserializeHistogramInfo(*it); |
| 378 } |
| 379 } |
| 380 |
| 381 // static |
| 382 bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) { |
| 383 if (histogram_info.empty()) { |
| 384 return false; |
| 385 } |
| 386 |
| 387 Pickle pickle(histogram_info.data(), |
| 388 static_cast<int>(histogram_info.size())); |
| 389 void* iter = NULL; |
| 390 size_t bucket_count; |
| 391 int declared_min; |
| 392 int declared_max; |
| 393 int histogram_type; |
| 394 int flags; |
| 395 std::string histogram_name; |
| 396 SampleSet sample; |
| 397 |
| 398 if (!pickle.ReadString(&iter, &histogram_name) || |
| 399 !pickle.ReadInt(&iter, &declared_min) || |
| 400 !pickle.ReadInt(&iter, &declared_max) || |
| 401 !pickle.ReadSize(&iter, &bucket_count) || |
| 402 !pickle.ReadInt(&iter, &histogram_type) || |
| 403 !pickle.ReadInt(&iter, &flags) || |
| 404 !sample.Histogram::SampleSet::Deserialize(&iter, pickle)) { |
| 405 LOG(ERROR) << "Picke error decoding Histogram: " << histogram_name; |
| 406 return false; |
| 407 } |
| 408 |
| 409 Histogram* render_histogram = |
| 410 StatisticsRecorder::GetHistogram(histogram_name); |
| 411 |
| 412 if (render_histogram == NULL) { |
| 413 if (histogram_type == EXPONENTIAL) { |
| 414 render_histogram = new Histogram(histogram_name.c_str(), |
| 415 declared_min, |
| 416 declared_max, |
| 417 bucket_count); |
| 418 } else if (histogram_type == LINEAR) { |
| 419 render_histogram = reinterpret_cast<Histogram*> |
| 420 (new LinearHistogram(histogram_name.c_str(), |
| 421 declared_min, |
| 422 declared_max, |
| 423 bucket_count)); |
| 424 } else { |
| 425 LOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: " << |
| 426 histogram_type; |
| 427 return false; |
| 428 } |
| 429 DCHECK(!(flags & kRendererHistogramFlag)); |
| 430 render_histogram->SetFlags(flags | kRendererHistogramFlag); |
| 431 } |
| 432 |
| 433 DCHECK(declared_min == render_histogram->declared_min()); |
| 434 DCHECK(declared_max == render_histogram->declared_max()); |
| 435 DCHECK(bucket_count == render_histogram->bucket_count()); |
| 436 DCHECK(histogram_type == render_histogram->histogram_type()); |
| 437 |
| 438 if (render_histogram->flags() & kRendererHistogramFlag) { |
| 439 render_histogram->AddSampleSet(sample); |
| 440 } else { |
| 441 DLOG(INFO) << "Single thread mode, histogram observed and not copied: " << |
| 442 histogram_name; |
| 443 } |
| 444 |
| 445 return true; |
| 446 } |
| 447 |
| 448 |
| 352 //------------------------------------------------------------------------------ | 449 //------------------------------------------------------------------------------ |
| 353 // Methods for the Histogram::SampleSet class | 450 // Methods for the Histogram::SampleSet class |
| 354 //------------------------------------------------------------------------------ | 451 //------------------------------------------------------------------------------ |
| 355 | 452 |
| 356 Histogram::SampleSet::SampleSet() | 453 Histogram::SampleSet::SampleSet() |
| 357 : counts_(), | 454 : counts_(), |
| 358 sum_(0), | 455 sum_(0), |
| 359 square_sum_(0) { | 456 square_sum_(0) { |
| 360 } | 457 } |
| 361 | 458 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 376 square_sum_ += (count * value) * static_cast<int64>(value); | 473 square_sum_ += (count * value) * static_cast<int64>(value); |
| 377 DCHECK(counts_[index] >= 0); | 474 DCHECK(counts_[index] >= 0); |
| 378 DCHECK(sum_ >= 0); | 475 DCHECK(sum_ >= 0); |
| 379 DCHECK(square_sum_ >= 0); | 476 DCHECK(square_sum_ >= 0); |
| 380 } | 477 } |
| 381 | 478 |
| 382 Count Histogram::SampleSet::TotalCount() const { | 479 Count Histogram::SampleSet::TotalCount() const { |
| 383 Count total = 0; | 480 Count total = 0; |
| 384 for (Counts::const_iterator it = counts_.begin(); | 481 for (Counts::const_iterator it = counts_.begin(); |
| 385 it != counts_.end(); | 482 it != counts_.end(); |
| 386 it++) { | 483 ++it) { |
| 387 total += *it; | 484 total += *it; |
| 388 } | 485 } |
| 389 return total; | 486 return total; |
| 390 } | 487 } |
| 391 | 488 |
| 392 void Histogram::SampleSet::Add(const SampleSet& other) { | 489 void Histogram::SampleSet::Add(const SampleSet& other) { |
| 393 DCHECK(counts_.size() == other.counts_.size()); | 490 DCHECK(counts_.size() == other.counts_.size()); |
| 394 sum_ += other.sum_; | 491 sum_ += other.sum_; |
| 395 square_sum_ += other.square_sum_; | 492 square_sum_ += other.square_sum_; |
| 396 for (size_t index = 0; index < counts_.size(); index++) | 493 for (size_t index = 0; index < counts_.size(); ++index) |
| 397 counts_[index] += other.counts_[index]; | 494 counts_[index] += other.counts_[index]; |
| 398 } | 495 } |
| 399 | 496 |
| 400 void Histogram::SampleSet::Subtract(const SampleSet& other) { | 497 void Histogram::SampleSet::Subtract(const SampleSet& other) { |
| 401 DCHECK(counts_.size() == other.counts_.size()); | 498 DCHECK(counts_.size() == other.counts_.size()); |
| 402 // Note: Race conditions in snapshotting a sum or square_sum may lead to | 499 // Note: Race conditions in snapshotting a sum or square_sum may lead to |
| 403 // (temporary) negative values when snapshots are later combined (and deltas | 500 // (temporary) negative values when snapshots are later combined (and deltas |
| 404 // calculated). As a result, we don't currently CHCEK() for positive values. | 501 // calculated). As a result, we don't currently CHCEK() for positive values. |
| 405 sum_ -= other.sum_; | 502 sum_ -= other.sum_; |
| 406 square_sum_ -= other.square_sum_; | 503 square_sum_ -= other.square_sum_; |
| 407 for (size_t index = 0; index < counts_.size(); index++) { | 504 for (size_t index = 0; index < counts_.size(); ++index) { |
| 408 counts_[index] -= other.counts_[index]; | 505 counts_[index] -= other.counts_[index]; |
| 409 DCHECK(counts_[index] >= 0); | 506 DCHECK(counts_[index] >= 0); |
| 410 } | 507 } |
| 411 } | 508 } |
| 412 | 509 |
| 510 bool Histogram::SampleSet::Serialize(Pickle* pickle) const { |
| 511 pickle->WriteInt64(sum_); |
| 512 pickle->WriteInt64(square_sum_); |
| 513 pickle->WriteSize(counts_.size()); |
| 514 |
| 515 for (size_t index = 0; index < counts_.size(); ++index) { |
| 516 pickle->WriteInt(counts_[index]); |
| 517 } |
| 518 |
| 519 return true; |
| 520 } |
| 521 |
| 522 bool Histogram::SampleSet::Deserialize(void** iter, const Pickle& pickle) { |
| 523 DCHECK(counts_.size() == 0); |
| 524 DCHECK(sum_ == 0); |
| 525 DCHECK(square_sum_ == 0); |
| 526 |
| 527 size_t counts_size; |
| 528 |
| 529 if (!pickle.ReadInt64(iter, &sum_) || |
| 530 !pickle.ReadInt64(iter, &square_sum_) || |
| 531 !pickle.ReadSize(iter, &counts_size)) { |
| 532 return false; |
| 533 } |
| 534 |
| 535 if (counts_size <= 0) |
| 536 return false; |
| 537 |
| 538 counts_.resize(counts_size, 0); |
| 539 for (size_t index = 0; index < counts_size; ++index) { |
| 540 if (!pickle.ReadInt(iter, &counts_[index])) { |
| 541 return false; |
| 542 } |
| 543 } |
| 544 |
| 545 return true; |
| 546 } |
| 547 |
| 413 //------------------------------------------------------------------------------ | 548 //------------------------------------------------------------------------------ |
| 414 // LinearHistogram: This histogram uses a traditional set of evenly spaced | 549 // LinearHistogram: This histogram uses a traditional set of evenly spaced |
| 415 // buckets. | 550 // buckets. |
| 416 //------------------------------------------------------------------------------ | 551 //------------------------------------------------------------------------------ |
| 417 | 552 |
| 418 LinearHistogram::LinearHistogram(const char* name, | 553 LinearHistogram::LinearHistogram(const char* name, Sample minimum, |
| 419 Sample minimum, Sample maximum, size_t bucket_count) | 554 Sample maximum, size_t bucket_count) |
| 420 : Histogram(name, minimum >= 1 ? minimum : 1, maximum, bucket_count) { | 555 : Histogram(name, minimum >= 1 ? minimum : 1, maximum, bucket_count) { |
| 421 InitializeBucketRange(); | 556 InitializeBucketRange(); |
| 422 DCHECK(ValidateBucketRanges()); | 557 DCHECK(ValidateBucketRanges()); |
| 423 } | 558 } |
| 424 | 559 |
| 425 LinearHistogram::LinearHistogram(const char* name, | 560 LinearHistogram::LinearHistogram(const char* name, |
| 426 TimeDelta minimum, TimeDelta maximum, size_t bucket_count) | 561 TimeDelta minimum, TimeDelta maximum, size_t bucket_count) |
| 427 : Histogram(name, minimum >= TimeDelta::FromMilliseconds(1) ? | 562 : Histogram(name, minimum >= TimeDelta::FromMilliseconds(1) ? |
| 428 minimum : TimeDelta::FromMilliseconds(1), | 563 minimum : TimeDelta::FromMilliseconds(1), |
| 429 maximum, bucket_count) { | 564 maximum, bucket_count) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 450 bool LinearHistogram::PrintEmptyBucket(size_t index) const { | 585 bool LinearHistogram::PrintEmptyBucket(size_t index) const { |
| 451 return bucket_description_.find(ranges(index)) == bucket_description_.end(); | 586 return bucket_description_.find(ranges(index)) == bucket_description_.end(); |
| 452 } | 587 } |
| 453 | 588 |
| 454 | 589 |
| 455 void LinearHistogram::InitializeBucketRange() { | 590 void LinearHistogram::InitializeBucketRange() { |
| 456 DCHECK(0 < declared_min()); // 0 is the underflow bucket here. | 591 DCHECK(0 < declared_min()); // 0 is the underflow bucket here. |
| 457 double min = declared_min(); | 592 double min = declared_min(); |
| 458 double max = declared_max(); | 593 double max = declared_max(); |
| 459 size_t i; | 594 size_t i; |
| 460 for (i = 1; i < bucket_count(); i++) { | 595 for (i = 1; i < bucket_count(); ++i) { |
| 461 double linear_range = (min * (bucket_count() -1 - i) + max * (i - 1)) / | 596 double linear_range = (min * (bucket_count() -1 - i) + max * (i - 1)) / |
| 462 (bucket_count() - 2); | 597 (bucket_count() - 2); |
| 463 SetBucketRange(i, static_cast<int> (linear_range + 0.5)); | 598 SetBucketRange(i, static_cast<int> (linear_range + 0.5)); |
| 464 } | 599 } |
| 465 } | 600 } |
| 466 | 601 |
| 467 // Find bucket to increment for sample value. | 602 // Find bucket to increment for sample value. |
| 468 size_t LinearHistogram::BucketIndex(Sample value) const { | 603 size_t LinearHistogram::BucketIndex(Sample value) const { |
| 469 if (value < declared_min()) return 0; | 604 if (value < declared_min()) return 0; |
| 470 if (value >= declared_max()) return bucket_count() - 1; | 605 if (value >= declared_max()) return bucket_count() - 1; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 541 delete lock_; | 676 delete lock_; |
| 542 lock_ = NULL; | 677 lock_ = NULL; |
| 543 } | 678 } |
| 544 | 679 |
| 545 // static | 680 // static |
| 546 bool StatisticsRecorder::WasStarted() { | 681 bool StatisticsRecorder::WasStarted() { |
| 547 return NULL != histograms_; | 682 return NULL != histograms_; |
| 548 } | 683 } |
| 549 | 684 |
| 550 // static | 685 // static |
| 551 bool StatisticsRecorder::Register(const Histogram& histogram) { | 686 bool StatisticsRecorder::Register(Histogram* histogram) { |
| 552 if (!histograms_) | 687 if (!histograms_) |
| 553 return false; | 688 return false; |
| 554 const std::string name = histogram.histogram_name(); | 689 const std::string name = histogram->histogram_name(); |
| 555 AutoLock auto_lock(*lock_); | 690 AutoLock auto_lock(*lock_); |
| 556 | 691 |
| 557 DCHECK(histograms_->end() == histograms_->find(name)) << name << " is already" | 692 DCHECK(histograms_->end() == histograms_->find(name)) << name << " is already" |
| 558 "registered as a histogram. Check for duplicate use of the name, or a " | 693 "registered as a histogram. Check for duplicate use of the name, or a " |
| 559 "race where a static initializer could be run by several threads."; | 694 "race where a static initializer could be run by several threads."; |
| 560 (*histograms_)[name] = &histogram; | 695 (*histograms_)[name] = histogram; |
| 561 return true; | 696 return true; |
| 562 } | 697 } |
| 563 | 698 |
| 564 // static | 699 // static |
| 565 void StatisticsRecorder::UnRegister(const Histogram& histogram) { | 700 void StatisticsRecorder::UnRegister(Histogram* histogram) { |
| 566 if (!histograms_) | 701 if (!histograms_) |
| 567 return; | 702 return; |
| 568 const std::string name = histogram.histogram_name(); | 703 const std::string name = histogram->histogram_name(); |
| 569 AutoLock auto_lock(*lock_); | 704 AutoLock auto_lock(*lock_); |
| 570 DCHECK(histograms_->end() != histograms_->find(name)); | 705 DCHECK(histograms_->end() != histograms_->find(name)); |
| 571 histograms_->erase(name); | 706 histograms_->erase(name); |
| 572 if (dump_on_exit_) { | 707 if (dump_on_exit_) { |
| 573 std::string output; | 708 std::string output; |
| 574 histogram.WriteAscii(true, "\n", &output); | 709 histogram->WriteAscii(true, "\n", &output); |
| 575 LOG(INFO) << output; | 710 LOG(INFO) << output; |
| 576 } | 711 } |
| 577 } | 712 } |
| 578 | 713 |
| 579 // static | 714 // static |
| 580 void StatisticsRecorder::WriteHTMLGraph(const std::string& query, | 715 void StatisticsRecorder::WriteHTMLGraph(const std::string& query, |
| 581 std::string* output) { | 716 std::string* output) { |
| 582 if (!histograms_) | 717 if (!histograms_) |
| 583 return; | 718 return; |
| 584 output->append("<html><head><title>About Histograms"); | 719 output->append("<html><head><title>About Histograms"); |
| 585 if (!query.empty()) | 720 if (!query.empty()) |
| 586 output->append(" - " + query); | 721 output->append(" - " + query); |
| 587 output->append("</title>" | 722 output->append("</title>" |
| 588 // We'd like the following no-cache... but it doesn't work. | 723 // We'd like the following no-cache... but it doesn't work. |
| 589 // "<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">" | 724 // "<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">" |
| 590 "</head><body>"); | 725 "</head><body>"); |
| 591 | 726 |
| 592 Histograms snapshot; | 727 Histograms snapshot; |
| 593 GetSnapshot(query, &snapshot); | 728 GetSnapshot(query, &snapshot); |
| 594 for (Histograms::iterator it = snapshot.begin(); | 729 for (Histograms::iterator it = snapshot.begin(); |
| 595 it != snapshot.end(); | 730 it != snapshot.end(); |
| 596 it++) { | 731 ++it) { |
| 597 (*it)->WriteHTMLGraph(output); | 732 (*it)->WriteHTMLGraph(output); |
| 598 output->append("<br><hr><br>"); | 733 output->append("<br><hr><br>"); |
| 599 } | 734 } |
| 600 output->append("</body></html>"); | 735 output->append("</body></html>"); |
| 601 } | 736 } |
| 602 | 737 |
| 603 // static | 738 // static |
| 604 void StatisticsRecorder::WriteGraph(const std::string& query, | 739 void StatisticsRecorder::WriteGraph(const std::string& query, |
| 605 std::string* output) { | 740 std::string* output) { |
| 606 if (!histograms_) | 741 if (!histograms_) |
| 607 return; | 742 return; |
| 608 if (query.length()) | 743 if (query.length()) |
| 609 StringAppendF(output, "Collections of histograms for %s\n", query.c_str()); | 744 StringAppendF(output, "Collections of histograms for %s\n", query.c_str()); |
| 610 else | 745 else |
| 611 output->append("Collections of all histograms\n"); | 746 output->append("Collections of all histograms\n"); |
| 612 | 747 |
| 613 Histograms snapshot; | 748 Histograms snapshot; |
| 614 GetSnapshot(query, &snapshot); | 749 GetSnapshot(query, &snapshot); |
| 615 for (Histograms::iterator it = snapshot.begin(); | 750 for (Histograms::iterator it = snapshot.begin(); |
| 616 it != snapshot.end(); | 751 it != snapshot.end(); |
| 617 it++) { | 752 ++it) { |
| 618 (*it)->WriteAscii(true, "\n", output); | 753 (*it)->WriteAscii(true, "\n", output); |
| 619 output->append("\n"); | 754 output->append("\n"); |
| 620 } | 755 } |
| 621 } | 756 } |
| 622 | 757 |
| 623 // static | 758 // static |
| 624 void StatisticsRecorder::GetHistograms(Histograms* output) { | 759 void StatisticsRecorder::GetHistograms(Histograms* output) { |
| 625 if (!histograms_) | 760 if (!histograms_) |
| 626 return; | 761 return; |
| 627 AutoLock auto_lock(*lock_); | 762 AutoLock auto_lock(*lock_); |
| 628 for (HistogramMap::iterator it = histograms_->begin(); | 763 for (HistogramMap::iterator it = histograms_->begin(); |
| 629 histograms_->end() != it; | 764 histograms_->end() != it; |
| 630 it++) { | 765 ++it) { |
| 631 output->push_back(it->second); | 766 output->push_back(it->second); |
| 632 } | 767 } |
| 633 } | 768 } |
| 634 | 769 |
| 770 Histogram* StatisticsRecorder::GetHistogram(const std::string& query) { |
| 771 if (!histograms_) |
| 772 return NULL; |
| 773 AutoLock auto_lock(*lock_); |
| 774 for (HistogramMap::iterator it = histograms_->begin(); |
| 775 histograms_->end() != it; |
| 776 ++it) { |
| 777 if (it->first.find(query) != std::string::npos) |
| 778 return it->second; |
| 779 } |
| 780 return NULL; |
| 781 } |
| 782 |
| 635 // private static | 783 // private static |
| 636 void StatisticsRecorder::GetSnapshot(const std::string& query, | 784 void StatisticsRecorder::GetSnapshot(const std::string& query, |
| 637 Histograms* snapshot) { | 785 Histograms* snapshot) { |
| 638 AutoLock auto_lock(*lock_); | 786 AutoLock auto_lock(*lock_); |
| 639 for (HistogramMap::iterator it = histograms_->begin(); | 787 for (HistogramMap::iterator it = histograms_->begin(); |
| 640 histograms_->end() != it; | 788 histograms_->end() != it; |
| 641 it++) { | 789 ++it) { |
| 642 if (it->first.find(query) != std::string::npos) | 790 if (it->first.find(query) != std::string::npos) |
| 643 snapshot->push_back(it->second); | 791 snapshot->push_back(it->second); |
| 644 } | 792 } |
| 645 } | 793 } |
| 646 | 794 |
| 647 // static | 795 // static |
| 648 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL; | 796 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL; |
| 649 // static | 797 // static |
| 650 Lock* StatisticsRecorder::lock_ = NULL; | 798 Lock* StatisticsRecorder::lock_ = NULL; |
| 651 // static | 799 // static |
| 652 bool StatisticsRecorder::dump_on_exit_ = false; | 800 bool StatisticsRecorder::dump_on_exit_ = false; |
| OLD | NEW |