statistics_recorder.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  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/statistics_recorder.h"
  5. #include <memory>
  6. #include "base/at_exit.h"
  7. #include "base/containers/contains.h"
  8. #include "base/debug/leak_annotations.h"
  9. #include "base/json/string_escape.h"
  10. #include "base/logging.h"
  11. #include "base/memory/ptr_util.h"
  12. #include "base/metrics/histogram.h"
  13. #include "base/metrics/histogram_snapshot_manager.h"
  14. #include "base/metrics/metrics_hashes.h"
  15. #include "base/metrics/persistent_histogram_allocator.h"
  16. #include "base/metrics/record_histogram_checker.h"
  17. #include "base/ranges/algorithm.h"
  18. #include "base/strings/stringprintf.h"
  19. #include "base/values.h"
  20. namespace base {
  21. namespace {
  22. bool HistogramNameLesser(const base::HistogramBase* a,
  23. const base::HistogramBase* b) {
  24. return strcmp(a->histogram_name(), b->histogram_name()) < 0;
  25. }
  26. } // namespace
  27. // static
  28. LazyInstance<Lock>::Leaky StatisticsRecorder::lock_ = LAZY_INSTANCE_INITIALIZER;
  29. // static
  30. StatisticsRecorder* StatisticsRecorder::top_ = nullptr;
  31. // static
  32. bool StatisticsRecorder::is_vlog_initialized_ = false;
  33. // static
  34. std::atomic<bool> StatisticsRecorder::have_active_callbacks_{false};
  35. // static
  36. std::atomic<StatisticsRecorder::GlobalSampleCallback>
  37. StatisticsRecorder::global_sample_callback_{nullptr};
  38. StatisticsRecorder::ScopedHistogramSampleObserver::
  39. ScopedHistogramSampleObserver(const std::string& name,
  40. OnSampleCallback callback)
  41. : histogram_name_(name), callback_(callback) {
  42. StatisticsRecorder::AddHistogramSampleObserver(histogram_name_, this);
  43. }
  44. StatisticsRecorder::ScopedHistogramSampleObserver::
  45. ~ScopedHistogramSampleObserver() {
  46. StatisticsRecorder::RemoveHistogramSampleObserver(histogram_name_, this);
  47. }
  48. void StatisticsRecorder::ScopedHistogramSampleObserver::RunCallback(
  49. const char* histogram_name,
  50. uint64_t name_hash,
  51. HistogramBase::Sample sample) {
  52. callback_.Run(histogram_name, name_hash, sample);
  53. }
  54. StatisticsRecorder::~StatisticsRecorder() {
  55. const AutoLock auto_lock(lock_.Get());
  56. DCHECK_EQ(this, top_);
  57. top_ = previous_;
  58. }
  59. // static
  60. void StatisticsRecorder::EnsureGlobalRecorderWhileLocked() {
  61. lock_.Get().AssertAcquired();
  62. if (top_)
  63. return;
  64. const StatisticsRecorder* const p = new StatisticsRecorder;
  65. // The global recorder is never deleted.
  66. ANNOTATE_LEAKING_OBJECT_PTR(p);
  67. DCHECK_EQ(p, top_);
  68. }
  69. // static
  70. void StatisticsRecorder::RegisterHistogramProvider(
  71. const WeakPtr<HistogramProvider>& provider) {
  72. const AutoLock auto_lock(lock_.Get());
  73. EnsureGlobalRecorderWhileLocked();
  74. top_->providers_.push_back(provider);
  75. }
  76. // static
  77. HistogramBase* StatisticsRecorder::RegisterOrDeleteDuplicate(
  78. HistogramBase* histogram) {
  79. // Declared before |auto_lock| to ensure correct destruction order.
  80. std::unique_ptr<HistogramBase> histogram_deleter;
  81. const AutoLock auto_lock(lock_.Get());
  82. EnsureGlobalRecorderWhileLocked();
  83. const char* const name = histogram->histogram_name();
  84. HistogramBase*& registered = top_->histograms_[name];
  85. if (!registered) {
  86. // |name| is guaranteed to never change or be deallocated so long
  87. // as the histogram is alive (which is forever).
  88. registered = histogram;
  89. ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322
  90. // If there are callbacks for this histogram, we set the kCallbackExists
  91. // flag.
  92. if (base::Contains(top_->observers_, name))
  93. histogram->SetFlags(HistogramBase::kCallbackExists);
  94. return histogram;
  95. }
  96. if (histogram == registered) {
  97. // The histogram was registered before.
  98. return histogram;
  99. }
  100. // We already have one histogram with this name.
  101. histogram_deleter.reset(histogram);
  102. return registered;
  103. }
  104. // static
  105. const BucketRanges* StatisticsRecorder::RegisterOrDeleteDuplicateRanges(
  106. const BucketRanges* ranges) {
  107. const AutoLock auto_lock(lock_.Get());
  108. EnsureGlobalRecorderWhileLocked();
  109. const BucketRanges* const registered =
  110. top_->ranges_manager_.RegisterOrDeleteDuplicateRanges(ranges);
  111. if (registered == ranges)
  112. ANNOTATE_LEAKING_OBJECT_PTR(ranges);
  113. return registered;
  114. }
  115. // static
  116. void StatisticsRecorder::WriteGraph(const std::string& query,
  117. std::string* output) {
  118. if (query.length())
  119. StringAppendF(output, "Collections of histograms for %s\n", query.c_str());
  120. else
  121. output->append("Collections of all histograms\n");
  122. for (const HistogramBase* const histogram :
  123. Sort(WithName(GetHistograms(), query))) {
  124. histogram->WriteAscii(output);
  125. output->append("\n");
  126. }
  127. }
  128. // static
  129. std::string StatisticsRecorder::ToJSON(JSONVerbosityLevel verbosity_level) {
  130. std::string output = "{\"histograms\":[";
  131. const char* sep = "";
  132. for (const HistogramBase* const histogram : Sort(GetHistograms())) {
  133. output += sep;
  134. sep = ",";
  135. std::string json;
  136. histogram->WriteJSON(&json, verbosity_level);
  137. output += json;
  138. }
  139. output += "]}";
  140. return output;
  141. }
  142. // static
  143. std::vector<const BucketRanges*> StatisticsRecorder::GetBucketRanges() {
  144. const AutoLock auto_lock(lock_.Get());
  145. EnsureGlobalRecorderWhileLocked();
  146. return top_->ranges_manager_.GetBucketRanges();
  147. }
  148. // static
  149. HistogramBase* StatisticsRecorder::FindHistogram(base::StringPiece name) {
  150. // This must be called *before* the lock is acquired below because it will
  151. // call back into this object to register histograms. Those called methods
  152. // will acquire the lock at that time.
  153. ImportGlobalPersistentHistograms();
  154. const AutoLock auto_lock(lock_.Get());
  155. EnsureGlobalRecorderWhileLocked();
  156. const HistogramMap::const_iterator it = top_->histograms_.find(name);
  157. return it != top_->histograms_.end() ? it->second : nullptr;
  158. }
  159. // static
  160. StatisticsRecorder::HistogramProviders
  161. StatisticsRecorder::GetHistogramProviders() {
  162. const AutoLock auto_lock(lock_.Get());
  163. EnsureGlobalRecorderWhileLocked();
  164. return top_->providers_;
  165. }
  166. // static
  167. void StatisticsRecorder::ImportProvidedHistograms() {
  168. // Merge histogram data from each provider in turn.
  169. for (const WeakPtr<HistogramProvider>& provider : GetHistogramProviders()) {
  170. // Weak-pointer may be invalid if the provider was destructed, though they
  171. // generally never are.
  172. if (provider)
  173. provider->MergeHistogramDeltas();
  174. }
  175. }
  176. // static
  177. void StatisticsRecorder::PrepareDeltas(
  178. bool include_persistent,
  179. HistogramBase::Flags flags_to_set,
  180. HistogramBase::Flags required_flags,
  181. HistogramSnapshotManager* snapshot_manager) {
  182. Histograms histograms = GetHistograms();
  183. if (!include_persistent)
  184. histograms = NonPersistent(std::move(histograms));
  185. snapshot_manager->PrepareDeltas(Sort(std::move(histograms)), flags_to_set,
  186. required_flags);
  187. }
  188. // static
  189. void StatisticsRecorder::InitLogOnShutdown() {
  190. const AutoLock auto_lock(lock_.Get());
  191. InitLogOnShutdownWhileLocked();
  192. }
  193. // static
  194. void StatisticsRecorder::AddHistogramSampleObserver(
  195. const std::string& name,
  196. StatisticsRecorder::ScopedHistogramSampleObserver* observer) {
  197. DCHECK(observer);
  198. const AutoLock auto_lock(lock_.Get());
  199. EnsureGlobalRecorderWhileLocked();
  200. auto iter = top_->observers_.find(name);
  201. if (iter == top_->observers_.end()) {
  202. top_->observers_.insert(
  203. {name, base::MakeRefCounted<HistogramSampleObserverList>()});
  204. }
  205. top_->observers_[name]->AddObserver(observer);
  206. const HistogramMap::const_iterator it = top_->histograms_.find(name);
  207. if (it != top_->histograms_.end())
  208. it->second->SetFlags(HistogramBase::kCallbackExists);
  209. have_active_callbacks_.store(
  210. global_sample_callback() || !top_->observers_.empty(),
  211. std::memory_order_relaxed);
  212. }
  213. // static
  214. void StatisticsRecorder::RemoveHistogramSampleObserver(
  215. const std::string& name,
  216. StatisticsRecorder::ScopedHistogramSampleObserver* observer) {
  217. const AutoLock auto_lock(lock_.Get());
  218. EnsureGlobalRecorderWhileLocked();
  219. auto iter = top_->observers_.find(name);
  220. DCHECK(iter != top_->observers_.end());
  221. auto result = iter->second->RemoveObserver(observer);
  222. if (result ==
  223. HistogramSampleObserverList::RemoveObserverResult::kWasOrBecameEmpty) {
  224. top_->observers_.erase(name);
  225. // We also clear the flag from the histogram (if it exists).
  226. const HistogramMap::const_iterator it = top_->histograms_.find(name);
  227. if (it != top_->histograms_.end())
  228. it->second->ClearFlags(HistogramBase::kCallbackExists);
  229. }
  230. have_active_callbacks_.store(
  231. global_sample_callback() || !top_->observers_.empty(),
  232. std::memory_order_relaxed);
  233. }
  234. // static
  235. void StatisticsRecorder::FindAndRunHistogramCallbacks(
  236. base::PassKey<HistogramBase>,
  237. const char* histogram_name,
  238. uint64_t name_hash,
  239. HistogramBase::Sample sample) {
  240. const AutoLock auto_lock(lock_.Get());
  241. EnsureGlobalRecorderWhileLocked();
  242. auto it = top_->observers_.find(histogram_name);
  243. // Ensure that this observer is still registered, as it might have been
  244. // unregistered before we acquired the lock.
  245. if (it == top_->observers_.end())
  246. return;
  247. it->second->Notify(FROM_HERE, &ScopedHistogramSampleObserver::RunCallback,
  248. histogram_name, name_hash, sample);
  249. }
  250. // static
  251. void StatisticsRecorder::SetGlobalSampleCallback(
  252. const GlobalSampleCallback& new_global_sample_callback) {
  253. const AutoLock auto_lock(lock_.Get());
  254. EnsureGlobalRecorderWhileLocked();
  255. DCHECK(!global_sample_callback() || !new_global_sample_callback);
  256. global_sample_callback_.store(new_global_sample_callback);
  257. have_active_callbacks_.store(
  258. new_global_sample_callback || !top_->observers_.empty(),
  259. std::memory_order_relaxed);
  260. }
  261. // static
  262. size_t StatisticsRecorder::GetHistogramCount() {
  263. const AutoLock auto_lock(lock_.Get());
  264. EnsureGlobalRecorderWhileLocked();
  265. return top_->histograms_.size();
  266. }
  267. // static
  268. void StatisticsRecorder::ForgetHistogramForTesting(base::StringPiece name) {
  269. const AutoLock auto_lock(lock_.Get());
  270. EnsureGlobalRecorderWhileLocked();
  271. const HistogramMap::iterator found = top_->histograms_.find(name);
  272. if (found == top_->histograms_.end())
  273. return;
  274. HistogramBase* const base = found->second;
  275. if (base->GetHistogramType() != SPARSE_HISTOGRAM) {
  276. // When forgetting a histogram, it's likely that other information is
  277. // also becoming invalid. Clear the persistent reference that may no
  278. // longer be valid. There's no danger in this as, at worst, duplicates
  279. // will be created in persistent memory.
  280. static_cast<Histogram*>(base)->bucket_ranges()->set_persistent_reference(0);
  281. }
  282. top_->histograms_.erase(found);
  283. }
  284. // static
  285. std::unique_ptr<StatisticsRecorder>
  286. StatisticsRecorder::CreateTemporaryForTesting() {
  287. const AutoLock auto_lock(lock_.Get());
  288. std::unique_ptr<StatisticsRecorder> temporary_recorder =
  289. WrapUnique(new StatisticsRecorder());
  290. temporary_recorder->ranges_manager_
  291. .DoNotReleaseRangesOnDestroyForTesting(); // IN-TEST
  292. return temporary_recorder;
  293. }
  294. // static
  295. void StatisticsRecorder::SetRecordChecker(
  296. std::unique_ptr<RecordHistogramChecker> record_checker) {
  297. const AutoLock auto_lock(lock_.Get());
  298. EnsureGlobalRecorderWhileLocked();
  299. top_->record_checker_ = std::move(record_checker);
  300. }
  301. // static
  302. bool StatisticsRecorder::ShouldRecordHistogram(uint32_t histogram_hash) {
  303. const AutoLock auto_lock(lock_.Get());
  304. EnsureGlobalRecorderWhileLocked();
  305. return !top_->record_checker_ ||
  306. top_->record_checker_->ShouldRecord(histogram_hash);
  307. }
  308. // static
  309. StatisticsRecorder::Histograms StatisticsRecorder::GetHistograms() {
  310. // This must be called *before* the lock is acquired below because it will
  311. // call back into this object to register histograms. Those called methods
  312. // will acquire the lock at that time.
  313. ImportGlobalPersistentHistograms();
  314. Histograms out;
  315. const AutoLock auto_lock(lock_.Get());
  316. EnsureGlobalRecorderWhileLocked();
  317. out.reserve(top_->histograms_.size());
  318. for (const auto& entry : top_->histograms_)
  319. out.push_back(entry.second);
  320. return out;
  321. }
  322. // static
  323. StatisticsRecorder::Histograms StatisticsRecorder::Sort(Histograms histograms) {
  324. ranges::sort(histograms, &HistogramNameLesser);
  325. return histograms;
  326. }
  327. // static
  328. StatisticsRecorder::Histograms StatisticsRecorder::WithName(
  329. Histograms histograms,
  330. const std::string& query) {
  331. // Need a C-string query for comparisons against C-string histogram name.
  332. const char* const query_string = query.c_str();
  333. histograms.erase(
  334. ranges::remove_if(histograms,
  335. [query_string](const HistogramBase* const h) {
  336. return !strstr(h->histogram_name(), query_string);
  337. }),
  338. histograms.end());
  339. return histograms;
  340. }
  341. // static
  342. StatisticsRecorder::Histograms StatisticsRecorder::NonPersistent(
  343. Histograms histograms) {
  344. histograms.erase(
  345. ranges::remove_if(histograms,
  346. [](const HistogramBase* const h) {
  347. return (h->flags() & HistogramBase::kIsPersistent) !=
  348. 0;
  349. }),
  350. histograms.end());
  351. return histograms;
  352. }
  353. // static
  354. void StatisticsRecorder::ImportGlobalPersistentHistograms() {
  355. // Import histograms from known persistent storage. Histograms could have been
  356. // added by other processes and they must be fetched and recognized locally.
  357. // If the persistent memory segment is not shared between processes, this call
  358. // does nothing.
  359. if (GlobalHistogramAllocator* allocator = GlobalHistogramAllocator::Get())
  360. allocator->ImportHistogramsToStatisticsRecorder();
  361. }
  362. StatisticsRecorder::StatisticsRecorder() {
  363. lock_.Get().AssertAcquired();
  364. previous_ = top_;
  365. top_ = this;
  366. InitLogOnShutdownWhileLocked();
  367. }
  368. // static
  369. void StatisticsRecorder::InitLogOnShutdownWhileLocked() {
  370. lock_.Get().AssertAcquired();
  371. if (!is_vlog_initialized_ && VLOG_IS_ON(1)) {
  372. is_vlog_initialized_ = true;
  373. const auto dump_to_vlog = [](void*) {
  374. std::string output;
  375. WriteGraph("", &output);
  376. VLOG(1) << output;
  377. };
  378. AtExitManager::RegisterCallback(dump_to_vlog, nullptr);
  379. }
  380. }
  381. } // namespace base