1 // Copyright (c) 2012 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 #include "base/metrics/sparse_histogram.h" 6 7 #include "base/metrics/sample_map.h" 8 #include "base/metrics/statistics_recorder.h" 9 #include "base/pickle.h" 10 #include "base/strings/stringprintf.h" 11 #include "base/synchronization/lock.h" 12 13 using std::map; 14 using std::string; 15 16 namespace base { 17 18 typedef HistogramBase::Count Count; 19 typedef HistogramBase::Sample Sample; 20 21 // static 22 HistogramBase* SparseHistogram::FactoryGet(const string& name, int32 flags) { 23 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name); 24 25 if (!histogram) { 26 // To avoid racy destruction at shutdown, the following will be leaked. 27 HistogramBase* tentative_histogram = new SparseHistogram(name); 28 tentative_histogram->SetFlags(flags); 29 histogram = 30 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); 31 } 32 DCHECK_EQ(SPARSE_HISTOGRAM, histogram->GetHistogramType()); 33 return histogram; 34 } 35 36 SparseHistogram::~SparseHistogram() {} 37 38 HistogramType SparseHistogram::GetHistogramType() const { 39 return SPARSE_HISTOGRAM; 40 } 41 42 bool SparseHistogram::HasConstructionArguments( 43 Sample expected_minimum, 44 Sample expected_maximum, 45 size_t expected_bucket_count) const { 46 // SparseHistogram never has min/max/bucket_count limit. 47 return false; 48 } 49 50 void SparseHistogram::Add(Sample value) { 51 base::AutoLock auto_lock(lock_); 52 samples_.Accumulate(value, 1); 53 } 54 55 scoped_ptr<HistogramSamples> SparseHistogram::SnapshotSamples() const { 56 scoped_ptr<SampleMap> snapshot(new SampleMap()); 57 58 base::AutoLock auto_lock(lock_); 59 snapshot->Add(samples_); 60 return snapshot.PassAs<HistogramSamples>(); 61 } 62 63 void SparseHistogram::AddSamples(const HistogramSamples& samples) { 64 base::AutoLock auto_lock(lock_); 65 samples_.Add(samples); 66 } 67 68 bool SparseHistogram::AddSamplesFromPickle(PickleIterator* iter) { 69 base::AutoLock auto_lock(lock_); 70 return samples_.AddFromPickle(iter); 71 } 72 73 void SparseHistogram::WriteHTMLGraph(string* output) const { 74 output->append("<PRE>"); 75 WriteAsciiImpl(true, "<br>", output); 76 output->append("</PRE>"); 77 } 78 79 void SparseHistogram::WriteAscii(string* output) const { 80 WriteAsciiImpl(true, "\n", output); 81 } 82 83 bool SparseHistogram::SerializeInfoImpl(Pickle* pickle) const { 84 return pickle->WriteString(histogram_name()) && pickle->WriteInt(flags()); 85 } 86 87 SparseHistogram::SparseHistogram(const string& name) 88 : HistogramBase(name) {} 89 90 HistogramBase* SparseHistogram::DeserializeInfoImpl(PickleIterator* iter) { 91 string histogram_name; 92 int flags; 93 if (!iter->ReadString(&histogram_name) || !iter->ReadInt(&flags)) { 94 DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name; 95 return NULL; 96 } 97 98 DCHECK(flags & HistogramBase::kIPCSerializationSourceFlag); 99 flags &= ~HistogramBase::kIPCSerializationSourceFlag; 100 101 return SparseHistogram::FactoryGet(histogram_name, flags); 102 } 103 104 void SparseHistogram::GetParameters(DictionaryValue* params) const { 105 // TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.) 106 } 107 108 void SparseHistogram::GetCountAndBucketData(Count* count, 109 int64* sum, 110 ListValue* buckets) const { 111 // TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.) 112 } 113 114 void SparseHistogram::WriteAsciiImpl(bool graph_it, 115 const std::string& newline, 116 std::string* output) const { 117 // Get a local copy of the data so we are consistent. 118 scoped_ptr<HistogramSamples> snapshot = SnapshotSamples(); 119 Count total_count = snapshot->TotalCount(); 120 double scaled_total_count = total_count / 100.0; 121 122 WriteAsciiHeader(total_count, output); 123 output->append(newline); 124 125 // Determine how wide the largest bucket range is (how many digits to print), 126 // so that we'll be able to right-align starts for the graphical bars. 127 // Determine which bucket has the largest sample count so that we can 128 // normalize the graphical bar-width relative to that sample count. 129 Count largest_count = 0; 130 Sample largest_sample = 0; 131 scoped_ptr<SampleCountIterator> it = snapshot->Iterator(); 132 while (!it->Done()) 133 { 134 Sample min; 135 Sample max; 136 Count count; 137 it->Get(&min, &max, &count); 138 if (min > largest_sample) 139 largest_sample = min; 140 if (count > largest_count) 141 largest_count = count; 142 it->Next(); 143 } 144 size_t print_width = GetSimpleAsciiBucketRange(largest_sample).size() + 1; 145 146 // iterate over each item and display them 147 it = snapshot->Iterator(); 148 while (!it->Done()) 149 { 150 Sample min; 151 Sample max; 152 Count count; 153 it->Get(&min, &max, &count); 154 155 // value is min, so display it 156 string range = GetSimpleAsciiBucketRange(min); 157 output->append(range); 158 for (size_t j = 0; range.size() + j < print_width + 1; ++j) 159 output->push_back(' '); 160 161 if (graph_it) 162 WriteAsciiBucketGraph(count, largest_count, output); 163 WriteAsciiBucketValue(count, scaled_total_count, output); 164 output->append(newline); 165 it->Next(); 166 } 167 } 168 169 void SparseHistogram::WriteAsciiHeader(const Count total_count, 170 std::string* output) const { 171 StringAppendF(output, 172 "Histogram: %s recorded %d samples", 173 histogram_name().c_str(), 174 total_count); 175 if (flags() & ~kHexRangePrintingFlag) 176 StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag); 177 } 178 179 } // namespace base 180