histogram_base.cc 8.5 KB

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