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