ipc/chromium/src/base/histogram.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
     2 // Use of this source code is governed by a BSD-style license that can be
     3 // found in the LICENSE file.
     5 // Histogram is an object that aggregates statistics, and can summarize them in
     6 // various forms, including ASCII graphical, HTML, and numerically (as a
     7 // vector of numbers corresponding to each of the aggregating buckets).
     9 // It supports calls to accumulate either time intervals (which are processed
    10 // as integral number of milliseconds), or arbitrary integral units.
    12 // The default layout of buckets is exponential.  For example, buckets might
    13 // contain (sequentially) the count of values in the following intervals:
    14 // [0,1), [1,2), [2,4), [4,8), [8,16), [16,32), [32,64), [64,infinity)
    15 // That bucket allocation would actually result from construction of a histogram
    16 // for values between 1 and 64, with 8 buckets, such as:
    17 // Histogram count(L"some name", 1, 64, 8);
    18 // Note that the underflow bucket [0,1) and the overflow bucket [64,infinity)
    19 // are not counted by the constructor in the user supplied "bucket_count"
    20 // argument.
    21 // The above example has an exponential ratio of 2 (doubling the bucket width
    22 // in each consecutive bucket.  The Histogram class automatically calculates
    23 // the smallest ratio that it can use to construct the number of buckets
    24 // selected in the constructor.  An another example, if you had 50 buckets,
    25 // and millisecond time values from 1 to 10000, then the ratio between
    26 // consecutive bucket widths will be approximately somewhere around the 50th
    27 // root of 10000.  This approach provides very fine grain (narrow) buckets
    28 // at the low end of the histogram scale, but allows the histogram to cover a
    29 // gigantic range with the addition of very few buckets.
    31 // Histograms use a pattern involving a function static variable, that is a
    32 // pointer to a histogram.  This static is explicitly initialized on any thread
    33 // that detects a uninitialized (NULL) pointer.  The potentially racy
    34 // initialization is not a problem as it is always set to point to the same
    35 // value (i.e., the FactoryGet always returns the same value).  FactoryGet
    36 // is also completely thread safe, which results in a completely thread safe,
    37 // and relatively fast, set of counters.  To avoid races at shutdown, the static
    38 // pointer is NOT deleted, and we leak the histograms at process termination.
    40 #ifndef BASE_METRICS_HISTOGRAM_H_
    41 #define BASE_METRICS_HISTOGRAM_H_
    42 #pragma once
    44 #include "mozilla/MemoryReporting.h"
    46 #include <map>
    47 #include <string>
    48 #include <vector>
    50 #include "base/time.h"
    51 #include "base/lock.h"
    53 class Pickle;
    55 namespace base {
    56 //------------------------------------------------------------------------------
    57 // Provide easy general purpose histogram in a macro, just like stats counters.
    58 // The first four macros use 50 buckets.
    60 #define HISTOGRAM_TIMES(name, sample) HISTOGRAM_CUSTOM_TIMES( \
    61     name, sample, base::TimeDelta::FromMilliseconds(1), \
    62     base::TimeDelta::FromSeconds(10), 50)
    64 #define HISTOGRAM_COUNTS(name, sample) HISTOGRAM_CUSTOM_COUNTS( \
    65     name, sample, 1, 1000000, 50)
    67 #define HISTOGRAM_COUNTS_100(name, sample) HISTOGRAM_CUSTOM_COUNTS( \
    68     name, sample, 1, 100, 50)
    70 #define HISTOGRAM_COUNTS_10000(name, sample) HISTOGRAM_CUSTOM_COUNTS( \
    71     name, sample, 1, 10000, 50)
    73 #define HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \
    74     static base::Histogram* counter(NULL); \
    75     if (!counter) \
    76       counter = base::Histogram::FactoryGet(name, min, max, bucket_count, \
    77                                             base::Histogram::kNoFlags); \
    78     DCHECK_EQ(name, counter->histogram_name()); \
    79     counter->Add(sample); \
    80   } while (0)
    82 #define HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
    83     HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
    85 // For folks that need real specific times, use this to select a precise range
    86 // of times you want plotted, and the number of buckets you want used.
    87 #define HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \
    88     static base::Histogram* counter(NULL); \
    89     if (!counter) \
    90       counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
    91                                                 base::Histogram::kNoFlags); \
    92     DCHECK_EQ(name, counter->histogram_name()); \
    93     counter->AddTime(sample); \
    94   } while (0)
    96 // DO NOT USE THIS.  It is being phased out, in favor of HISTOGRAM_CUSTOM_TIMES.
    97 #define HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \
    98     static base::Histogram* counter(NULL); \
    99     if (!counter) \
   100       counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
   101                                                 base::Histogram::kNoFlags); \
   102     DCHECK_EQ(name, counter->histogram_name()); \
   103     if ((sample) < (max)) counter->AddTime(sample); \
   104   } while (0)
   106 // Support histograming of an enumerated value.  The samples should always be
   107 // less than boundary_value.
   109 #define HISTOGRAM_ENUMERATION(name, sample, boundary_value) do { \
   110     static base::Histogram* counter(NULL); \
   111     if (!counter) \
   112       counter = base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
   113           boundary_value + 1, base::Histogram::kNoFlags); \
   114     DCHECK_EQ(name, counter->histogram_name()); \
   115     counter->Add(sample); \
   116   } while (0)
   118 #define HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) do { \
   119     static base::Histogram* counter(NULL); \
   120     if (!counter) \
   121       counter = base::CustomHistogram::FactoryGet(name, custom_ranges, \
   122                                                   base::Histogram::kNoFlags); \
   123     DCHECK_EQ(name, counter->histogram_name()); \
   124     counter->Add(sample); \
   125   } while (0)
   128 //------------------------------------------------------------------------------
   129 // Define Debug vs non-debug flavors of macros.
   130 #ifndef NDEBUG
   132 #define DHISTOGRAM_TIMES(name, sample) HISTOGRAM_TIMES(name, sample)
   133 #define DHISTOGRAM_COUNTS(name, sample) HISTOGRAM_COUNTS(name, sample)
   134 #define DHISTOGRAM_PERCENTAGE(name, under_one_hundred) HISTOGRAM_PERCENTAGE(\
   135     name, under_one_hundred)
   136 #define DHISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
   137     HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count)
   138 #define DHISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) \
   139     HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count)
   140 #define DHISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
   141     HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count)
   142 #define DHISTOGRAM_ENUMERATION(name, sample, boundary_value) \
   143     HISTOGRAM_ENUMERATION(name, sample, boundary_value)
   144 #define DHISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
   145     HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges)
   147 #else  // NDEBUG
   149 #define DHISTOGRAM_TIMES(name, sample) do {} while (0)
   150 #define DHISTOGRAM_COUNTS(name, sample) do {} while (0)
   151 #define DHISTOGRAM_PERCENTAGE(name, under_one_hundred) do {} while (0)
   152 #define DHISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
   153     do {} while (0)
   154 #define DHISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) \
   155     do {} while (0)
   156 #define DHISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
   157     do {} while (0)
   158 #define DHISTOGRAM_ENUMERATION(name, sample, boundary_value) do {} while (0)
   159 #define DHISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
   160     do {} while (0)
   162 #endif  // NDEBUG
   164 //------------------------------------------------------------------------------
   165 // The following macros provide typical usage scenarios for callers that wish
   166 // to record histogram data, and have the data submitted/uploaded via UMA.
   167 // Not all systems support such UMA, but if they do, the following macros
   168 // should work with the service.
   170 #define UMA_HISTOGRAM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
   171     name, sample, base::TimeDelta::FromMilliseconds(1), \
   172     base::TimeDelta::FromSeconds(10), 50)
   174 #define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
   175     name, sample, base::TimeDelta::FromMilliseconds(10), \
   176     base::TimeDelta::FromMinutes(3), 50)
   178 // Use this macro when times can routinely be much longer than 10 seconds.
   179 #define UMA_HISTOGRAM_LONG_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
   180     name, sample, base::TimeDelta::FromMilliseconds(1), \
   181     base::TimeDelta::FromHours(1), 50)
   183 #define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \
   184     static base::Histogram* counter(NULL); \
   185     if (!counter) \
   186       counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
   187             base::Histogram::kUmaTargetedHistogramFlag); \
   188     DCHECK_EQ(name, counter->histogram_name()); \
   189     counter->AddTime(sample); \
   190   } while (0)
   192 // DO NOT USE THIS.  It is being phased out, in favor of HISTOGRAM_CUSTOM_TIMES.
   193 #define UMA_HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \
   194     static base::Histogram* counter(NULL); \
   195     if (!counter) \
   196       counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
   197            base::Histogram::kUmaTargetedHistogramFlag); \
   198     DCHECK_EQ(name, counter->histogram_name()); \
   199     if ((sample) < (max)) counter->AddTime(sample); \
   200   } while (0)
   202 #define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
   203     name, sample, 1, 1000000, 50)
   205 #define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
   206     name, sample, 1, 100, 50)
   208 #define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
   209     name, sample, 1, 10000, 50)
   211 #define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \
   212     static base::Histogram* counter(NULL); \
   213     if (!counter) \
   214       counter = base::Histogram::FactoryGet(name, min, max, bucket_count, \
   215           base::Histogram::kUmaTargetedHistogramFlag); \
   216     DCHECK_EQ(name, counter->histogram_name()); \
   217     counter->Add(sample); \
   218   } while (0)
   220 #define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
   221     name, sample, 1000, 500000, 50)
   223 #define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
   224     name, sample, 1, 1000, 50)
   226 #define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
   227     UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
   229 #define UMA_HISTOGRAM_BOOLEAN(name, sample) do { \
   230     static base::Histogram* counter(NULL); \
   231     if (!counter) \
   232       counter = base::BooleanHistogram::FactoryGet(name, \
   233           base::Histogram::kUmaTargetedHistogramFlag); \
   234     DCHECK_EQ(name, counter->histogram_name()); \
   235     counter->AddBoolean(sample); \
   236   } while (0)
   238 #define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) do { \
   239     static base::Histogram* counter(NULL); \
   240     if (!counter) \
   241       counter = base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
   242           boundary_value + 1, base::Histogram::kUmaTargetedHistogramFlag); \
   243     DCHECK_EQ(name, counter->histogram_name()); \
   244     counter->Add(sample); \
   245   } while (0)
   247 #define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) do { \
   248     static base::Histogram* counter(NULL); \
   249     if (!counter) \
   250       counter = base::CustomHistogram::FactoryGet(name, custom_ranges, \
   251           base::Histogram::kUmaTargetedHistogramFlag); \
   252     DCHECK_EQ(name, counter->histogram_name()); \
   253     counter->Add(sample); \
   254   } while (0)
   256 //------------------------------------------------------------------------------
   258 class BooleanHistogram;
   259 class CustomHistogram;
   260 class Histogram;
   261 class LinearHistogram;
   263 class Histogram {
   264  public:
   265   typedef int Sample;  // Used for samples (and ranges of samples).
   266   typedef int Count;  // Used to count samples in a bucket.
   267   static const Sample kSampleType_MAX = INT_MAX;
   268   // Initialize maximum number of buckets in histograms as 16,384.
   269   static const size_t kBucketCount_MAX;
   271   typedef std::vector<Count> Counts;
   272   typedef std::vector<Sample> Ranges;
   274   // These enums are used to facilitate deserialization of renderer histograms
   275   // into the browser.
   276   enum ClassType {
   277     HISTOGRAM,
   278     LINEAR_HISTOGRAM,
   279     BOOLEAN_HISTOGRAM,
   280     FLAG_HISTOGRAM,
   281     CUSTOM_HISTOGRAM,
   282     NOT_VALID_IN_RENDERER
   283   };
   285   enum BucketLayout {
   286     EXPONENTIAL,
   287     LINEAR,
   288     CUSTOM
   289   };
   291   enum Flags {
   292     kNoFlags = 0,
   293     kUmaTargetedHistogramFlag = 0x1,  // Histogram should be UMA uploaded.
   294     kExtendedStatisticsFlag = 0x2, // OK to gather extended statistics on histograms.
   296     // Indicate that the histogram was pickled to be sent across an IPC Channel.
   297     // If we observe this flag on a histogram being aggregated into after IPC,
   298     // then we are running in a single process mode, and the aggregation should
   299     // not take place (as we would be aggregating back into the source
   300     // histogram!).
   301     kIPCSerializationSourceFlag = 0x10,
   303     kHexRangePrintingFlag = 0x8000  // Fancy bucket-naming supported.
   304   };
   306   enum Inconsistencies {
   307     NO_INCONSISTENCIES = 0x0,
   308     RANGE_CHECKSUM_ERROR = 0x1,
   309     BUCKET_ORDER_ERROR = 0x2,
   310     COUNT_HIGH_ERROR = 0x4,
   311     COUNT_LOW_ERROR = 0x8,
   313     NEVER_EXCEEDED_VALUE = 0x10
   314   };
   316   struct DescriptionPair {
   317     Sample sample;
   318     const char* description;  // Null means end of a list of pairs.
   319   };
   321   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
   323   //----------------------------------------------------------------------------
   324   // Statistic values, developed over the life of the histogram.
   326   class SampleSet {
   327    public:
   328     explicit SampleSet();
   329     ~SampleSet();
   331     // Adjust size of counts_ for use with given histogram.
   332     void Resize(const Histogram& histogram);
   333     void CheckSize(const Histogram& histogram) const;
   335     // Accessor for histogram to make routine additions.
   336     void AccumulateWithLinearStats(Sample value, Count count, size_t index);
   337     // Alternate routine for exponential histograms.
   338     // computeExpensiveStatistics should be true if we want to compute log sums.
   339     void AccumulateWithExponentialStats(Sample value, Count count, size_t index,
   340 					bool computeExtendedStatistics);
   342     // Accessor methods.
   343     Count counts(size_t i) const { return counts_[i]; }
   344     Count TotalCount() const;
   345     int64_t sum() const { return sum_; }
   346     uint64_t sum_squares() const { return sum_squares_; }
   347     double log_sum() const { return log_sum_; }
   348     double log_sum_squares() const { return log_sum_squares_; }
   349     int64_t redundant_count() const { return redundant_count_; }
   350     size_t size() const { return counts_.size(); }
   352     // Arithmetic manipulation of corresponding elements of the set.
   353     void Add(const SampleSet& other);
   354     void Subtract(const SampleSet& other);
   356     bool Serialize(Pickle* pickle) const;
   357     bool Deserialize(void** iter, const Pickle& pickle);
   359     size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf);
   361    protected:
   362     // Actual histogram data is stored in buckets, showing the count of values
   363     // that fit into each bucket.
   364     Counts counts_;
   366     // Save simple stats locally.  Note that this MIGHT get done in base class
   367     // without shared memory at some point.
   368     int64_t sum_;         // sum of samples.
   369     uint64_t sum_squares_; // sum of squares of samples.
   371     // These fields may or may not be updated at the discretion of the
   372     // histogram.  We use the natural log and compute ln(sample+1) so that
   373     // zeros are handled sanely.
   374     double log_sum_;      // sum of logs of samples.
   375     double log_sum_squares_; // sum of squares of logs of samples
   377    private:
   378     void Accumulate(Sample value, Count count, size_t index);
   380     // To help identify memory corruption, we reduntantly save the number of
   381     // samples we've accumulated into all of our buckets.  We can compare this
   382     // count to the sum of the counts in all buckets, and detect problems.  Note
   383     // that due to races in histogram accumulation (if a histogram is indeed
   384     // updated on several threads simultaneously), the tallies might mismatch,
   385     // and also the snapshotting code may asynchronously get a mismatch (though
   386     // generally either race based mismatch cause is VERY rare).
   387     int64_t redundant_count_;
   388   };
   390   //----------------------------------------------------------------------------
   391   // minimum should start from 1. 0 is invalid as a minimum. 0 is an implicit
   392   // default underflow bucket.
   393   static Histogram* FactoryGet(const std::string& name,
   394                                Sample minimum,
   395                                Sample maximum,
   396                                size_t bucket_count,
   397                                Flags flags);
   398   static Histogram* FactoryTimeGet(const std::string& name,
   399                                    base::TimeDelta minimum,
   400                                    base::TimeDelta maximum,
   401                                    size_t bucket_count,
   402                                    Flags flags);
   404   void Add(int value);
   405   void Subtract(int value);
   407   // This method is an interface, used only by BooleanHistogram.
   408   virtual void AddBoolean(bool value);
   410   // Accept a TimeDelta to increment.
   411   void AddTime(TimeDelta time) {
   412     Add(static_cast<int>(time.InMilliseconds()));
   413   }
   415   virtual void AddSampleSet(const SampleSet& sample);
   417   void Clear();
   419   // This method is an interface, used only by LinearHistogram.
   420   virtual void SetRangeDescriptions(const DescriptionPair descriptions[]);
   422   // The following methods provide graphical histogram displays.
   423   void WriteHTMLGraph(std::string* output) const;
   424   void WriteAscii(bool graph_it, const std::string& newline,
   425                   std::string* output) const;
   427   // Support generic flagging of Histograms.
   428   // 0x1 Currently used to mark this histogram to be recorded by UMA..
   429   // 0x8000 means print ranges in hex.
   430   void SetFlags(Flags flags) { flags_ = static_cast<Flags> (flags_ | flags); }
   431   void ClearFlags(Flags flags) { flags_ = static_cast<Flags>(flags_ & ~flags); }
   432   int flags() const { return flags_; }
   434   // Convenience methods for serializing/deserializing the histograms.
   435   // Histograms from Renderer process are serialized and sent to the browser.
   436   // Browser process reconstructs the histogram from the pickled version
   437   // accumulates the browser-side shadow copy of histograms (that mirror
   438   // histograms created in the renderer).
   440   // Serialize the given snapshot of a Histogram into a String. Uses
   441   // Pickle class to flatten the object.
   442   static std::string SerializeHistogramInfo(const Histogram& histogram,
   443                                             const SampleSet& snapshot);
   444   // The following method accepts a list of pickled histograms and
   445   // builds a histogram and updates shadow copy of histogram data in the
   446   // browser process.
   447   static bool DeserializeHistogramInfo(const std::string& histogram_info);
   449   // Check to see if bucket ranges, counts and tallies in the snapshot are
   450   // consistent with the bucket ranges and checksums in our histogram.  This can
   451   // produce a false-alarm if a race occurred in the reading of the data during
   452   // a SnapShot process, but should otherwise be false at all times (unless we
   453   // have memory over-writes, or DRAM failures).
   454   virtual Inconsistencies FindCorruption(const SampleSet& snapshot) const;
   456   //----------------------------------------------------------------------------
   457   // Accessors for factory constuction, serialization and testing.
   458   //----------------------------------------------------------------------------
   459   virtual ClassType histogram_type() const;
   460   const std::string& histogram_name() const { return histogram_name_; }
   461   Sample declared_min() const { return declared_min_; }
   462   Sample declared_max() const { return declared_max_; }
   463   virtual Sample ranges(size_t i) const;
   464   uint32_t range_checksum() const { return range_checksum_; }
   465   virtual size_t bucket_count() const;
   466   // Snapshot the current complete set of sample data.
   467   // Override with atomic/locked snapshot if needed.
   468   virtual void SnapshotSample(SampleSet* sample) const;
   470   virtual bool HasConstructorArguments(Sample minimum, Sample maximum,
   471                                        size_t bucket_count);
   473   virtual bool HasConstructorTimeDeltaArguments(TimeDelta minimum,
   474                                                 TimeDelta maximum,
   475                                                 size_t bucket_count);
   476   // Return true iff the range_checksum_ matches current ranges_ vector.
   477   bool HasValidRangeChecksum() const;
   479  protected:
   480   Histogram(const std::string& name, Sample minimum,
   481             Sample maximum, size_t bucket_count);
   482   Histogram(const std::string& name, TimeDelta minimum,
   483             TimeDelta maximum, size_t bucket_count);
   485   virtual ~Histogram();
   487   // Initialize ranges_ mapping.
   488   void InitializeBucketRange();
   490   // Method to override to skip the display of the i'th bucket if it's empty.
   491   virtual bool PrintEmptyBucket(size_t index) const;
   493   //----------------------------------------------------------------------------
   494   // Methods to override to create histogram with different bucket widths.
   495   //----------------------------------------------------------------------------
   496   // Find bucket to increment for sample value.
   497   virtual size_t BucketIndex(Sample value) const;
   498   // Get normalized size, relative to the ranges_[i].
   499   virtual double GetBucketSize(Count current, size_t i) const;
   501   // Recalculate range_checksum_.
   502   void ResetRangeChecksum();
   504   // Return a string description of what goes in a given bucket.
   505   // Most commonly this is the numeric value, but in derived classes it may
   506   // be a name (or string description) given to the bucket.
   507   virtual const std::string GetAsciiBucketRange(size_t it) const;
   509   //----------------------------------------------------------------------------
   510   // Methods to override to create thread safe histogram.
   511   //----------------------------------------------------------------------------
   512   // Update all our internal data, including histogram
   513   virtual void Accumulate(Sample value, Count count, size_t index);
   515   //----------------------------------------------------------------------------
   516   // Accessors for derived classes.
   517   //----------------------------------------------------------------------------
   518   void SetBucketRange(size_t i, Sample value);
   520   // Validate that ranges_ was created sensibly (top and bottom range
   521   // values relate properly to the declared_min_ and declared_max_)..
   522   bool ValidateBucketRanges() const;
   524   virtual uint32_t CalculateRangeChecksum() const;
   526   // Finally, provide the state that changes with the addition of each new
   527   // sample.
   528   SampleSet sample_;
   530  private:
   531   friend class StatisticsRecorder;  // To allow it to delete duplicates.
   533   // Post constructor initialization.
   534   void Initialize();
   536   // Checksum function for accumulating range values into a checksum.
   537   static uint32_t Crc32(uint32_t sum, Sample range);
   539   //----------------------------------------------------------------------------
   540   // Helpers for emitting Ascii graphic.  Each method appends data to output.
   542   // Find out how large the (graphically) the largest bucket will appear to be.
   543   double GetPeakBucketSize(const SampleSet& snapshot) const;
   545   // Write a common header message describing this histogram.
   546   void WriteAsciiHeader(const SampleSet& snapshot,
   547                         Count sample_count, std::string* output) const;
   549   // Write information about previous, current, and next buckets.
   550   // Information such as cumulative percentage, etc.
   551   void WriteAsciiBucketContext(const int64_t past, const Count current,
   552                                const int64_t remaining, const size_t i,
   553                                std::string* output) const;
   555   // Write textual description of the bucket contents (relative to histogram).
   556   // Output is the count in the buckets, as well as the percentage.
   557   void WriteAsciiBucketValue(Count current, double scaled_sum,
   558                              std::string* output) const;
   560   // Produce actual graph (set of blank vs non blank char's) for a bucket.
   561   void WriteAsciiBucketGraph(double current_size, double max_size,
   562                              std::string* output) const;
   564   //----------------------------------------------------------------------------
   565   // Table for generating Crc32 values.
   566   static const uint32_t kCrcTable[256];
   567   //----------------------------------------------------------------------------
   568   // Invariant values set at/near construction time
   570   // ASCII version of original name given to the constructor.  All identically
   571   // named instances will be coalesced cross-project.
   572   const std::string histogram_name_;
   573   Sample declared_min_;  // Less than this goes into counts_[0]
   574   Sample declared_max_;  // Over this goes into counts_[bucket_count_ - 1].
   575   size_t bucket_count_;  // Dimension of counts_[].
   577   // Flag the histogram for recording by UMA via metric_services.h.
   578   Flags flags_;
   580   // For each index, show the least value that can be stored in the
   581   // corresponding bucket. We also append one extra element in this array,
   582   // containing kSampleType_MAX, to make calculations easy.
   583   // The dimension of ranges_ is bucket_count + 1.
   584   Ranges ranges_;
   586   // For redundancy, we store a checksum of all the sample ranges when ranges
   587   // are generated.  If ever there is ever a difference, then the histogram must
   588   // have been corrupted.
   589   uint32_t range_checksum_;
   591   DISALLOW_COPY_AND_ASSIGN(Histogram);
   592 };
   594 //------------------------------------------------------------------------------
   596 // LinearHistogram is a more traditional histogram, with evenly spaced
   597 // buckets.
   598 class LinearHistogram : public Histogram {
   599  public:
   600   virtual ~LinearHistogram();
   602   /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit
   603      default underflow bucket. */
   604   static Histogram* FactoryGet(const std::string& name,
   605                                Sample minimum,
   606                                Sample maximum,
   607                                size_t bucket_count,
   608                                Flags flags);
   609   static Histogram* FactoryTimeGet(const std::string& name,
   610                                    TimeDelta minimum,
   611                                    TimeDelta maximum,
   612                                    size_t bucket_count,
   613                                    Flags flags);
   615   // Overridden from Histogram:
   616   virtual ClassType histogram_type() const;
   618   virtual void Accumulate(Sample value, Count count, size_t index);
   620   // Store a list of number/text values for use in rendering the histogram.
   621   // The last element in the array has a null in its "description" slot.
   622   virtual void SetRangeDescriptions(const DescriptionPair descriptions[]);
   624  protected:
   625   LinearHistogram(const std::string& name, Sample minimum,
   626                   Sample maximum, size_t bucket_count);
   628   LinearHistogram(const std::string& name, TimeDelta minimum,
   629                   TimeDelta maximum, size_t bucket_count);
   631   // Initialize ranges_ mapping.
   632   void InitializeBucketRange();
   633   virtual double GetBucketSize(Count current, size_t i) const;
   635   // If we have a description for a bucket, then return that.  Otherwise
   636   // let parent class provide a (numeric) description.
   637   virtual const std::string GetAsciiBucketRange(size_t i) const;
   639   // Skip printing of name for numeric range if we have a name (and if this is
   640   // an empty bucket).
   641   virtual bool PrintEmptyBucket(size_t index) const;
   643  private:
   644   // For some ranges, we store a printable description of a bucket range.
   645   // If there is no desciption, then GetAsciiBucketRange() uses parent class
   646   // to provide a description.
   647   typedef std::map<Sample, std::string> BucketDescriptionMap;
   648   BucketDescriptionMap bucket_description_;
   650   DISALLOW_COPY_AND_ASSIGN(LinearHistogram);
   651 };
   653 //------------------------------------------------------------------------------
   655 // BooleanHistogram is a histogram for booleans.
   656 class BooleanHistogram : public LinearHistogram {
   657  public:
   658   static Histogram* FactoryGet(const std::string& name, Flags flags);
   660   virtual ClassType histogram_type() const;
   662   virtual void AddBoolean(bool value);
   664   virtual void Accumulate(Sample value, Count count, size_t index);
   666  protected:
   667   explicit BooleanHistogram(const std::string& name);
   669   DISALLOW_COPY_AND_ASSIGN(BooleanHistogram);
   670 };
   672 //------------------------------------------------------------------------------
   674 // FlagHistogram is like boolean histogram, but only allows a single off/on value.
   675 class FlagHistogram : public BooleanHistogram
   676 {
   677 public:
   678   static Histogram *FactoryGet(const std::string &name, Flags flags);
   680   virtual ClassType histogram_type() const;
   682   virtual void Accumulate(Sample value, Count count, size_t index);
   684   virtual void AddSampleSet(const SampleSet& sample);
   686 private:
   687   explicit FlagHistogram(const std::string &name);
   688   bool mSwitched;
   690   DISALLOW_COPY_AND_ASSIGN(FlagHistogram);
   691 };
   693 //------------------------------------------------------------------------------
   695 // CustomHistogram is a histogram for a set of custom integers.
   696 class CustomHistogram : public Histogram {
   697  public:
   699   static Histogram* FactoryGet(const std::string& name,
   700                                const std::vector<Sample>& custom_ranges,
   701                                Flags flags);
   703   // Overridden from Histogram:
   704   virtual ClassType histogram_type() const;
   706  protected:
   707   CustomHistogram(const std::string& name,
   708                   const std::vector<Sample>& custom_ranges);
   710   // Initialize ranges_ mapping.
   711   void InitializedCustomBucketRange(const std::vector<Sample>& custom_ranges);
   712   virtual double GetBucketSize(Count current, size_t i) const;
   714   DISALLOW_COPY_AND_ASSIGN(CustomHistogram);
   715 };
   717 //------------------------------------------------------------------------------
   718 // StatisticsRecorder handles all histograms in the system.  It provides a
   719 // general place for histograms to register, and supports a global API for
   720 // accessing (i.e., dumping, or graphing) the data in all the histograms.
   722 class StatisticsRecorder {
   723  public:
   724   typedef std::vector<Histogram*> Histograms;
   726   StatisticsRecorder();
   728   ~StatisticsRecorder();
   730   // Find out if histograms can now be registered into our list.
   731   static bool IsActive();
   733   // Register, or add a new histogram to the collection of statistics. If an
   734   // identically named histogram is already registered, then the argument
   735   // |histogram| will deleted.  The returned value is always the registered
   736   // histogram (either the argument, or the pre-existing registered histogram).
   737   static Histogram* RegisterOrDeleteDuplicate(Histogram* histogram);
   739   // Methods for printing histograms.  Only histograms which have query as
   740   // a substring are written to output (an empty string will process all
   741   // registered histograms).
   742   static void WriteHTMLGraph(const std::string& query, std::string* output);
   743   static void WriteGraph(const std::string& query, std::string* output);
   745   // Method for extracting histograms which were marked for use by UMA.
   746   static void GetHistograms(Histograms* output);
   748   // Find a histogram by name. It matches the exact name. This method is thread
   749   // safe.  If a matching histogram is not found, then the |histogram| is
   750   // not changed.
   751   static bool FindHistogram(const std::string& query, Histogram** histogram);
   753   static bool dump_on_exit() { return dump_on_exit_; }
   755   static void set_dump_on_exit(bool enable) { dump_on_exit_ = enable; }
   757   // GetSnapshot copies some of the pointers to registered histograms into the
   758   // caller supplied vector (Histograms).  Only histograms with names matching
   759   // query are returned. The query must be a substring of histogram name for its
   760   // pointer to be copied.
   761   static void GetSnapshot(const std::string& query, Histograms* snapshot);
   764  private:
   765   // We keep all registered histograms in a map, from name to histogram.
   766   typedef std::map<std::string, Histogram*> HistogramMap;
   768   static HistogramMap* histograms_;
   770   // lock protects access to the above map.
   771   static Lock* lock_;
   773   // Dump all known histograms to log.
   774   static bool dump_on_exit_;
   776   DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder);
   777 };
   779 }  // namespace base
   781 #endif  // BASE_METRICS_HISTOGRAM_H_

mercurial