LCOV - code coverage report
Current view: directory - ipc/chromium/src/base - histogram.cc (source / functions) Found Hit Coverage
Test: app.info Lines: 627 279 44.5 %
Date: 2012-06-02 Functions: 84 43 51.2 %

       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.
       4                 : 
       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).
       8                 : // See header file for details and examples.
       9                 : 
      10                 : #include "base/histogram.h"
      11                 : 
      12                 : #include <math.h>
      13                 : 
      14                 : #include <algorithm>
      15                 : #include <string>
      16                 : 
      17                 : #include "base/logging.h"
      18                 : #include "base/pickle.h"
      19                 : #include "base/string_util.h"
      20                 : #include "base/logging.h"
      21                 : 
      22                 : namespace base {
      23                 : 
      24                 : #define DVLOG(x) LOG(ERROR)
      25                 : #define CHECK_GT DCHECK_GT
      26                 : #define CHECK_LT DCHECK_LT
      27                 : typedef ::Lock Lock;
      28                 : typedef ::AutoLock AutoLock;
      29                 : 
      30                 : // Static table of checksums for all possible 8 bit bytes.
      31                 : const uint32 Histogram::kCrcTable[256] = {0x0, 0x77073096L, 0xee0e612cL,
      32                 : 0x990951baL, 0x76dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0xedb8832L,
      33                 : 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x9b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
      34                 : 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL,
      35                 : 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL,
      36                 : 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L,
      37                 : 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL,
      38                 : 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
      39                 : 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L,
      40                 : 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL,
      41                 : 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL,
      42                 : 0xb6662d3dL, 0x76dc4190L, 0x1db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L,
      43                 : 0x6b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0xf00f934L, 0x9609a88eL,
      44                 : 0xe10e9818L, 0x7f6a0dbbL, 0x86d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L,
      45                 : 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L,
      46                 : 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL,
      47                 : 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L,
      48                 : 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
      49                 : 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL,
      50                 : 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L,
      51                 : 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L,
      52                 : 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L,
      53                 : 0x9abfb3b6L, 0x3b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x4db2615L,
      54                 : 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0xd6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL,
      55                 : 0x9309ff9dL, 0xa00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L,
      56                 : 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L,
      57                 : 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L,
      58                 : 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
      59                 : 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L,
      60                 : 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL,
      61                 : 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L,
      62                 : 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L,
      63                 : 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
      64                 : 0x26d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x5005713L, 0x95bf4a82L,
      65                 : 0xe2b87a14L, 0x7bb12baeL, 0xcb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L,
      66                 : 0xbdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL,
      67                 : 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL,
      68                 : 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
      69                 : 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL,
      70                 : 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L,
      71                 : 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L,
      72                 : 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL,
      73                 : 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
      74                 : 0x2d02ef8dL,
      75                 : };
      76                 : 
      77                 : typedef Histogram::Count Count;
      78                 : 
      79                 : // static
      80                 : const size_t Histogram::kBucketCount_MAX = 16384u;
      81                 : 
      82           19785 : Histogram* Histogram::FactoryGet(const std::string& name,
      83                 :                                  Sample minimum,
      84                 :                                  Sample maximum,
      85                 :                                  size_t bucket_count,
      86                 :                                  Flags flags) {
      87           19785 :   Histogram* histogram(NULL);
      88                 : 
      89                 :   // Defensive code.
      90           19785 :   if (minimum < 1)
      91               0 :     minimum = 1;
      92           19785 :   if (maximum > kSampleType_MAX - 1)
      93               0 :     maximum = kSampleType_MAX - 1;
      94                 : 
      95           19785 :   if (!StatisticsRecorder::FindHistogram(name, &histogram)) {
      96                 :     // Extra variable is not needed... but this keeps this section basically
      97                 :     // identical to other derived classes in this file (and compiler will
      98                 :     // optimize away the extra variable.
      99                 :     // To avoid racy destruction at shutdown, the following will be leaked.
     100                 :     Histogram* tentative_histogram =
     101           19759 :         new Histogram(name, minimum, maximum, bucket_count);
     102           19759 :     tentative_histogram->InitializeBucketRange();
     103           19759 :     tentative_histogram->SetFlags(flags);
     104                 :     histogram =
     105           19759 :         StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
     106                 :   }
     107                 : 
     108           19785 :   DCHECK_EQ(HISTOGRAM, histogram->histogram_type());
     109           19785 :   DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count));
     110           19785 :   return histogram;
     111                 : }
     112                 : 
     113               0 : Histogram* Histogram::FactoryTimeGet(const std::string& name,
     114                 :                                      TimeDelta minimum,
     115                 :                                      TimeDelta maximum,
     116                 :                                      size_t bucket_count,
     117                 :                                      Flags flags) {
     118               0 :   return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(),
     119               0 :                     bucket_count, flags);
     120                 : }
     121                 : 
     122         1354027 : void Histogram::Add(int value) {
     123         1354027 :   if (value > kSampleType_MAX - 1)
     124               0 :     value = kSampleType_MAX - 1;
     125         1354027 :   if (value < 0)
     126               0 :     value = 0;
     127         1354027 :   size_t index = BucketIndex(value);
     128         1354028 :   DCHECK_GE(value, ranges(index));
     129         1354028 :   DCHECK_LT(value, ranges(index + 1));
     130         1354027 :   Accumulate(value, 1, index);
     131         1354027 : }
     132                 : 
     133              16 : void Histogram::Subtract(int value) {
     134              16 :   if (value > kSampleType_MAX - 1)
     135               0 :     value = kSampleType_MAX - 1;
     136              16 :   if (value < 0)
     137               0 :     value = 0;
     138              16 :   size_t index = BucketIndex(value);
     139              16 :   DCHECK_GE(value, ranges(index));
     140              16 :   DCHECK_LT(value, ranges(index + 1));
     141              16 :   Accumulate(value, -1, index);
     142              16 : }
     143                 : 
     144               0 : void Histogram::AddBoolean(bool value) {
     145               0 :   DCHECK(false);
     146               0 : }
     147                 : 
     148              72 : void Histogram::AddSampleSet(const SampleSet& sample) {
     149              72 :   sample_.Add(sample);
     150              72 : }
     151                 : 
     152               0 : void Histogram::SetRangeDescriptions(const DescriptionPair descriptions[]) {
     153               0 :   DCHECK(false);
     154               0 : }
     155                 : 
     156                 : // The following methods provide a graphical histogram display.
     157               0 : void Histogram::WriteHTMLGraph(std::string* output) const {
     158                 :   // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
     159               0 :   output->append("<PRE>");
     160               0 :   WriteAscii(true, "<br>", output);
     161               0 :   output->append("</PRE>");
     162               0 : }
     163                 : 
     164               0 : void Histogram::WriteAscii(bool graph_it, const std::string& newline,
     165                 :                            std::string* output) const {
     166                 :   // Get local (stack) copies of all effectively volatile class data so that we
     167                 :   // are consistent across our output activities.
     168               0 :   SampleSet snapshot;
     169               0 :   SnapshotSample(&snapshot);
     170               0 :   Count sample_count = snapshot.TotalCount();
     171                 : 
     172               0 :   WriteAsciiHeader(snapshot, sample_count, output);
     173               0 :   output->append(newline);
     174                 : 
     175                 :   // Prepare to normalize graphical rendering of bucket contents.
     176               0 :   double max_size = 0;
     177               0 :   if (graph_it)
     178               0 :     max_size = GetPeakBucketSize(snapshot);
     179                 : 
     180                 :   // Calculate space needed to print bucket range numbers.  Leave room to print
     181                 :   // nearly the largest bucket range without sliding over the histogram.
     182               0 :   size_t largest_non_empty_bucket = bucket_count() - 1;
     183               0 :   while (0 == snapshot.counts(largest_non_empty_bucket)) {
     184               0 :     if (0 == largest_non_empty_bucket)
     185               0 :       break;  // All buckets are empty.
     186               0 :     --largest_non_empty_bucket;
     187                 :   }
     188                 : 
     189                 :   // Calculate largest print width needed for any of our bucket range displays.
     190               0 :   size_t print_width = 1;
     191               0 :   for (size_t i = 0; i < bucket_count(); ++i) {
     192               0 :     if (snapshot.counts(i)) {
     193               0 :       size_t width = GetAsciiBucketRange(i).size() + 1;
     194               0 :       if (width > print_width)
     195               0 :         print_width = width;
     196                 :     }
     197                 :   }
     198                 : 
     199               0 :   int64 remaining = sample_count;
     200               0 :   int64 past = 0;
     201                 :   // Output the actual histogram graph.
     202               0 :   for (size_t i = 0; i < bucket_count(); ++i) {
     203               0 :     Count current = snapshot.counts(i);
     204               0 :     if (!current && !PrintEmptyBucket(i))
     205               0 :       continue;
     206               0 :     remaining -= current;
     207               0 :     std::string range = GetAsciiBucketRange(i);
     208               0 :     output->append(range);
     209               0 :     for (size_t j = 0; range.size() + j < print_width + 1; ++j)
     210               0 :       output->push_back(' ');
     211               0 :     if (0 == current && i < bucket_count() - 1 && 0 == snapshot.counts(i + 1)) {
     212               0 :       while (i < bucket_count() - 1 && 0 == snapshot.counts(i + 1))
     213               0 :         ++i;
     214               0 :       output->append("... ");
     215               0 :       output->append(newline);
     216               0 :       continue;  // No reason to plot emptiness.
     217                 :     }
     218               0 :     double current_size = GetBucketSize(current, i);
     219               0 :     if (graph_it)
     220               0 :       WriteAsciiBucketGraph(current_size, max_size, output);
     221               0 :     WriteAsciiBucketContext(past, current, remaining, i, output);
     222               0 :     output->append(newline);
     223               0 :     past += current;
     224                 :   }
     225               0 :   DCHECK_EQ(sample_count, past);
     226               0 : }
     227                 : 
     228                 : // static
     229               0 : std::string Histogram::SerializeHistogramInfo(const Histogram& histogram,
     230                 :                                               const SampleSet& snapshot) {
     231               0 :   DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type());
     232                 : 
     233               0 :   Pickle pickle;
     234               0 :   pickle.WriteString(histogram.histogram_name());
     235               0 :   pickle.WriteInt(histogram.declared_min());
     236               0 :   pickle.WriteInt(histogram.declared_max());
     237               0 :   pickle.WriteSize(histogram.bucket_count());
     238               0 :   pickle.WriteUInt32(histogram.range_checksum());
     239               0 :   pickle.WriteInt(histogram.histogram_type());
     240               0 :   pickle.WriteInt(histogram.flags());
     241                 : 
     242               0 :   snapshot.Serialize(&pickle);
     243               0 :   return std::string(static_cast<const char*>(pickle.data()), pickle.size());
     244                 : }
     245                 : 
     246                 : // static
     247               0 : bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) {
     248               0 :   if (histogram_info.empty()) {
     249               0 :       return false;
     250                 :   }
     251                 : 
     252                 :   Pickle pickle(histogram_info.data(),
     253               0 :                 static_cast<int>(histogram_info.size()));
     254               0 :   std::string histogram_name;
     255                 :   int declared_min;
     256                 :   int declared_max;
     257                 :   size_t bucket_count;
     258                 :   uint32 range_checksum;
     259                 :   int histogram_type;
     260                 :   int pickle_flags;
     261               0 :   SampleSet sample;
     262                 : 
     263               0 :   void* iter = NULL;
     264               0 :   if (!pickle.ReadString(&iter, &histogram_name) ||
     265               0 :       !pickle.ReadInt(&iter, &declared_min) ||
     266               0 :       !pickle.ReadInt(&iter, &declared_max) ||
     267               0 :       !pickle.ReadSize(&iter, &bucket_count) ||
     268               0 :       !pickle.ReadUInt32(&iter, &range_checksum) ||
     269               0 :       !pickle.ReadInt(&iter, &histogram_type) ||
     270               0 :       !pickle.ReadInt(&iter, &pickle_flags) ||
     271               0 :       !sample.Histogram::SampleSet::Deserialize(&iter, pickle)) {
     272               0 :     LOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
     273               0 :     return false;
     274                 :   }
     275               0 :   DCHECK(pickle_flags & kIPCSerializationSourceFlag);
     276                 :   // Since these fields may have come from an untrusted renderer, do additional
     277                 :   // checks above and beyond those in Histogram::Initialize()
     278               0 :   if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min ||
     279                 :       INT_MAX / sizeof(Count) <= bucket_count || bucket_count < 2) {
     280               0 :     LOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
     281               0 :     return false;
     282                 :   }
     283                 : 
     284               0 :   Flags flags = static_cast<Flags>(pickle_flags & ~kIPCSerializationSourceFlag);
     285                 : 
     286               0 :   DCHECK_NE(NOT_VALID_IN_RENDERER, histogram_type);
     287                 : 
     288               0 :   Histogram* render_histogram(NULL);
     289                 : 
     290               0 :   if (histogram_type == HISTOGRAM) {
     291                 :     render_histogram = Histogram::FactoryGet(
     292               0 :         histogram_name, declared_min, declared_max, bucket_count, flags);
     293               0 :   } else if (histogram_type == LINEAR_HISTOGRAM) {
     294                 :     render_histogram = LinearHistogram::FactoryGet(
     295               0 :         histogram_name, declared_min, declared_max, bucket_count, flags);
     296               0 :   } else if (histogram_type == BOOLEAN_HISTOGRAM) {
     297               0 :     render_histogram = BooleanHistogram::FactoryGet(histogram_name, flags);
     298                 :   } else {
     299               0 :     LOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: "
     300               0 :                << histogram_type;
     301               0 :     return false;
     302                 :   }
     303                 : 
     304               0 :   DCHECK_EQ(render_histogram->declared_min(), declared_min);
     305               0 :   DCHECK_EQ(render_histogram->declared_max(), declared_max);
     306               0 :   DCHECK_EQ(render_histogram->bucket_count(), bucket_count);
     307               0 :   DCHECK_EQ(render_histogram->range_checksum(), range_checksum);
     308               0 :   DCHECK_EQ(render_histogram->histogram_type(), histogram_type);
     309                 : 
     310               0 :   if (render_histogram->flags() & kIPCSerializationSourceFlag) {
     311               0 :     DVLOG(1) << "Single process mode, histogram observed and not copied: "
     312               0 :              << histogram_name;
     313                 :   } else {
     314               0 :     DCHECK_EQ(flags & render_histogram->flags(), flags);
     315               0 :     render_histogram->AddSampleSet(sample);
     316                 :   }
     317                 : 
     318               0 :   return true;
     319                 : }
     320                 : 
     321                 : //------------------------------------------------------------------------------
     322                 : // Methods for the validating a sample and a related histogram.
     323                 : //------------------------------------------------------------------------------
     324                 : 
     325             602 : Histogram::Inconsistencies Histogram::FindCorruption(
     326                 :     const SampleSet& snapshot) const {
     327             602 :   int inconsistencies = NO_INCONSISTENCIES;
     328             602 :   Sample previous_range = -1;  // Bottom range is always 0.
     329             602 :   int64 count = 0;
     330          355452 :   for (size_t index = 0; index < bucket_count(); ++index) {
     331          354850 :     count += snapshot.counts(index);
     332          354850 :     int new_range = ranges(index);
     333          354850 :     if (previous_range >= new_range)
     334               0 :       inconsistencies |= BUCKET_ORDER_ERROR;
     335          354850 :     previous_range = new_range;
     336                 :   }
     337                 : 
     338             602 :   if (!HasValidRangeChecksum())
     339               0 :     inconsistencies |= RANGE_CHECKSUM_ERROR;
     340                 : 
     341             602 :   int64 delta64 = snapshot.redundant_count() - count;
     342             602 :   if (delta64 != 0) {
     343               0 :     int delta = static_cast<int>(delta64);
     344               0 :     if (delta != delta64)
     345               0 :       delta = INT_MAX;  // Flag all giant errors as INT_MAX.
     346                 :     // Since snapshots of histograms are taken asynchronously relative to
     347                 :     // sampling (and snapped from different threads), it is pretty likely that
     348                 :     // we'll catch a redundant count that doesn't match the sample count.  We
     349                 :     // allow for a certain amount of slop before flagging this as an
     350                 :     // inconsistency.  Even with an inconsistency, we'll snapshot it again (for
     351                 :     // UMA in about a half hour, so we'll eventually get the data, if it was
     352                 :     // not the result of a corruption.  If histograms show that 1 is "too tight"
     353                 :     // then we may try to use 2 or 3 for this slop value.
     354               0 :     const int kCommonRaceBasedCountMismatch = 1;
     355               0 :     if (delta > 0) {
     356               0 :       UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta);
     357               0 :       if (delta > kCommonRaceBasedCountMismatch)
     358               0 :         inconsistencies |= COUNT_HIGH_ERROR;
     359                 :     } else {
     360               0 :       DCHECK_GT(0, delta);
     361               0 :       UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta);
     362               0 :       if (-delta > kCommonRaceBasedCountMismatch)
     363               0 :         inconsistencies |= COUNT_LOW_ERROR;
     364                 :     }
     365                 :   }
     366             602 :   return static_cast<Inconsistencies>(inconsistencies);
     367                 : }
     368                 : 
     369           20151 : Histogram::ClassType Histogram::histogram_type() const {
     370           20151 :   return HISTOGRAM;
     371                 : }
     372                 : 
     373        25596624 : Histogram::Sample Histogram::ranges(size_t i) const {
     374        25596624 :   return ranges_[i];
     375                 : }
     376                 : 
     377        34250043 : size_t Histogram::bucket_count() const {
     378        34250043 :   return bucket_count_;
     379                 : }
     380                 : 
     381                 : // Do a safe atomic snapshot of sample data.
     382                 : // This implementation assumes we are on a safe single thread.
     383             724 : void Histogram::SnapshotSample(SampleSet* sample) const {
     384                 :   // Note locking not done in this version!!!
     385             724 :   *sample = sample_;
     386             724 : }
     387                 : 
     388           26150 : bool Histogram::HasConstructorArguments(Sample minimum,
     389                 :                                         Sample maximum,
     390                 :                                         size_t bucket_count) {
     391                 :   return ((minimum == declared_min_) && (maximum == declared_max_) &&
     392           26150 :           (bucket_count == bucket_count_));
     393                 : }
     394                 : 
     395               0 : bool Histogram::HasConstructorTimeDeltaArguments(TimeDelta minimum,
     396                 :                                                  TimeDelta maximum,
     397                 :                                                  size_t bucket_count) {
     398               0 :   return ((minimum.InMilliseconds() == declared_min_) &&
     399               0 :           (maximum.InMilliseconds() == declared_max_) &&
     400               0 :           (bucket_count == bucket_count_));
     401                 : }
     402                 : 
     403           32938 : bool Histogram::HasValidRangeChecksum() const {
     404           32938 :   return CalculateRangeChecksum() == range_checksum_;
     405                 : }
     406                 : 
     407           32336 : Histogram::Histogram(const std::string& name, Sample minimum,
     408                 :                      Sample maximum, size_t bucket_count)
     409                 :   : histogram_name_(name),
     410                 :     declared_min_(minimum),
     411                 :     declared_max_(maximum),
     412                 :     bucket_count_(bucket_count),
     413                 :     flags_(kNoFlags),
     414                 :     ranges_(bucket_count + 1, 0),
     415                 :     range_checksum_(0),
     416           32336 :     sample_() {
     417           32336 :   Initialize();
     418           32336 : }
     419                 : 
     420               0 : Histogram::Histogram(const std::string& name, TimeDelta minimum,
     421                 :                      TimeDelta maximum, size_t bucket_count)
     422                 :   : histogram_name_(name),
     423               0 :     declared_min_(static_cast<int> (minimum.InMilliseconds())),
     424               0 :     declared_max_(static_cast<int> (maximum.InMilliseconds())),
     425                 :     bucket_count_(bucket_count),
     426                 :     flags_(kNoFlags),
     427                 :     ranges_(bucket_count + 1, 0),
     428                 :     range_checksum_(0),
     429               0 :     sample_() {
     430               0 :   Initialize();
     431               0 : }
     432                 : 
     433               0 : Histogram::~Histogram() {
     434               0 :   if (StatisticsRecorder::dump_on_exit()) {
     435               0 :     std::string output;
     436               0 :     WriteAscii(true, "\n", &output);
     437               0 :     LOG(INFO) << output;
     438                 :   }
     439                 : 
     440                 :   // Just to make sure most derived class did this properly...
     441               0 :   DCHECK(ValidateBucketRanges());
     442               0 : }
     443                 : 
     444                 : // Calculate what range of values are held in each bucket.
     445                 : // We have to be careful that we don't pick a ratio between starting points in
     446                 : // consecutive buckets that is sooo small, that the integer bounds are the same
     447                 : // (effectively making one bucket get no values).  We need to avoid:
     448                 : //   ranges_[i] == ranges_[i + 1]
     449                 : // To avoid that, we just do a fine-grained bucket width as far as we need to
     450                 : // until we get a ratio that moves us along at least 2 units at a time.  From
     451                 : // that bucket onward we do use the exponential growth of buckets.
     452           19759 : void Histogram::InitializeBucketRange() {
     453           19759 :   double log_max = log(static_cast<double>(declared_max()));
     454                 :   double log_ratio;
     455                 :   double log_next;
     456           19759 :   size_t bucket_index = 1;
     457           19759 :   Sample current = declared_min();
     458           19759 :   SetBucketRange(bucket_index, current);
     459          707329 :   while (bucket_count() > ++bucket_index) {
     460                 :     double log_current;
     461          667811 :     log_current = log(static_cast<double>(current));
     462                 :     // Calculate the count'th root of the range.
     463          667811 :     log_ratio = (log_max - log_current) / (bucket_count() - bucket_index);
     464                 :     // See where the next bucket would start.
     465          667811 :     log_next = log_current + log_ratio;
     466                 :     int next;
     467          667811 :     next = static_cast<int>(floor(exp(log_next) + 0.5));
     468          667811 :     if (next > current)
     469          646756 :       current = next;
     470                 :     else
     471           21055 :       ++current;  // Just do a narrow bucket, and keep trying.
     472          667811 :     SetBucketRange(bucket_index, current);
     473                 :   }
     474           19759 :   ResetRangeChecksum();
     475                 : 
     476           19759 :   DCHECK_EQ(bucket_count(), bucket_index);
     477           19759 : }
     478                 : 
     479               0 : bool Histogram::PrintEmptyBucket(size_t index) const {
     480               0 :   return true;
     481                 : }
     482                 : 
     483         1354051 : size_t Histogram::BucketIndex(Sample value) const {
     484                 :   // Use simple binary search.  This is very general, but there are better
     485                 :   // approaches if we knew that the buckets were linearly distributed.
     486         1354051 :   DCHECK_LE(ranges(0), value);
     487         1354050 :   DCHECK_GT(ranges(bucket_count()), value);
     488         1354051 :   size_t under = 0;
     489         1354051 :   size_t over = bucket_count();
     490                 :   size_t mid;
     491                 : 
     492         4048969 :   do {
     493         5403020 :     DCHECK_GE(over, under);
     494         5403020 :     mid = under + (over - under)/2;
     495         5403020 :     if (mid == under)
     496                 :       break;
     497         4048969 :     if (ranges(mid) <= value)
     498         1097178 :       under = mid;
     499                 :     else
     500         2951791 :       over = mid;
     501                 :   } while (true);
     502                 : 
     503         1354051 :   DCHECK_LE(ranges(mid), value);
     504         1354051 :   CHECK_GT(ranges(mid+1), value);
     505         1354051 :   return mid;
     506                 : }
     507                 : 
     508                 : // Use the actual bucket widths (like a linear histogram) until the widths get
     509                 : // over some transition value, and then use that transition width.  Exponentials
     510                 : // get so big so fast (and we don't expect to see a lot of entries in the large
     511                 : // buckets), so we need this to make it possible to see what is going on and
     512                 : // not have 0-graphical-height buckets.
     513               0 : double Histogram::GetBucketSize(Count current, size_t i) const {
     514               0 :   DCHECK_GT(ranges(i + 1), ranges(i));
     515                 :   static const double kTransitionWidth = 5;
     516               0 :   double denominator = ranges(i + 1) - ranges(i);
     517               0 :   if (denominator > kTransitionWidth)
     518               0 :     denominator = kTransitionWidth;  // Stop trying to normalize.
     519               0 :   return current/denominator;
     520                 : }
     521                 : 
     522           32336 : void Histogram::ResetRangeChecksum() {
     523           32336 :   range_checksum_ = CalculateRangeChecksum();
     524           32336 : }
     525                 : 
     526               0 : const std::string Histogram::GetAsciiBucketRange(size_t i) const {
     527               0 :   std::string result;
     528               0 :   if (kHexRangePrintingFlag & flags_)
     529               0 :     StringAppendF(&result, "%#x", ranges(i));
     530                 :   else
     531               0 :     StringAppendF(&result, "%d", ranges(i));
     532                 :   return result;
     533                 : }
     534                 : 
     535                 : // Update histogram data with new sample.
     536         1354037 : void Histogram::Accumulate(Sample value, Count count, size_t index) {
     537                 :   // Note locking not done in this version!!!
     538         1354037 :   sample_.Accumulate(value, count, index);
     539         1354036 : }
     540                 : 
     541         6209724 : void Histogram::SetBucketRange(size_t i, Sample value) {
     542         6209724 :   DCHECK_GT(bucket_count_, i);
     543         6209724 :   ranges_[i] = value;
     544         6209724 : }
     545                 : 
     546               0 : bool Histogram::ValidateBucketRanges() const {
     547                 :   // Standard assertions that all bucket ranges should satisfy.
     548               0 :   DCHECK_EQ(bucket_count_ + 1, ranges_.size());
     549               0 :   DCHECK_EQ(0, ranges_[0]);
     550               0 :   DCHECK_EQ(declared_min(), ranges_[1]);
     551               0 :   DCHECK_EQ(declared_max(), ranges_[bucket_count_ - 1]);
     552               0 :   DCHECK_EQ(kSampleType_MAX, ranges_[bucket_count_]);
     553               0 :   return true;
     554                 : }
     555                 : 
     556           65274 : uint32 Histogram::CalculateRangeChecksum() const {
     557           65274 :   DCHECK_EQ(ranges_.size(), bucket_count() + 1);
     558           65274 :   uint32 checksum = static_cast<uint32>(ranges_.size());  // Seed checksum.
     559        12904244 :   for (size_t index = 0; index < bucket_count(); ++index)
     560        12838970 :     checksum = Crc32(checksum, ranges(index));
     561           65274 :   return checksum;
     562                 : }
     563                 : 
     564           32336 : void Histogram::Initialize() {
     565           32336 :   sample_.Resize(*this);
     566           32336 :   if (declared_min_ < 1)
     567               0 :     declared_min_ = 1;
     568           32336 :   if (declared_max_ > kSampleType_MAX - 1)
     569               0 :     declared_max_ = kSampleType_MAX - 1;
     570           32336 :   DCHECK_LE(declared_min_, declared_max_);
     571           32336 :   DCHECK_GT(bucket_count_, 1u);
     572           32336 :   CHECK_LT(bucket_count_, kBucketCount_MAX);
     573           32336 :   size_t maximal_bucket_count = declared_max_ - declared_min_ + 2;
     574           32336 :   DCHECK_LE(bucket_count_, maximal_bucket_count);
     575           32336 :   DCHECK_EQ(0, ranges_[0]);
     576           32336 :   ranges_[bucket_count_] = kSampleType_MAX;
     577           32336 : }
     578                 : 
     579                 : // We generate the CRC-32 using the low order bits to select whether to XOR in
     580                 : // the reversed polynomial 0xedb88320L.  This is nice and simple, and allows us
     581                 : // to keep the quotient in a uint32.  Since we're not concerned about the nature
     582                 : // of corruptions (i.e., we don't care about bit sequencing, since we are
     583                 : // handling memory changes, which are more grotesque) so we don't bother to
     584                 : // get the CRC correct for big-endian vs little-ending calculations.  All we
     585                 : // need is a nice hash, that tends to depend on all the bits of the sample, with
     586                 : // very little chance of changes in one place impacting changes in another
     587                 : // place.
     588        12838970 : uint32 Histogram::Crc32(uint32 sum, Histogram::Sample range) {
     589        12838970 :   const bool kUseRealCrc = true;  // TODO(jar): Switch to false and watch stats.
     590                 :   if (kUseRealCrc) {
     591                 :     union {
     592                 :       Histogram::Sample range;
     593                 :       unsigned char bytes[sizeof(Histogram::Sample)];
     594                 :     } converter;
     595        12838970 :     converter.range = range;
     596        64194850 :     for (size_t i = 0; i < sizeof(converter); ++i)
     597        51355880 :       sum = kCrcTable[(sum & 0xff) ^ converter.bytes[i]] ^ (sum >> 8);
     598                 :   } else {
     599                 :     // Use hash techniques provided in ReallyFastHash, except we don't care
     600                 :     // about "avalanching" (which would worsten the hash, and add collisions),
     601                 :     // and we don't care about edge cases since we have an even number of bytes.
     602                 :     union {
     603                 :       Histogram::Sample range;
     604                 :       uint16 ints[sizeof(Histogram::Sample) / 2];
     605                 :     } converter;
     606                 :     DCHECK_EQ(sizeof(Histogram::Sample), sizeof(converter));
     607                 :     converter.range = range;
     608                 :     sum += converter.ints[0];
     609                 :     sum = (sum << 16) ^ sum ^ (static_cast<uint32>(converter.ints[1]) << 11);
     610                 :     sum += sum >> 11;
     611                 :   }
     612        12838970 :   return sum;
     613                 : }
     614                 : 
     615                 : //------------------------------------------------------------------------------
     616                 : // Private methods
     617                 : 
     618               0 : double Histogram::GetPeakBucketSize(const SampleSet& snapshot) const {
     619               0 :   double max = 0;
     620               0 :   for (size_t i = 0; i < bucket_count() ; ++i) {
     621               0 :     double current_size = GetBucketSize(snapshot.counts(i), i);
     622               0 :     if (current_size > max)
     623               0 :       max = current_size;
     624                 :   }
     625               0 :   return max;
     626                 : }
     627                 : 
     628               0 : void Histogram::WriteAsciiHeader(const SampleSet& snapshot,
     629                 :                                  Count sample_count,
     630                 :                                  std::string* output) const {
     631                 :   StringAppendF(output,
     632                 :                 "Histogram: %s recorded %d samples",
     633               0 :                 histogram_name().c_str(),
     634               0 :                 sample_count);
     635               0 :   if (0 == sample_count) {
     636               0 :     DCHECK_EQ(snapshot.sum(), 0);
     637                 :   } else {
     638               0 :     double average = static_cast<float>(snapshot.sum()) / sample_count;
     639                 : 
     640               0 :     StringAppendF(output, ", average = %.1f", average);
     641                 :   }
     642               0 :   if (flags_ & ~kHexRangePrintingFlag)
     643               0 :     StringAppendF(output, " (flags = 0x%x)", flags_ & ~kHexRangePrintingFlag);
     644               0 : }
     645                 : 
     646               0 : void Histogram::WriteAsciiBucketContext(const int64 past,
     647                 :                                         const Count current,
     648                 :                                         const int64 remaining,
     649                 :                                         const size_t i,
     650                 :                                         std::string* output) const {
     651               0 :   double scaled_sum = (past + current + remaining) / 100.0;
     652               0 :   WriteAsciiBucketValue(current, scaled_sum, output);
     653               0 :   if (0 < i) {
     654               0 :     double percentage = past / scaled_sum;
     655               0 :     StringAppendF(output, " {%3.1f%%}", percentage);
     656                 :   }
     657               0 : }
     658                 : 
     659               0 : void Histogram::WriteAsciiBucketValue(Count current, double scaled_sum,
     660                 :                                       std::string* output) const {
     661               0 :   StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum);
     662               0 : }
     663                 : 
     664               0 : void Histogram::WriteAsciiBucketGraph(double current_size, double max_size,
     665                 :                                       std::string* output) const {
     666               0 :   const int k_line_length = 72;  // Maximal horizontal width of graph.
     667                 :   int x_count = static_cast<int>(k_line_length * (current_size / max_size)
     668               0 :                                  + 0.5);
     669               0 :   int x_remainder = k_line_length - x_count;
     670                 : 
     671               0 :   while (0 < x_count--)
     672               0 :     output->append("-");
     673               0 :   output->append("O");
     674               0 :   while (0 < x_remainder--)
     675               0 :     output->append(" ");
     676               0 : }
     677                 : 
     678                 : //------------------------------------------------------------------------------
     679                 : // Methods for the Histogram::SampleSet class
     680                 : //------------------------------------------------------------------------------
     681                 : 
     682           33134 : Histogram::SampleSet::SampleSet()
     683                 :     : counts_(),
     684                 :       sum_(0),
     685           33134 :       redundant_count_(0) {
     686           33134 : }
     687                 : 
     688             798 : Histogram::SampleSet::~SampleSet() {
     689             798 : }
     690                 : 
     691           32336 : void Histogram::SampleSet::Resize(const Histogram& histogram) {
     692           32336 :   counts_.resize(histogram.bucket_count(), 0);
     693           32336 : }
     694                 : 
     695               0 : void Histogram::SampleSet::CheckSize(const Histogram& histogram) const {
     696               0 :   DCHECK_EQ(histogram.bucket_count(), counts_.size());
     697               0 : }
     698                 : 
     699                 : 
     700         1354037 : void Histogram::SampleSet::Accumulate(Sample value,  Count count,
     701                 :                                       size_t index) {
     702         1354037 :   DCHECK(count == 1 || count == -1);
     703         1354037 :   counts_[index] += count;
     704         1354037 :   sum_ += count * value;
     705         1354037 :   redundant_count_ += count;
     706         1354037 :   DCHECK_GE(counts_[index], 0);
     707         1354036 :   DCHECK_GE(sum_, 0);
     708         1354036 :   DCHECK_GE(redundant_count_, 0);
     709         1354036 : }
     710                 : 
     711               0 : Count Histogram::SampleSet::TotalCount() const {
     712               0 :   Count total = 0;
     713               0 :   for (Counts::const_iterator it = counts_.begin();
     714               0 :        it != counts_.end();
     715                 :        ++it) {
     716               0 :     total += *it;
     717                 :   }
     718               0 :   return total;
     719                 : }
     720                 : 
     721              72 : void Histogram::SampleSet::Add(const SampleSet& other) {
     722              72 :   DCHECK_EQ(counts_.size(), other.counts_.size());
     723              72 :   sum_ += other.sum_;
     724              72 :   redundant_count_ += other.redundant_count_;
     725           61910 :   for (size_t index = 0; index < counts_.size(); ++index)
     726           61838 :     counts_[index] += other.counts_[index];
     727              72 : }
     728                 : 
     729               0 : void Histogram::SampleSet::Subtract(const SampleSet& other) {
     730               0 :   DCHECK_EQ(counts_.size(), other.counts_.size());
     731                 :   // Note: Race conditions in snapshotting a sum may lead to (temporary)
     732                 :   // negative values when snapshots are later combined (and deltas calculated).
     733                 :   // As a result, we don't currently CHCEK() for positive values.
     734               0 :   sum_ -= other.sum_;
     735               0 :   redundant_count_ -= other.redundant_count_;
     736               0 :   for (size_t index = 0; index < counts_.size(); ++index) {
     737               0 :     counts_[index] -= other.counts_[index];
     738               0 :     DCHECK_GE(counts_[index], 0);
     739                 :   }
     740               0 : }
     741                 : 
     742              74 : bool Histogram::SampleSet::Serialize(Pickle* pickle) const {
     743              74 :   pickle->WriteInt64(sum_);
     744              74 :   pickle->WriteInt64(redundant_count_);
     745              74 :   pickle->WriteSize(counts_.size());
     746                 : 
     747           41883 :   for (size_t index = 0; index < counts_.size(); ++index) {
     748           41809 :     pickle->WriteInt(counts_[index]);
     749                 :   }
     750                 : 
     751              74 :   return true;
     752                 : }
     753                 : 
     754              74 : bool Histogram::SampleSet::Deserialize(void** iter, const Pickle& pickle) {
     755              74 :   DCHECK_EQ(counts_.size(), 0u);
     756              74 :   DCHECK_EQ(sum_, 0);
     757              74 :   DCHECK_EQ(redundant_count_, 0);
     758                 : 
     759                 :   size_t counts_size;
     760                 : 
     761             222 :   if (!pickle.ReadInt64(iter, &sum_) ||
     762              74 :       !pickle.ReadInt64(iter, &redundant_count_) ||
     763              74 :       !pickle.ReadSize(iter, &counts_size)) {
     764               0 :     return false;
     765                 :   }
     766                 : 
     767              74 :   if (counts_size == 0)
     768               0 :     return false;
     769                 : 
     770              74 :   int count = 0;
     771           41883 :   for (size_t index = 0; index < counts_size; ++index) {
     772                 :     int i;
     773           41809 :     if (!pickle.ReadInt(iter, &i))
     774               0 :       return false;
     775           41809 :     counts_.push_back(i);
     776           41809 :     count += i;
     777                 :   }
     778                 : 
     779              74 :   return true;
     780                 : }
     781                 : 
     782                 : //------------------------------------------------------------------------------
     783                 : // LinearHistogram: This histogram uses a traditional set of evenly spaced
     784                 : // buckets.
     785                 : //------------------------------------------------------------------------------
     786                 : 
     787               0 : LinearHistogram::~LinearHistogram() {
     788               0 : }
     789                 : 
     790            6365 : Histogram* LinearHistogram::FactoryGet(const std::string& name,
     791                 :                                        Sample minimum,
     792                 :                                        Sample maximum,
     793                 :                                        size_t bucket_count,
     794                 :                                        Flags flags) {
     795            6365 :   Histogram* histogram(NULL);
     796                 : 
     797            6365 :   if (minimum < 1)
     798               0 :     minimum = 1;
     799            6365 :   if (maximum > kSampleType_MAX - 1)
     800               0 :     maximum = kSampleType_MAX - 1;
     801                 : 
     802            6365 :   if (!StatisticsRecorder::FindHistogram(name, &histogram)) {
     803                 :     // To avoid racy destruction at shutdown, the following will be leaked.
     804                 :     LinearHistogram* tentative_histogram =
     805            6347 :         new LinearHistogram(name, minimum, maximum, bucket_count);
     806            6347 :     tentative_histogram->InitializeBucketRange();
     807            6347 :     tentative_histogram->SetFlags(flags);
     808                 :     histogram =
     809            6347 :         StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
     810                 :   }
     811                 : 
     812            6365 :   DCHECK_EQ(LINEAR_HISTOGRAM, histogram->histogram_type());
     813            6365 :   DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count));
     814            6365 :   return histogram;
     815                 : }
     816                 : 
     817               0 : Histogram* LinearHistogram::FactoryTimeGet(const std::string& name,
     818                 :                                            TimeDelta minimum,
     819                 :                                            TimeDelta maximum,
     820                 :                                            size_t bucket_count,
     821                 :                                            Flags flags) {
     822               0 :   return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(),
     823               0 :                     bucket_count, flags);
     824                 : }
     825                 : 
     826            6539 : Histogram::ClassType LinearHistogram::histogram_type() const {
     827            6539 :   return LINEAR_HISTOGRAM;
     828                 : }
     829                 : 
     830               0 : void LinearHistogram::SetRangeDescriptions(
     831                 :     const DescriptionPair descriptions[]) {
     832               0 :   for (int i =0; descriptions[i].description; ++i) {
     833               0 :     bucket_description_[descriptions[i].sample] = descriptions[i].description;
     834                 :   }
     835               0 : }
     836                 : 
     837           12577 : LinearHistogram::LinearHistogram(const std::string& name,
     838                 :                                  Sample minimum,
     839                 :                                  Sample maximum,
     840                 :                                  size_t bucket_count)
     841           12577 :     : Histogram(name, minimum >= 1 ? minimum : 1, maximum, bucket_count) {
     842           12577 : }
     843                 : 
     844               0 : LinearHistogram::LinearHistogram(const std::string& name,
     845                 :                                  TimeDelta minimum,
     846                 :                                  TimeDelta maximum,
     847                 :                                  size_t bucket_count)
     848               0 :     : Histogram(name, minimum >= TimeDelta::FromMilliseconds(1) ?
     849                 :                                  minimum : TimeDelta::FromMilliseconds(1),
     850               0 :                 maximum, bucket_count) {
     851               0 : }
     852                 : 
     853           12577 : void LinearHistogram::InitializeBucketRange() {
     854           12577 :   DCHECK_GT(declared_min(), 0);  // 0 is the underflow bucket here.
     855           12577 :   double min = declared_min();
     856           12577 :   double max = declared_max();
     857                 :   size_t i;
     858         5534731 :   for (i = 1; i < bucket_count(); ++i) {
     859         5522154 :     double linear_range = (min * (bucket_count() -1 - i) + max * (i - 1)) /
     860         5522154 :                           (bucket_count() - 2);
     861         5522154 :     SetBucketRange(i, static_cast<int> (linear_range + 0.5));
     862                 :   }
     863           12577 :   ResetRangeChecksum();
     864           12577 : }
     865                 : 
     866               0 : double LinearHistogram::GetBucketSize(Count current, size_t i) const {
     867               0 :   DCHECK_GT(ranges(i + 1), ranges(i));
     868                 :   // Adjacent buckets with different widths would have "surprisingly" many (few)
     869                 :   // samples in a histogram if we didn't normalize this way.
     870               0 :   double denominator = ranges(i + 1) - ranges(i);
     871               0 :   return current/denominator;
     872                 : }
     873                 : 
     874               0 : const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const {
     875               0 :   int range = ranges(i);
     876               0 :   BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
     877               0 :   if (it == bucket_description_.end())
     878               0 :     return Histogram::GetAsciiBucketRange(i);
     879               0 :   return it->second;
     880                 : }
     881                 : 
     882               0 : bool LinearHistogram::PrintEmptyBucket(size_t index) const {
     883               0 :   return bucket_description_.find(ranges(index)) == bucket_description_.end();
     884                 : }
     885                 : 
     886                 : 
     887                 : //------------------------------------------------------------------------------
     888                 : // This section provides implementation for BooleanHistogram.
     889                 : //------------------------------------------------------------------------------
     890                 : 
     891            6225 : Histogram* BooleanHistogram::FactoryGet(const std::string& name, Flags flags) {
     892            6225 :   Histogram* histogram(NULL);
     893                 : 
     894            6225 :   if (!StatisticsRecorder::FindHistogram(name, &histogram)) {
     895                 :     // To avoid racy destruction at shutdown, the following will be leaked.
     896            6224 :     BooleanHistogram* tentative_histogram = new BooleanHistogram(name);
     897            6224 :     tentative_histogram->InitializeBucketRange();
     898            6224 :     tentative_histogram->SetFlags(flags);
     899                 :     histogram =
     900            6224 :         StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
     901                 :   }
     902                 : 
     903            6225 :   DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->histogram_type());
     904            6225 :   return histogram;
     905                 : }
     906                 : 
     907            6255 : Histogram::ClassType BooleanHistogram::histogram_type() const {
     908            6255 :   return BOOLEAN_HISTOGRAM;
     909                 : }
     910                 : 
     911               0 : void BooleanHistogram::AddBoolean(bool value) {
     912               0 :   Add(value ? 1 : 0);
     913               0 : }
     914                 : 
     915            6230 : BooleanHistogram::BooleanHistogram(const std::string& name)
     916            6230 :     : LinearHistogram(name, 1, 2, 3) {
     917            6230 : }
     918                 : 
     919                 : //------------------------------------------------------------------------------
     920                 : // FlagHistogram:
     921                 : //------------------------------------------------------------------------------
     922                 : 
     923                 : Histogram *
     924               6 : FlagHistogram::FactoryGet(const std::string &name, Flags flags)
     925                 : {
     926               6 :   Histogram *h(nsnull);
     927                 : 
     928               6 :   if (!StatisticsRecorder::FindHistogram(name, &h)) {
     929                 :     // To avoid racy destruction at shutdown, the following will be leaked.
     930               6 :     FlagHistogram *fh = new FlagHistogram(name);
     931               6 :     fh->InitializeBucketRange();
     932               6 :     fh->SetFlags(flags);
     933               6 :     size_t zero_index = fh->BucketIndex(0);
     934               6 :     fh->Histogram::Accumulate(1, 1, zero_index);
     935               6 :     h = StatisticsRecorder::RegisterOrDeleteDuplicate(fh);
     936                 :   }
     937                 : 
     938               6 :   return h;
     939                 : }
     940                 : 
     941               6 : FlagHistogram::FlagHistogram(const std::string &name)
     942               6 :   : BooleanHistogram(name), mSwitched(false) {
     943               6 : }
     944                 : 
     945                 : Histogram::ClassType
     946              20 : FlagHistogram::histogram_type() const
     947                 : {
     948              20 :   return FLAG_HISTOGRAM;
     949                 : }
     950                 : 
     951                 : void
     952              15 : FlagHistogram::Accumulate(Sample value, Count count, size_t index)
     953                 : {
     954              15 :   if (mSwitched) {
     955              14 :     return;
     956                 :   }
     957                 : 
     958               1 :   mSwitched = true;
     959               1 :   DCHECK_EQ(value, 1);
     960               1 :   Histogram::Accumulate(value, 1, index);
     961               1 :   size_t zero_index = BucketIndex(0);
     962               1 :   Histogram::Accumulate(1, -1, zero_index);
     963                 : }
     964                 : 
     965                 : //------------------------------------------------------------------------------
     966                 : // CustomHistogram:
     967                 : //------------------------------------------------------------------------------
     968                 : 
     969               0 : Histogram* CustomHistogram::FactoryGet(const std::string& name,
     970                 :                                        const std::vector<Sample>& custom_ranges,
     971                 :                                        Flags flags) {
     972               0 :   Histogram* histogram(NULL);
     973                 : 
     974                 :   // Remove the duplicates in the custom ranges array.
     975               0 :   std::vector<int> ranges = custom_ranges;
     976               0 :   ranges.push_back(0);  // Ensure we have a zero value.
     977               0 :   std::sort(ranges.begin(), ranges.end());
     978               0 :   ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end());
     979               0 :   if (ranges.size() <= 1) {
     980               0 :     DCHECK(false);
     981                 :     // Note that we pushed a 0 in above, so for defensive code....
     982               0 :     ranges.push_back(1);  // Put in some data so we can index to [1].
     983                 :   }
     984                 : 
     985               0 :   DCHECK_LT(ranges.back(), kSampleType_MAX);
     986                 : 
     987               0 :   if (!StatisticsRecorder::FindHistogram(name, &histogram)) {
     988                 :     // To avoid racy destruction at shutdown, the following will be leaked.
     989               0 :     CustomHistogram* tentative_histogram = new CustomHistogram(name, ranges);
     990               0 :     tentative_histogram->InitializedCustomBucketRange(ranges);
     991               0 :     tentative_histogram->SetFlags(flags);
     992                 :     histogram =
     993               0 :         StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
     994                 :   }
     995                 : 
     996               0 :   DCHECK_EQ(histogram->histogram_type(), CUSTOM_HISTOGRAM);
     997               0 :   DCHECK(histogram->HasConstructorArguments(ranges[1], ranges.back(),
     998               0 :                                             ranges.size()));
     999               0 :   return histogram;
    1000                 : }
    1001                 : 
    1002               0 : Histogram::ClassType CustomHistogram::histogram_type() const {
    1003               0 :   return CUSTOM_HISTOGRAM;
    1004                 : }
    1005                 : 
    1006               0 : CustomHistogram::CustomHistogram(const std::string& name,
    1007                 :                                  const std::vector<Sample>& custom_ranges)
    1008               0 :     : Histogram(name, custom_ranges[1], custom_ranges.back(),
    1009               0 :                 custom_ranges.size()) {
    1010               0 :   DCHECK_GT(custom_ranges.size(), 1u);
    1011               0 :   DCHECK_EQ(custom_ranges[0], 0);
    1012               0 : }
    1013                 : 
    1014               0 : void CustomHistogram::InitializedCustomBucketRange(
    1015                 :     const std::vector<Sample>& custom_ranges) {
    1016               0 :   DCHECK_GT(custom_ranges.size(), 1u);
    1017               0 :   DCHECK_EQ(custom_ranges[0], 0);
    1018               0 :   DCHECK_LE(custom_ranges.size(), bucket_count());
    1019               0 :   for (size_t index = 0; index < custom_ranges.size(); ++index)
    1020               0 :     SetBucketRange(index, custom_ranges[index]);
    1021               0 :   ResetRangeChecksum();
    1022               0 : }
    1023                 : 
    1024               0 : double CustomHistogram::GetBucketSize(Count current, size_t i) const {
    1025               0 :   return 1;
    1026                 : }
    1027                 : 
    1028                 : //------------------------------------------------------------------------------
    1029                 : // The next section handles global (central) support for all histograms, as well
    1030                 : // as startup/teardown of this service.
    1031                 : //------------------------------------------------------------------------------
    1032                 : 
    1033                 : // This singleton instance should be started during the single threaded portion
    1034                 : // of main(), and hence it is not thread safe.  It initializes globals to
    1035                 : // provide support for all future calls.
    1036            1464 : StatisticsRecorder::StatisticsRecorder() {
    1037            1464 :   DCHECK(!histograms_);
    1038            1464 :   if (lock_ == NULL) {
    1039                 :     // This will leak on purpose. It's the only way to make sure we won't race
    1040                 :     // against the static uninitialization of the module while one of our
    1041                 :     // static methods relying on the lock get called at an inappropriate time
    1042                 :     // during the termination phase. Since it's a static data member, we will
    1043                 :     // leak one per process, which would be similar to the instance allocated
    1044                 :     // during static initialization and released only on  process termination.
    1045            1464 :     lock_ = new base::Lock;
    1046                 :   }
    1047            2928 :   base::AutoLock auto_lock(*lock_);
    1048            1464 :   histograms_ = new HistogramMap;
    1049            1464 : }
    1050                 : 
    1051            1487 : StatisticsRecorder::~StatisticsRecorder() {
    1052            1487 :   DCHECK(histograms_ && lock_);
    1053                 : 
    1054            1487 :   if (dump_on_exit_) {
    1055               0 :     std::string output;
    1056               0 :     WriteGraph("", &output);
    1057               0 :     LOG(INFO) << output;
    1058                 :   }
    1059                 :   // Clean up.
    1060            1487 :   HistogramMap* histograms = NULL;
    1061                 :   {
    1062            2974 :     base::AutoLock auto_lock(*lock_);
    1063            1487 :     histograms = histograms_;
    1064            1487 :     histograms_ = NULL;
    1065                 :   }
    1066            1487 :   delete histograms;
    1067                 :   // We don't delete lock_ on purpose to avoid having to properly protect
    1068                 :   // against it going away after we checked for NULL in the static methods.
    1069            1487 : }
    1070                 : 
    1071                 : // static
    1072               0 : bool StatisticsRecorder::IsActive() {
    1073               0 :   if (lock_ == NULL)
    1074               0 :     return false;
    1075               0 :   base::AutoLock auto_lock(*lock_);
    1076               0 :   return NULL != histograms_;
    1077                 : }
    1078                 : 
    1079           32336 : Histogram* StatisticsRecorder::RegisterOrDeleteDuplicate(Histogram* histogram) {
    1080           32336 :   DCHECK(histogram->HasValidRangeChecksum());
    1081           32336 :   if (lock_ == NULL)
    1082               0 :     return histogram;
    1083           64672 :   base::AutoLock auto_lock(*lock_);
    1084           32336 :   if (!histograms_)
    1085               0 :     return histogram;
    1086           64672 :   const std::string name = histogram->histogram_name();
    1087           32336 :   HistogramMap::iterator it = histograms_->find(name);
    1088                 :   // Avoid overwriting a previous registration.
    1089           32336 :   if (histograms_->end() == it) {
    1090           32336 :     (*histograms_)[name] = histogram;
    1091                 :   } else {
    1092               0 :     delete histogram;  // We already have one by this name.
    1093               0 :     histogram = it->second;
    1094                 :   }
    1095           32336 :   return histogram;
    1096                 : }
    1097                 : 
    1098                 : // static
    1099               0 : void StatisticsRecorder::WriteHTMLGraph(const std::string& query,
    1100                 :                                         std::string* output) {
    1101               0 :   if (!IsActive())
    1102               0 :     return;
    1103               0 :   output->append("<html><head><title>About Histograms");
    1104               0 :   if (!query.empty())
    1105               0 :     output->append(" - " + query);
    1106                 :   output->append("</title>"
    1107                 :                  // We'd like the following no-cache... but it doesn't work.
    1108                 :                  // "<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">"
    1109               0 :                  "</head><body>");
    1110                 : 
    1111               0 :   Histograms snapshot;
    1112               0 :   GetSnapshot(query, &snapshot);
    1113               0 :   for (Histograms::iterator it = snapshot.begin();
    1114               0 :        it != snapshot.end();
    1115                 :        ++it) {
    1116               0 :     (*it)->WriteHTMLGraph(output);
    1117               0 :     output->append("<br><hr><br>");
    1118                 :   }
    1119               0 :   output->append("</body></html>");
    1120                 : }
    1121                 : 
    1122                 : // static
    1123               0 : void StatisticsRecorder::WriteGraph(const std::string& query,
    1124                 :                                     std::string* output) {
    1125               0 :   if (!IsActive())
    1126               0 :     return;
    1127               0 :   if (query.length())
    1128               0 :     StringAppendF(output, "Collections of histograms for %s\n", query.c_str());
    1129                 :   else
    1130               0 :     output->append("Collections of all histograms\n");
    1131                 : 
    1132               0 :   Histograms snapshot;
    1133               0 :   GetSnapshot(query, &snapshot);
    1134               0 :   for (Histograms::iterator it = snapshot.begin();
    1135               0 :        it != snapshot.end();
    1136                 :        ++it) {
    1137               0 :     (*it)->WriteAscii(true, "\n", output);
    1138               0 :     output->append("\n");
    1139                 :   }
    1140                 : }
    1141                 : 
    1142                 : // static
    1143              10 : void StatisticsRecorder::GetHistograms(Histograms* output) {
    1144              10 :   if (lock_ == NULL)
    1145               0 :     return;
    1146              20 :   base::AutoLock auto_lock(*lock_);
    1147              10 :   if (!histograms_)
    1148                 :     return;
    1149             814 :   for (HistogramMap::iterator it = histograms_->begin();
    1150             407 :        histograms_->end() != it;
    1151                 :        ++it) {
    1152             397 :     DCHECK_EQ(it->first, it->second->histogram_name());
    1153             397 :     output->push_back(it->second);
    1154                 :   }
    1155                 : }
    1156                 : 
    1157           32381 : bool StatisticsRecorder::FindHistogram(const std::string& name,
    1158                 :                                        Histogram** histogram) {
    1159           32381 :   if (lock_ == NULL)
    1160               0 :     return false;
    1161           64762 :   base::AutoLock auto_lock(*lock_);
    1162           32381 :   if (!histograms_)
    1163               0 :     return false;
    1164           32381 :   HistogramMap::iterator it = histograms_->find(name);
    1165           32381 :   if (histograms_->end() == it)
    1166           32336 :     return false;
    1167              45 :   *histogram = it->second;
    1168              45 :   return true;
    1169                 : }
    1170                 : 
    1171                 : // private static
    1172               0 : void StatisticsRecorder::GetSnapshot(const std::string& query,
    1173                 :                                      Histograms* snapshot) {
    1174               0 :   if (lock_ == NULL)
    1175               0 :     return;
    1176               0 :   base::AutoLock auto_lock(*lock_);
    1177               0 :   if (!histograms_)
    1178                 :     return;
    1179               0 :   for (HistogramMap::iterator it = histograms_->begin();
    1180               0 :        histograms_->end() != it;
    1181                 :        ++it) {
    1182               0 :     if (it->first.find(query) != std::string::npos)
    1183               0 :       snapshot->push_back(it->second);
    1184                 :   }
    1185                 : }
    1186                 : 
    1187                 : // static
    1188                 : StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL;
    1189                 : // static
    1190                 : base::Lock* StatisticsRecorder::lock_ = NULL;
    1191                 : // static
    1192                 : bool StatisticsRecorder::dump_on_exit_ = false;
    1193                 : 
    1194                 : }  // namespace base

Generated by: LCOV version 1.7