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 <utility> 11 12 #include "base/json/json_string_value_serializer.h" 13 #include "base/logging.h" 14 #include "base/metrics/histogram.h" 15 #include "base/metrics/histogram_samples.h" 16 #include "base/metrics/sparse_histogram.h" 17 #include "base/metrics/statistics_recorder.h" 18 #include "base/pickle.h" 19 #include "base/process/process_handle.h" 20 #include "base/strings/stringprintf.h" 21 #include "base/values.h" 22 23 namespace base { 24 25 std::string HistogramTypeToString(HistogramType type) { 26 switch (type) { 27 case HISTOGRAM: 28 return "HISTOGRAM"; 29 case LINEAR_HISTOGRAM: 30 return "LINEAR_HISTOGRAM"; 31 case BOOLEAN_HISTOGRAM: 32 return "BOOLEAN_HISTOGRAM"; 33 case CUSTOM_HISTOGRAM: 34 return "CUSTOM_HISTOGRAM"; 35 case SPARSE_HISTOGRAM: 36 return "SPARSE_HISTOGRAM"; 37 } 38 NOTREACHED(); 39 return "UNKNOWN"; 40 } 41 42 HistogramBase* DeserializeHistogramInfo(PickleIterator* iter) { 43 int type; 44 if (!iter->ReadInt(&type)) 45 return NULL; 46 47 switch (type) { 48 case HISTOGRAM: 49 return Histogram::DeserializeInfoImpl(iter); 50 case LINEAR_HISTOGRAM: 51 return LinearHistogram::DeserializeInfoImpl(iter); 52 case BOOLEAN_HISTOGRAM: 53 return BooleanHistogram::DeserializeInfoImpl(iter); 54 case CUSTOM_HISTOGRAM: 55 return CustomHistogram::DeserializeInfoImpl(iter); 56 case SPARSE_HISTOGRAM: 57 return SparseHistogram::DeserializeInfoImpl(iter); 58 default: 59 return NULL; 60 } 61 } 62 63 const HistogramBase::Sample HistogramBase::kSampleType_MAX = INT_MAX; 64 HistogramBase* HistogramBase::report_histogram_ = nullptr; 65 66 HistogramBase::HistogramBase(const std::string& name) 67 : histogram_name_(name), 68 flags_(kNoFlags) {} 69 70 HistogramBase::~HistogramBase() {} 71 72 void HistogramBase::CheckName(const StringPiece& name) const { 73 DCHECK_EQ(histogram_name(), name); 74 } 75 76 void HistogramBase::SetFlags(int32_t flags) { 77 HistogramBase::Count old_flags = subtle::NoBarrier_Load(&flags_); 78 subtle::NoBarrier_Store(&flags_, old_flags | flags); 79 } 80 81 void HistogramBase::ClearFlags(int32_t flags) { 82 HistogramBase::Count old_flags = subtle::NoBarrier_Load(&flags_); 83 subtle::NoBarrier_Store(&flags_, old_flags & ~flags); 84 } 85 86 void HistogramBase::AddTime(const TimeDelta& time) { 87 Add(static_cast<Sample>(time.InMilliseconds())); 88 } 89 90 void HistogramBase::AddBoolean(bool value) { 91 Add(value ? 1 : 0); 92 } 93 94 bool HistogramBase::SerializeInfo(Pickle* pickle) const { 95 if (!pickle->WriteInt(GetHistogramType())) 96 return false; 97 return SerializeInfoImpl(pickle); 98 } 99 100 uint32_t HistogramBase::FindCorruption( 101 const HistogramSamples& /*samples*/) const { 102 // Not supported by default. 103 return NO_INCONSISTENCIES; 104 } 105 106 void HistogramBase::WriteJSON(std::string* output) const { 107 Count count; 108 int64_t sum; 109 std::unique_ptr<ListValue> buckets(new ListValue()); 110 GetCountAndBucketData(&count, &sum, buckets.get()); 111 std::unique_ptr<DictionaryValue> parameters(new DictionaryValue()); 112 GetParameters(parameters.get()); 113 114 JSONStringValueSerializer serializer(output); 115 DictionaryValue root; 116 root.SetString("name", histogram_name()); 117 root.SetInteger("count", count); 118 root.SetDouble("sum", static_cast<double>(sum)); 119 root.SetInteger("flags", flags()); 120 root.Set("params", std::move(parameters)); 121 root.Set("buckets", std::move(buckets)); 122 root.SetInteger("pid", GetCurrentProcId()); 123 serializer.Serialize(root); 124 } 125 126 // static 127 void HistogramBase::EnableActivityReportHistogram( 128 const std::string& process_type) { 129 DCHECK(!report_histogram_); 130 size_t existing = StatisticsRecorder::GetHistogramCount(); 131 if (existing != 0) { 132 DVLOG(1) << existing 133 << " histograms were created before reporting was enabled."; 134 } 135 136 std::string name = 137 "UMA.Histograms.Activity" + 138 (process_type.empty() ? process_type : "." + process_type); 139 140 // Calling FactoryGet() here rather than using a histogram-macro works 141 // around some problems with tests that could end up seeing the results 142 // histogram when not expected due to a bad interaction between 143 // HistogramTester and StatisticsRecorder. 144 report_histogram_ = LinearHistogram::FactoryGet( 145 name, 1, HISTOGRAM_REPORT_MAX, HISTOGRAM_REPORT_MAX + 1, 146 kUmaTargetedHistogramFlag); 147 report_histogram_->Add(HISTOGRAM_REPORT_CREATED); 148 } 149 150 void HistogramBase::FindAndRunCallback(HistogramBase::Sample sample) const { 151 if ((flags() & kCallbackExists) == 0) 152 return; 153 154 StatisticsRecorder::OnSampleCallback cb = 155 StatisticsRecorder::FindCallback(histogram_name()); 156 if (!cb.is_null()) 157 cb.Run(sample); 158 } 159 160 void HistogramBase::WriteAsciiBucketGraph(double current_size, 161 double max_size, 162 std::string* output) const { 163 const int k_line_length = 72; // Maximal horizontal width of graph. 164 int x_count = static_cast<int>(k_line_length * (current_size / max_size) 165 + 0.5); 166 int x_remainder = k_line_length - x_count; 167 168 while (0 < x_count--) 169 output->append("-"); 170 output->append("O"); 171 while (0 < x_remainder--) 172 output->append(" "); 173 } 174 175 const std::string HistogramBase::GetSimpleAsciiBucketRange( 176 Sample sample) const { 177 std::string result; 178 if (kHexRangePrintingFlag & flags()) 179 StringAppendF(&result, "%#x", sample); 180 else 181 StringAppendF(&result, "%d", sample); 182 return result; 183 } 184 185 void HistogramBase::WriteAsciiBucketValue(Count current, 186 double scaled_sum, 187 std::string* output) const { 188 StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum); 189 } 190 191 // static 192 void HistogramBase::ReportHistogramActivity(const HistogramBase& histogram, 193 ReportActivity activity) { 194 if (!report_histogram_) 195 return; 196 197 const int32_t flags = histogram.flags_; 198 HistogramReport report_type = HISTOGRAM_REPORT_MAX; 199 switch (activity) { 200 case HISTOGRAM_CREATED: 201 report_histogram_->Add(HISTOGRAM_REPORT_HISTOGRAM_CREATED); 202 switch (histogram.GetHistogramType()) { 203 case HISTOGRAM: 204 report_type = HISTOGRAM_REPORT_TYPE_LOGARITHMIC; 205 break; 206 case LINEAR_HISTOGRAM: 207 report_type = HISTOGRAM_REPORT_TYPE_LINEAR; 208 break; 209 case BOOLEAN_HISTOGRAM: 210 report_type = HISTOGRAM_REPORT_TYPE_BOOLEAN; 211 break; 212 case CUSTOM_HISTOGRAM: 213 report_type = HISTOGRAM_REPORT_TYPE_CUSTOM; 214 break; 215 case SPARSE_HISTOGRAM: 216 report_type = HISTOGRAM_REPORT_TYPE_SPARSE; 217 break; 218 } 219 report_histogram_->Add(report_type); 220 if (flags & kIsPersistent) 221 report_histogram_->Add(HISTOGRAM_REPORT_FLAG_PERSISTENT); 222 if ((flags & kUmaStabilityHistogramFlag) == kUmaStabilityHistogramFlag) 223 report_histogram_->Add(HISTOGRAM_REPORT_FLAG_UMA_STABILITY); 224 else if (flags & kUmaTargetedHistogramFlag) 225 report_histogram_->Add(HISTOGRAM_REPORT_FLAG_UMA_TARGETED); 226 break; 227 228 case HISTOGRAM_LOOKUP: 229 report_histogram_->Add(HISTOGRAM_REPORT_HISTOGRAM_LOOKUP); 230 break; 231 } 232 } 233 234 } // namespace base 235