sparse_histogram.cc 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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/sparse_histogram.h"
  5. #include <utility>
  6. #include "base/logging.h"
  7. #include "base/memory/ptr_util.h"
  8. #include "base/metrics/dummy_histogram.h"
  9. #include "base/metrics/metrics_hashes.h"
  10. #include "base/metrics/persistent_histogram_allocator.h"
  11. #include "base/metrics/persistent_sample_map.h"
  12. #include "base/metrics/sample_map.h"
  13. #include "base/metrics/statistics_recorder.h"
  14. #include "base/notreached.h"
  15. #include "base/pickle.h"
  16. #include "base/strings/utf_string_conversions.h"
  17. #include "base/synchronization/lock.h"
  18. #include "base/values.h"
  19. namespace base {
  20. typedef HistogramBase::Count Count;
  21. typedef HistogramBase::Sample Sample;
  22. // static
  23. HistogramBase* SparseHistogram::FactoryGet(const std::string& name,
  24. int32_t flags) {
  25. HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
  26. if (!histogram) {
  27. // TODO(gayane): |HashMetricName| is called again in Histogram constructor.
  28. // Refactor code to avoid the additional call.
  29. bool should_record =
  30. StatisticsRecorder::ShouldRecordHistogram(HashMetricNameAs32Bits(name));
  31. if (!should_record)
  32. return DummyHistogram::GetInstance();
  33. // Try to create the histogram using a "persistent" allocator. As of
  34. // 2016-02-25, the availability of such is controlled by a base::Feature
  35. // that is off by default. If the allocator doesn't exist or if
  36. // allocating from it fails, code below will allocate the histogram from
  37. // the process heap.
  38. PersistentMemoryAllocator::Reference histogram_ref = 0;
  39. std::unique_ptr<HistogramBase> tentative_histogram;
  40. PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
  41. if (allocator) {
  42. tentative_histogram = allocator->AllocateHistogram(
  43. SPARSE_HISTOGRAM, name, 0, 0, nullptr, flags, &histogram_ref);
  44. }
  45. // Handle the case where no persistent allocator is present or the
  46. // persistent allocation fails (perhaps because it is full).
  47. if (!tentative_histogram) {
  48. DCHECK(!histogram_ref); // Should never have been set.
  49. DCHECK(!allocator); // Shouldn't have failed.
  50. flags &= ~HistogramBase::kIsPersistent;
  51. tentative_histogram.reset(new SparseHistogram(GetPermanentName(name)));
  52. tentative_histogram->SetFlags(flags);
  53. }
  54. // Register this histogram with the StatisticsRecorder. Keep a copy of
  55. // the pointer value to tell later whether the locally created histogram
  56. // was registered or deleted. The type is "void" because it could point
  57. // to released memory after the following line.
  58. const void* tentative_histogram_ptr = tentative_histogram.get();
  59. histogram = StatisticsRecorder::RegisterOrDeleteDuplicate(
  60. tentative_histogram.release());
  61. // Persistent histograms need some follow-up processing.
  62. if (histogram_ref) {
  63. allocator->FinalizeHistogram(histogram_ref,
  64. histogram == tentative_histogram_ptr);
  65. }
  66. }
  67. CHECK_EQ(SPARSE_HISTOGRAM, histogram->GetHistogramType());
  68. return histogram;
  69. }
  70. // static
  71. std::unique_ptr<HistogramBase> SparseHistogram::PersistentCreate(
  72. PersistentHistogramAllocator* allocator,
  73. const char* name,
  74. HistogramSamples::Metadata* meta,
  75. HistogramSamples::Metadata* logged_meta) {
  76. return WrapUnique(new SparseHistogram(allocator, name, meta, logged_meta));
  77. }
  78. SparseHistogram::~SparseHistogram() = default;
  79. uint64_t SparseHistogram::name_hash() const {
  80. return unlogged_samples_->id();
  81. }
  82. HistogramType SparseHistogram::GetHistogramType() const {
  83. return SPARSE_HISTOGRAM;
  84. }
  85. bool SparseHistogram::HasConstructionArguments(
  86. Sample expected_minimum,
  87. Sample expected_maximum,
  88. size_t expected_bucket_count) const {
  89. // SparseHistogram never has min/max/bucket_count limit.
  90. return false;
  91. }
  92. void SparseHistogram::Add(Sample value) {
  93. AddCount(value, 1);
  94. }
  95. void SparseHistogram::AddCount(Sample value, int count) {
  96. if (count <= 0) {
  97. NOTREACHED();
  98. return;
  99. }
  100. {
  101. base::AutoLock auto_lock(lock_);
  102. unlogged_samples_->Accumulate(value, count);
  103. }
  104. if (UNLIKELY(StatisticsRecorder::have_active_callbacks()))
  105. FindAndRunCallbacks(value);
  106. }
  107. std::unique_ptr<HistogramSamples> SparseHistogram::SnapshotSamples() const {
  108. std::unique_ptr<SampleMap> snapshot(new SampleMap(name_hash()));
  109. base::AutoLock auto_lock(lock_);
  110. snapshot->Add(*unlogged_samples_);
  111. snapshot->Add(*logged_samples_);
  112. return std::move(snapshot);
  113. }
  114. std::unique_ptr<HistogramSamples> SparseHistogram::SnapshotDelta() {
  115. DCHECK(!final_delta_created_);
  116. std::unique_ptr<SampleMap> snapshot(new SampleMap(name_hash()));
  117. base::AutoLock auto_lock(lock_);
  118. snapshot->Add(*unlogged_samples_);
  119. unlogged_samples_->Subtract(*snapshot);
  120. logged_samples_->Add(*snapshot);
  121. return std::move(snapshot);
  122. }
  123. std::unique_ptr<HistogramSamples> SparseHistogram::SnapshotFinalDelta() const {
  124. DCHECK(!final_delta_created_);
  125. final_delta_created_ = true;
  126. std::unique_ptr<SampleMap> snapshot(new SampleMap(name_hash()));
  127. base::AutoLock auto_lock(lock_);
  128. snapshot->Add(*unlogged_samples_);
  129. return std::move(snapshot);
  130. }
  131. void SparseHistogram::AddSamples(const HistogramSamples& samples) {
  132. base::AutoLock auto_lock(lock_);
  133. unlogged_samples_->Add(samples);
  134. }
  135. bool SparseHistogram::AddSamplesFromPickle(PickleIterator* iter) {
  136. base::AutoLock auto_lock(lock_);
  137. return unlogged_samples_->AddFromPickle(iter);
  138. }
  139. base::Value::Dict SparseHistogram::ToGraphDict() const {
  140. std::unique_ptr<HistogramSamples> snapshot = SnapshotSamples();
  141. return snapshot->ToGraphDict(histogram_name(), flags());
  142. }
  143. void SparseHistogram::SerializeInfoImpl(Pickle* pickle) const {
  144. pickle->WriteString(histogram_name());
  145. pickle->WriteInt(flags());
  146. }
  147. SparseHistogram::SparseHistogram(const char* name)
  148. : HistogramBase(name),
  149. unlogged_samples_(new SampleMap(HashMetricName(name))),
  150. logged_samples_(new SampleMap(unlogged_samples_->id())) {}
  151. SparseHistogram::SparseHistogram(PersistentHistogramAllocator* allocator,
  152. const char* name,
  153. HistogramSamples::Metadata* meta,
  154. HistogramSamples::Metadata* logged_meta)
  155. : HistogramBase(name),
  156. // While other histogram types maintain a static vector of values with
  157. // sufficient space for both "active" and "logged" samples, with each
  158. // SampleVector being given the appropriate half, sparse histograms
  159. // have no such initial allocation. Each sample has its own record
  160. // attached to a single PersistentSampleMap by a common 64-bit identifier.
  161. // Since a sparse histogram has two sample maps (active and logged),
  162. // there must be two sets of sample records with diffent IDs. The
  163. // "active" samples use, for convenience purposes, an ID matching
  164. // that of the histogram while the "logged" samples use that number
  165. // plus 1.
  166. unlogged_samples_(
  167. new PersistentSampleMap(HashMetricName(name), allocator, meta)),
  168. logged_samples_(new PersistentSampleMap(unlogged_samples_->id() + 1,
  169. allocator,
  170. logged_meta)) {}
  171. HistogramBase* SparseHistogram::DeserializeInfoImpl(PickleIterator* iter) {
  172. std::string histogram_name;
  173. int flags;
  174. if (!iter->ReadString(&histogram_name) || !iter->ReadInt(&flags)) {
  175. DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
  176. return nullptr;
  177. }
  178. flags &= ~HistogramBase::kIPCSerializationSourceFlag;
  179. return SparseHistogram::FactoryGet(histogram_name, flags);
  180. }
  181. Value::Dict SparseHistogram::GetParameters() const {
  182. // Unlike Histogram::GetParameters, only set the type here, and no other
  183. // params. The other params do not make sense for sparse histograms.
  184. Value::Dict params;
  185. params.Set("type", HistogramTypeToString(GetHistogramType()));
  186. return params;
  187. }
  188. } // namespace base