| OLD | NEW |
| 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 | 8 |
| 9 // It supports calls to accumulate either time intervals (which are processed | 9 // It supports calls to accumulate either time intervals (which are processed |
| 10 // as integral number of milliseconds), or arbitrary integral units. | 10 // as integral number of milliseconds), or arbitrary integral units. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 // gigantic range with the addition of very few buckets. | 29 // gigantic range with the addition of very few buckets. |
| 30 | 30 |
| 31 #ifndef BASE_METRICS_HISTOGRAM_H_ | 31 #ifndef BASE_METRICS_HISTOGRAM_H_ |
| 32 #define BASE_METRICS_HISTOGRAM_H_ | 32 #define BASE_METRICS_HISTOGRAM_H_ |
| 33 #pragma once | 33 #pragma once |
| 34 | 34 |
| 35 #include <map> | 35 #include <map> |
| 36 #include <string> | 36 #include <string> |
| 37 #include <vector> | 37 #include <vector> |
| 38 | 38 |
| 39 #include "base/gtest_prod_util.h" | |
| 40 #include "base/ref_counted.h" | 39 #include "base/ref_counted.h" |
| 41 #include "base/logging.h" | 40 #include "base/logging.h" |
| 42 #include "base/time.h" | 41 #include "base/time.h" |
| 43 | 42 |
| 44 class Lock; | 43 class Lock; |
| 45 class Pickle; | 44 class Pickle; |
| 46 | 45 |
| 47 namespace base { | 46 namespace base { |
| 48 | 47 |
| 49 //------------------------------------------------------------------------------ | 48 //------------------------------------------------------------------------------ |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 237 | 236 |
| 238 class Histogram : public base::RefCountedThreadSafe<Histogram> { | 237 class Histogram : public base::RefCountedThreadSafe<Histogram> { |
| 239 public: | 238 public: |
| 240 typedef int Sample; // Used for samples (and ranges of samples). | 239 typedef int Sample; // Used for samples (and ranges of samples). |
| 241 typedef int Count; // Used to count samples in a bucket. | 240 typedef int Count; // Used to count samples in a bucket. |
| 242 static const Sample kSampleType_MAX = INT_MAX; | 241 static const Sample kSampleType_MAX = INT_MAX; |
| 243 | 242 |
| 244 typedef std::vector<Count> Counts; | 243 typedef std::vector<Count> Counts; |
| 245 typedef std::vector<Sample> Ranges; | 244 typedef std::vector<Sample> Ranges; |
| 246 | 245 |
| 247 // These enums are used to facilitate deserialization of renderer histograms | 246 /* These enums are meant to facilitate deserialization of renderer histograms |
| 248 // into the browser. | 247 into the browser. */ |
| 249 enum ClassType { | 248 enum ClassType { |
| 250 HISTOGRAM, | 249 HISTOGRAM, |
| 251 LINEAR_HISTOGRAM, | 250 LINEAR_HISTOGRAM, |
| 252 BOOLEAN_HISTOGRAM, | 251 BOOLEAN_HISTOGRAM, |
| 253 CUSTOM_HISTOGRAM, | 252 CUSTOM_HISTOGRAM, |
| 254 NOT_VALID_IN_RENDERER | 253 NOT_VALID_IN_RENDERER |
| 255 }; | 254 }; |
| 256 | 255 |
| 257 enum BucketLayout { | 256 enum BucketLayout { |
| 258 EXPONENTIAL, | 257 EXPONENTIAL, |
| 259 LINEAR, | 258 LINEAR, |
| 260 CUSTOM | 259 CUSTOM |
| 261 }; | 260 }; |
| 262 | 261 |
| 263 enum Flags { | 262 enum Flags { |
| 264 kNoFlags = 0, | 263 kNoFlags = 0, |
| 265 kUmaTargetedHistogramFlag = 0x1, // Histogram should be UMA uploaded. | 264 kUmaTargetedHistogramFlag = 0x1, // Histogram should be UMA uploaded. |
| 266 | 265 |
| 267 // Indicate that the histogram was pickled to be sent across an IPC Channel. | 266 // Indicate that the histogram was pickled to be sent across an IPC Channel. |
| 268 // If we observe this flag on a histogram being aggregated into after IPC, | 267 // If we observe this flag on a histogram being aggregated into after IPC, |
| 269 // then we are running in a single process mode, and the aggregation should | 268 // then we are running in a single process mode, and the aggregation should |
| 270 // not take place (as we would be aggregating back into the source | 269 // not take place (as we would be aggregating back into the source |
| 271 // histogram!). | 270 // histogram!). |
| 272 kIPCSerializationSourceFlag = 0x10, | 271 kIPCSerializationSourceFlag = 0x10, |
| 273 | 272 |
| 274 kHexRangePrintingFlag = 0x8000, // Fancy bucket-naming supported. | 273 kHexRangePrintingFlag = 0x8000, // Fancy bucket-naming supported. |
| 275 }; | 274 }; |
| 276 | 275 |
| 277 enum Inconsistencies { | |
| 278 NO_INCONSISTENCIES = 0x0, | |
| 279 RANGE_CHECKSUM_ERROR = 0x1, | |
| 280 BUCKET_ORDER_ERROR = 0x2, | |
| 281 COUNT_HIGH_ERROR = 0x4, | |
| 282 COUNT_LOW_ERROR = 0x8, | |
| 283 | |
| 284 NEVER_EXCEEDED_VALUE = 0x10 | |
| 285 }; | |
| 286 | |
| 287 struct DescriptionPair { | 276 struct DescriptionPair { |
| 288 Sample sample; | 277 Sample sample; |
| 289 const char* description; // Null means end of a list of pairs. | 278 const char* description; // Null means end of a list of pairs. |
| 290 }; | 279 }; |
| 291 | 280 |
| 292 //---------------------------------------------------------------------------- | 281 //---------------------------------------------------------------------------- |
| 293 // Statistic values, developed over the life of the histogram. | 282 // Statistic values, developed over the life of the histogram. |
| 294 | 283 |
| 295 class SampleSet { | 284 class SampleSet { |
| 296 public: | 285 public: |
| 297 explicit SampleSet(); | 286 explicit SampleSet(); |
| 298 ~SampleSet(); | 287 ~SampleSet(); |
| 299 | 288 |
| 300 // Adjust size of counts_ for use with given histogram. | 289 // Adjust size of counts_ for use with given histogram. |
| 301 void Resize(const Histogram& histogram); | 290 void Resize(const Histogram& histogram); |
| 302 void CheckSize(const Histogram& histogram) const; | 291 void CheckSize(const Histogram& histogram) const; |
| 303 | 292 |
| 304 // Accessor for histogram to make routine additions. | 293 // Accessor for histogram to make routine additions. |
| 305 void Accumulate(Sample value, Count count, size_t index); | 294 void Accumulate(Sample value, Count count, size_t index); |
| 306 | 295 |
| 307 // Accessor methods. | 296 // Accessor methods. |
| 308 Count counts(size_t i) const { return counts_[i]; } | 297 Count counts(size_t i) const { return counts_[i]; } |
| 309 Count TotalCount() const; | 298 Count TotalCount() const; |
| 310 int64 sum() const { return sum_; } | 299 int64 sum() const { return sum_; } |
| 311 int64 square_sum() const { return square_sum_; } | 300 int64 square_sum() const { return square_sum_; } |
| 312 int64 redundant_count() const { return redundant_count_; } | |
| 313 | 301 |
| 314 // Arithmetic manipulation of corresponding elements of the set. | 302 // Arithmetic manipulation of corresponding elements of the set. |
| 315 void Add(const SampleSet& other); | 303 void Add(const SampleSet& other); |
| 316 void Subtract(const SampleSet& other); | 304 void Subtract(const SampleSet& other); |
| 317 | 305 |
| 318 bool Serialize(Pickle* pickle) const; | 306 bool Serialize(Pickle* pickle) const; |
| 319 bool Deserialize(void** iter, const Pickle& pickle); | 307 bool Deserialize(void** iter, const Pickle& pickle); |
| 320 | 308 |
| 321 protected: | 309 protected: |
| 322 // Actual histogram data is stored in buckets, showing the count of values | 310 // Actual histogram data is stored in buckets, showing the count of values |
| 323 // that fit into each bucket. | 311 // that fit into each bucket. |
| 324 Counts counts_; | 312 Counts counts_; |
| 325 | 313 |
| 326 // Save simple stats locally. Note that this MIGHT get done in base class | 314 // Save simple stats locally. Note that this MIGHT get done in base class |
| 327 // without shared memory at some point. | 315 // without shared memory at some point. |
| 328 int64 sum_; // sum of samples. | 316 int64 sum_; // sum of samples. |
| 329 int64 square_sum_; // sum of squares of samples. | 317 int64 square_sum_; // sum of squares of samples. |
| 330 | |
| 331 private: | |
| 332 // Allow tests to corrupt our innards for testing purposes. | |
| 333 FRIEND_TEST(HistogramTest, CorruptSampleCounts); | |
| 334 | |
| 335 // To help identify memory corruption, we reduntantly save the number of | |
| 336 // samples we've accumulated into all of our buckets. We can compare this | |
| 337 // count to the sum of the counts in all buckets, and detect problems. Note | |
| 338 // that due to races in histogram accumulation (if a histogram is indeed | |
| 339 // updated on several threads simultaneously), the tallies might mismatch, | |
| 340 // and also the snapshotting code may asynchronously get a mismatch (though | |
| 341 // generally either race based mismatch cause is VERY rare). | |
| 342 int64 redundant_count_; | |
| 343 }; | 318 }; |
| 344 | |
| 345 //---------------------------------------------------------------------------- | 319 //---------------------------------------------------------------------------- |
| 346 // minimum should start from 1. 0 is invalid as a minimum. 0 is an implicit | 320 // minimum should start from 1. 0 is invalid as a minimum. 0 is an implicit |
| 347 // default underflow bucket. | 321 // default underflow bucket. |
| 348 static scoped_refptr<Histogram> FactoryGet(const std::string& name, | 322 static scoped_refptr<Histogram> FactoryGet(const std::string& name, |
| 349 Sample minimum, Sample maximum, size_t bucket_count, Flags flags); | 323 Sample minimum, Sample maximum, size_t bucket_count, Flags flags); |
| 350 static scoped_refptr<Histogram> FactoryTimeGet(const std::string& name, | 324 static scoped_refptr<Histogram> FactoryTimeGet(const std::string& name, |
| 351 base::TimeDelta minimum, base::TimeDelta maximum, size_t bucket_count, | 325 base::TimeDelta minimum, base::TimeDelta maximum, size_t bucket_count, |
| 352 Flags flags); | 326 Flags flags); |
| 353 | 327 |
| 354 void Add(int value); | 328 void Add(int value); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 386 | 360 |
| 387 // Serialize the given snapshot of a Histogram into a String. Uses | 361 // Serialize the given snapshot of a Histogram into a String. Uses |
| 388 // Pickle class to flatten the object. | 362 // Pickle class to flatten the object. |
| 389 static std::string SerializeHistogramInfo(const Histogram& histogram, | 363 static std::string SerializeHistogramInfo(const Histogram& histogram, |
| 390 const SampleSet& snapshot); | 364 const SampleSet& snapshot); |
| 391 // The following method accepts a list of pickled histograms and | 365 // The following method accepts a list of pickled histograms and |
| 392 // builds a histogram and updates shadow copy of histogram data in the | 366 // builds a histogram and updates shadow copy of histogram data in the |
| 393 // browser process. | 367 // browser process. |
| 394 static bool DeserializeHistogramInfo(const std::string& histogram_info); | 368 static bool DeserializeHistogramInfo(const std::string& histogram_info); |
| 395 | 369 |
| 396 // Check to see if bucket ranges, counts and tallies in the snapshot are | |
| 397 // consistent with the bucket ranges and checksums in our histogram. This can | |
| 398 // produce a false-alarm if a race occurred in the reading of the data during | |
| 399 // a SnapShot process, but should otherwise be false at all times (unless we | |
| 400 // have memory over-writes, or DRAM failures). | |
| 401 Inconsistencies FindCorruption(const SampleSet& snapshot) const; | |
| 402 | |
| 403 //---------------------------------------------------------------------------- | 370 //---------------------------------------------------------------------------- |
| 404 // Accessors for factory constuction, serialization and testing. | 371 // Accessors for factory constuction, serialization and testing. |
| 405 //---------------------------------------------------------------------------- | 372 //---------------------------------------------------------------------------- |
| 406 virtual ClassType histogram_type() const { return HISTOGRAM; } | 373 virtual ClassType histogram_type() const { return HISTOGRAM; } |
| 407 const std::string& histogram_name() const { return histogram_name_; } | 374 const std::string& histogram_name() const { return histogram_name_; } |
| 408 Sample declared_min() const { return declared_min_; } | 375 Sample declared_min() const { return declared_min_; } |
| 409 Sample declared_max() const { return declared_max_; } | 376 Sample declared_max() const { return declared_max_; } |
| 410 virtual Sample ranges(size_t i) const { return ranges_[i];} | 377 virtual Sample ranges(size_t i) const { return ranges_[i];} |
| 411 Sample range_checksum() const { return range_checksum_; } | |
| 412 virtual size_t bucket_count() const { return bucket_count_; } | 378 virtual size_t bucket_count() const { return bucket_count_; } |
| 413 // Snapshot the current complete set of sample data. | 379 // Snapshot the current complete set of sample data. |
| 414 // Override with atomic/locked snapshot if needed. | 380 // Override with atomic/locked snapshot if needed. |
| 415 virtual void SnapshotSample(SampleSet* sample) const; | 381 virtual void SnapshotSample(SampleSet* sample) const; |
| 416 | 382 |
| 417 virtual bool HasConstructorArguments(Sample minimum, Sample maximum, | 383 virtual bool HasConstructorArguments(Sample minimum, Sample maximum, |
| 418 size_t bucket_count); | 384 size_t bucket_count); |
| 419 | 385 |
| 420 virtual bool HasConstructorTimeDeltaArguments(TimeDelta minimum, | 386 virtual bool HasConstructorTimeDeltaArguments(TimeDelta minimum, |
| 421 TimeDelta maximum, | 387 TimeDelta maximum, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 436 //---------------------------------------------------------------------------- | 402 //---------------------------------------------------------------------------- |
| 437 // Methods to override to create histogram with different bucket widths. | 403 // Methods to override to create histogram with different bucket widths. |
| 438 //---------------------------------------------------------------------------- | 404 //---------------------------------------------------------------------------- |
| 439 // Initialize ranges_ mapping. | 405 // Initialize ranges_ mapping. |
| 440 virtual void InitializeBucketRange(); | 406 virtual void InitializeBucketRange(); |
| 441 // Find bucket to increment for sample value. | 407 // Find bucket to increment for sample value. |
| 442 virtual size_t BucketIndex(Sample value) const; | 408 virtual size_t BucketIndex(Sample value) const; |
| 443 // Get normalized size, relative to the ranges_[i]. | 409 // Get normalized size, relative to the ranges_[i]. |
| 444 virtual double GetBucketSize(Count current, size_t i) const; | 410 virtual double GetBucketSize(Count current, size_t i) const; |
| 445 | 411 |
| 446 // Recalculate range_checksum_. | |
| 447 void ResetRangeChecksum(); | |
| 448 | |
| 449 // Return a string description of what goes in a given bucket. | 412 // Return a string description of what goes in a given bucket. |
| 450 // Most commonly this is the numeric value, but in derived classes it may | 413 // Most commonly this is the numeric value, but in derived classes it may |
| 451 // be a name (or string description) given to the bucket. | 414 // be a name (or string description) given to the bucket. |
| 452 virtual const std::string GetAsciiBucketRange(size_t it) const; | 415 virtual const std::string GetAsciiBucketRange(size_t it) const; |
| 453 | 416 |
| 454 //---------------------------------------------------------------------------- | 417 //---------------------------------------------------------------------------- |
| 455 // Methods to override to create thread safe histogram. | 418 // Methods to override to create thread safe histogram. |
| 456 //---------------------------------------------------------------------------- | 419 //---------------------------------------------------------------------------- |
| 457 // Update all our internal data, including histogram | 420 // Update all our internal data, including histogram |
| 458 virtual void Accumulate(Sample value, Count count, size_t index); | 421 virtual void Accumulate(Sample value, Count count, size_t index); |
| 459 | 422 |
| 460 //---------------------------------------------------------------------------- | 423 //---------------------------------------------------------------------------- |
| 461 // Accessors for derived classes. | 424 // Accessors for derived classes. |
| 462 //---------------------------------------------------------------------------- | 425 //---------------------------------------------------------------------------- |
| 463 void SetBucketRange(size_t i, Sample value); | 426 void SetBucketRange(size_t i, Sample value); |
| 464 | 427 |
| 465 // Validate that ranges_ was created sensibly (top and bottom range | 428 // Validate that ranges_ was created sensibly (top and bottom range |
| 466 // values relate properly to the declared_min_ and declared_max_).. | 429 // values relate properly to the declared_min_ and declared_max_).. |
| 467 bool ValidateBucketRanges() const; | 430 bool ValidateBucketRanges() const; |
| 468 | 431 |
| 469 private: | 432 private: |
| 470 // Allow tests to corrupt our innards for testing purposes. | |
| 471 FRIEND_TEST(HistogramTest, CorruptBucketBounds); | |
| 472 FRIEND_TEST(HistogramTest, CorruptSampleCounts); | |
| 473 | |
| 474 // Post constructor initialization. | 433 // Post constructor initialization. |
| 475 void Initialize(); | 434 void Initialize(); |
| 476 | 435 |
| 477 // Return true iff the range_checksum_ matches current ranges_ vector. | |
| 478 bool HasValidRangeChecksum() const; | |
| 479 | |
| 480 Sample CalculateRangeChecksum() const; | |
| 481 | |
| 482 //---------------------------------------------------------------------------- | 436 //---------------------------------------------------------------------------- |
| 483 // Helpers for emitting Ascii graphic. Each method appends data to output. | 437 // Helpers for emitting Ascii graphic. Each method appends data to output. |
| 484 | 438 |
| 485 // Find out how large the (graphically) the largest bucket will appear to be. | 439 // Find out how large the (graphically) the largest bucket will appear to be. |
| 486 double GetPeakBucketSize(const SampleSet& snapshot) const; | 440 double GetPeakBucketSize(const SampleSet& snapshot) const; |
| 487 | 441 |
| 488 // Write a common header message describing this histogram. | 442 // Write a common header message describing this histogram. |
| 489 void WriteAsciiHeader(const SampleSet& snapshot, | 443 void WriteAsciiHeader(const SampleSet& snapshot, |
| 490 Count sample_count, std::string* output) const; | 444 Count sample_count, std::string* output) const; |
| 491 | 445 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 516 | 470 |
| 517 // Flag the histogram for recording by UMA via metric_services.h. | 471 // Flag the histogram for recording by UMA via metric_services.h. |
| 518 Flags flags_; | 472 Flags flags_; |
| 519 | 473 |
| 520 // For each index, show the least value that can be stored in the | 474 // For each index, show the least value that can be stored in the |
| 521 // corresponding bucket. We also append one extra element in this array, | 475 // corresponding bucket. We also append one extra element in this array, |
| 522 // containing kSampleType_MAX, to make calculations easy. | 476 // containing kSampleType_MAX, to make calculations easy. |
| 523 // The dimension of ranges_ is bucket_count + 1. | 477 // The dimension of ranges_ is bucket_count + 1. |
| 524 Ranges ranges_; | 478 Ranges ranges_; |
| 525 | 479 |
| 526 // For redundancy, we store the sum of all the sample ranges when ranges are | |
| 527 // generated. If ever there is ever a difference, then the histogram must | |
| 528 // have been corrupted. | |
| 529 Sample range_checksum_; | |
| 530 | |
| 531 // Finally, provide the state that changes with the addition of each new | 480 // Finally, provide the state that changes with the addition of each new |
| 532 // sample. | 481 // sample. |
| 533 SampleSet sample_; | 482 SampleSet sample_; |
| 534 | 483 |
| 535 DISALLOW_COPY_AND_ASSIGN(Histogram); | 484 DISALLOW_COPY_AND_ASSIGN(Histogram); |
| 536 }; | 485 }; |
| 537 | 486 |
| 538 //------------------------------------------------------------------------------ | 487 //------------------------------------------------------------------------------ |
| 539 | 488 |
| 540 // LinearHistogram is a more traditional histogram, with evenly spaced | 489 // LinearHistogram is a more traditional histogram, with evenly spaced |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 605 }; | 554 }; |
| 606 | 555 |
| 607 //------------------------------------------------------------------------------ | 556 //------------------------------------------------------------------------------ |
| 608 | 557 |
| 609 // CustomHistogram is a histogram for a set of custom integers. | 558 // CustomHistogram is a histogram for a set of custom integers. |
| 610 class CustomHistogram : public Histogram { | 559 class CustomHistogram : public Histogram { |
| 611 public: | 560 public: |
| 612 virtual ClassType histogram_type() const; | 561 virtual ClassType histogram_type() const; |
| 613 | 562 |
| 614 static scoped_refptr<Histogram> FactoryGet(const std::string& name, | 563 static scoped_refptr<Histogram> FactoryGet(const std::string& name, |
| 615 const std::vector<Sample>& custom_ranges, Flags flags); | 564 const std::vector<int>& custom_ranges, Flags flags); |
| 616 | 565 |
| 617 protected: | 566 protected: |
| 618 CustomHistogram(const std::string& name, | 567 CustomHistogram(const std::string& name, |
| 619 const std::vector<Sample>& custom_ranges); | 568 const std::vector<int>& custom_ranges); |
| 620 | 569 |
| 621 // Initialize ranges_ mapping. | 570 // Initialize ranges_ mapping. |
| 622 virtual void InitializeBucketRange(); | 571 virtual void InitializeBucketRange(); |
| 623 virtual double GetBucketSize(Count current, size_t i) const; | 572 virtual double GetBucketSize(Count current, size_t i) const; |
| 624 | 573 |
| 625 private: | 574 private: |
| 626 // Temporary pointer used during construction/initialization, and then NULLed. | 575 // Temporary pointer used during construction/initialization, and then NULLed. |
| 627 const std::vector<Sample>* ranges_vector_; | 576 const std::vector<int>* ranges_vector_; |
| 628 | 577 |
| 629 DISALLOW_COPY_AND_ASSIGN(CustomHistogram); | 578 DISALLOW_COPY_AND_ASSIGN(CustomHistogram); |
| 630 }; | 579 }; |
| 631 | 580 |
| 632 //------------------------------------------------------------------------------ | 581 //------------------------------------------------------------------------------ |
| 633 // StatisticsRecorder handles all histograms in the system. It provides a | 582 // StatisticsRecorder handles all histograms in the system. It provides a |
| 634 // general place for histograms to register, and supports a global API for | 583 // general place for histograms to register, and supports a global API for |
| 635 // accessing (i.e., dumping, or graphing) the data in all the histograms. | 584 // accessing (i.e., dumping, or graphing) the data in all the histograms. |
| 636 | 585 |
| 637 class StatisticsRecorder { | 586 class StatisticsRecorder { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 685 | 634 |
| 686 // Dump all known histograms to log. | 635 // Dump all known histograms to log. |
| 687 static bool dump_on_exit_; | 636 static bool dump_on_exit_; |
| 688 | 637 |
| 689 DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder); | 638 DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder); |
| 690 }; | 639 }; |
| 691 | 640 |
| 692 } // namespace base | 641 } // namespace base |
| 693 | 642 |
| 694 #endif // BASE_METRICS_HISTOGRAM_H_ | 643 #endif // BASE_METRICS_HISTOGRAM_H_ |
| OLD | NEW |