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/histogram_base.h" 6 7 #include <limits.h> 8 9 #include <memory> 10 #include <set> 11 #include <utility> 12 13 #include "base/json/json_string_value_serializer.h" 14 #include "base/lazy_instance.h" 15 #include "base/logging.h" 16 #include "base/metrics/histogram.h" 17 #include "base/metrics/histogram_macros.h" 18 #include "base/metrics/histogram_samples.h" 19 #include "base/metrics/sparse_histogram.h" 20 #include "base/metrics/statistics_recorder.h" 21 #include "base/numerics/safe_conversions.h" 22 #include "base/pickle.h" 23 #include "base/process/process_handle.h" 24 #include "base/rand_util.h" 25 #include "base/strings/stringprintf.h" 26 #include "base/synchronization/lock.h" 27 #include "base/values.h" 28 29 namespace base { 30 31 std::string HistogramTypeToString(HistogramType type) { 32 switch (type) { 33 case HISTOGRAM: 34 return "HISTOGRAM"; 35 case LINEAR_HISTOGRAM: 36 return "LINEAR_HISTOGRAM"; 37 case BOOLEAN_HISTOGRAM: 38 return "BOOLEAN_HISTOGRAM"; 39 case CUSTOM_HISTOGRAM: 40 return "CUSTOM_HISTOGRAM"; 41 case SPARSE_HISTOGRAM: 42 return "SPARSE_HISTOGRAM"; 43 case DUMMY_HISTOGRAM: 44 return "DUMMY_HISTOGRAM"; 45 } 46 NOTREACHED(); 47 return "UNKNOWN"; 48 } 49 50 HistogramBase* DeserializeHistogramInfo(PickleIterator* iter) { 51 int type; 52 if (!iter->ReadInt(&type)) 53 return nullptr; 54 55 switch (type) { 56 case HISTOGRAM: 57 return Histogram::DeserializeInfoImpl(iter); 58 case LINEAR_HISTOGRAM: 59 return LinearHistogram::DeserializeInfoImpl(iter); 60 case BOOLEAN_HISTOGRAM: 61 return BooleanHistogram::DeserializeInfoImpl(iter); 62 case CUSTOM_HISTOGRAM: 63 return CustomHistogram::DeserializeInfoImpl(iter); 64 case SPARSE_HISTOGRAM: 65 return SparseHistogram::DeserializeInfoImpl(iter); 66 default: 67 return nullptr; 68 } 69 } 70 71 const HistogramBase::Sample HistogramBase::kSampleType_MAX = INT_MAX; 72 73 HistogramBase::HistogramBase(const char* name) 74 : histogram_name_(name), flags_(kNoFlags) {} 75 76 HistogramBase::~HistogramBase() = default; 77 78 void HistogramBase::CheckName(const StringPiece& name) const { 79 DCHECK_EQ(StringPiece(histogram_name()), name); 80 } 81 82 void HistogramBase::SetFlags(int32_t flags) { 83 HistogramBase::Count old_flags = subtle::NoBarrier_Load(&flags_); 84 subtle::NoBarrier_Store(&flags_, old_flags | flags); 85 } 86 87 void HistogramBase::ClearFlags(int32_t flags) { 88 HistogramBase::Count old_flags = subtle::NoBarrier_Load(&flags_); 89 subtle::NoBarrier_Store(&flags_, old_flags & ~flags); 90 } 91 92 void HistogramBase::AddScaled(Sample value, int count, int scale) { 93 DCHECK_LT(0, scale); 94 95 // Convert raw count and probabilistically round up/down if the remainder 96 // is more than a random number [0, scale). This gives a more accurate 97 // count when there are a large number of records. RandInt is "inclusive", 98 // hence the -1 for the max value. 99 int64_t count_scaled = count / scale; 100 if (count - (count_scaled * scale) > base::RandInt(0, scale - 1)) 101 count_scaled += 1; 102 if (count_scaled == 0) 103 return; 104 105 AddCount(value, count_scaled); 106 } 107 108 void HistogramBase::AddKilo(Sample value, int count) { 109 AddScaled(value, count, 1000); 110 } 111 112 void HistogramBase::AddKiB(Sample value, int count) { 113 AddScaled(value, count, 1024); 114 } 115 116 void HistogramBase::AddTimeMillisecondsGranularity(const TimeDelta& time) { 117 Add(saturated_cast<Sample>(time.InMilliseconds())); 118 } 119 120 void HistogramBase::AddTimeMicrosecondsGranularity(const TimeDelta& time) { 121 // Intentionally drop high-resolution reports on clients with low-resolution 122 // clocks. High-resolution metrics cannot make use of low-resolution data and 123 // reporting it merely adds noise to the metric. https://crbug.com/807615#c16 124 if (TimeTicks::IsHighResolution()) 125 Add(saturated_cast<Sample>(time.InMicroseconds())); 126 } 127 128 void HistogramBase::AddBoolean(bool value) { 129 Add(value ? 1 : 0); 130 } 131 132 void HistogramBase::SerializeInfo(Pickle* pickle) const { 133 pickle->WriteInt(GetHistogramType()); 134 SerializeInfoImpl(pickle); 135 } 136 137 uint32_t HistogramBase::FindCorruption(const HistogramSamples& samples) const { 138 // Not supported by default. 139 return NO_INCONSISTENCIES; 140 } 141 142 void HistogramBase::ValidateHistogramContents() const {} 143 144 void HistogramBase::WriteJSON(std::string* output, 145 JSONVerbosityLevel verbosity_level) const { 146 Count count; 147 int64_t sum; 148 std::unique_ptr<ListValue> buckets(new ListValue()); 149 GetCountAndBucketData(&count, &sum, buckets.get()); 150 std::unique_ptr<DictionaryValue> parameters(new DictionaryValue()); 151 GetParameters(parameters.get()); 152 153 JSONStringValueSerializer serializer(output); 154 DictionaryValue root; 155 root.SetString("name", histogram_name()); 156 root.SetInteger("count", count); 157 root.SetDouble("sum", static_cast<double>(sum)); 158 root.SetInteger("flags", flags()); 159 root.Set("params", std::move(parameters)); 160 if (verbosity_level != JSON_VERBOSITY_LEVEL_OMIT_BUCKETS) 161 root.Set("buckets", std::move(buckets)); 162 root.SetInteger("pid", GetUniqueIdForProcess()); 163 serializer.Serialize(root); 164 } 165 166 void HistogramBase::FindAndRunCallback(HistogramBase::Sample sample) const { 167 if ((flags() & kCallbackExists) == 0) 168 return; 169 170 StatisticsRecorder::OnSampleCallback cb = 171 StatisticsRecorder::FindCallback(histogram_name()); 172 if (!cb.is_null()) 173 cb.Run(sample); 174 } 175 176 void HistogramBase::WriteAsciiBucketGraph(double current_size, 177 double max_size, 178 std::string* output) const { 179 const int k_line_length = 72; // Maximal horizontal width of graph. 180 int x_count = static_cast<int>(k_line_length * (current_size / max_size) 181 + 0.5); 182 int x_remainder = k_line_length - x_count; 183 184 while (0 < x_count--) 185 output->append("-"); 186 output->append("O"); 187 while (0 < x_remainder--) 188 output->append(" "); 189 } 190 191 const std::string HistogramBase::GetSimpleAsciiBucketRange( 192 Sample sample) const { 193 return StringPrintf("%d", sample); 194 } 195 196 void HistogramBase::WriteAsciiBucketValue(Count current, 197 double scaled_sum, 198 std::string* output) const { 199 StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum); 200 } 201 202 // static 203 char const* HistogramBase::GetPermanentName(const std::string& name) { 204 // A set of histogram names that provides the "permanent" lifetime required 205 // by histogram objects for those strings that are not already code constants 206 // or held in persistent memory. 207 static LazyInstance<std::set<std::string>>::Leaky permanent_names; 208 static LazyInstance<Lock>::Leaky permanent_names_lock; 209 210 AutoLock lock(permanent_names_lock.Get()); 211 auto result = permanent_names.Get().insert(name); 212 return result.first->c_str(); 213 } 214 215 } // namespace base 216