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 |