histogram_snapshot_manager.cc 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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_snapshot_manager.h"
  5. #include <memory>
  6. #include "base/debug/alias.h"
  7. #include "base/logging.h"
  8. #include "base/memory/raw_ptr.h"
  9. #include "base/metrics/histogram_flattener.h"
  10. #include "base/metrics/histogram_samples.h"
  11. #include "base/metrics/statistics_recorder.h"
  12. namespace base {
  13. namespace {
  14. // A simple object to set an "active" flag and clear it upon destruction. It is
  15. // an error if the flag is already set.
  16. class MakeActive {
  17. public:
  18. explicit MakeActive(std::atomic<bool>* is_active) : is_active_(is_active) {
  19. bool was_active = is_active_->exchange(true, std::memory_order_relaxed);
  20. CHECK(!was_active);
  21. }
  22. MakeActive(const MakeActive&) = delete;
  23. MakeActive& operator=(const MakeActive&) = delete;
  24. ~MakeActive() { is_active_->store(false, std::memory_order_relaxed); }
  25. private:
  26. raw_ptr<std::atomic<bool>> is_active_;
  27. };
  28. } // namespace
  29. HistogramSnapshotManager::HistogramSnapshotManager(
  30. HistogramFlattener* histogram_flattener)
  31. : histogram_flattener_(histogram_flattener) {
  32. DCHECK(histogram_flattener_);
  33. is_active_.store(false, std::memory_order_relaxed);
  34. }
  35. HistogramSnapshotManager::~HistogramSnapshotManager() = default;
  36. void HistogramSnapshotManager::PrepareDeltas(
  37. const std::vector<HistogramBase*>& histograms,
  38. HistogramBase::Flags flags_to_set,
  39. HistogramBase::Flags required_flags) {
  40. for (HistogramBase* const histogram : histograms) {
  41. histogram->SetFlags(flags_to_set);
  42. if ((histogram->flags() & required_flags) == required_flags)
  43. PrepareDelta(histogram);
  44. }
  45. }
  46. void HistogramSnapshotManager::PrepareDelta(HistogramBase* histogram) {
  47. PrepareSamples(histogram, histogram->SnapshotDelta());
  48. }
  49. void HistogramSnapshotManager::PrepareFinalDelta(
  50. const HistogramBase* histogram) {
  51. PrepareSamples(histogram, histogram->SnapshotFinalDelta());
  52. }
  53. void HistogramSnapshotManager::PrepareSamples(
  54. const HistogramBase* histogram,
  55. std::unique_ptr<HistogramSamples> samples) {
  56. DCHECK(histogram_flattener_);
  57. // Ensure that there is no concurrent access going on while accessing the
  58. // set of known histograms. The flag will be reset when this object goes
  59. // out of scope.
  60. MakeActive make_active(&is_active_);
  61. // Get information known about this histogram. If it did not previously
  62. // exist, one will be created and initialized.
  63. SampleInfo* sample_info = &known_histograms_[histogram->name_hash()];
  64. // Crash if we detect that our histograms have been overwritten. This may be
  65. // a fair distance from the memory smasher, but we hope to correlate these
  66. // crashes with other events, such as plugins, or usage patterns, etc.
  67. uint32_t corruption = histogram->FindCorruption(*samples);
  68. if (HistogramBase::BUCKET_ORDER_ERROR & corruption) {
  69. // Extract fields useful during debug.
  70. const BucketRanges* ranges =
  71. static_cast<const Histogram*>(histogram)->bucket_ranges();
  72. uint32_t ranges_checksum = ranges->checksum();
  73. uint32_t ranges_calc_checksum = ranges->CalculateChecksum();
  74. int32_t flags = histogram->flags();
  75. // The checksum should have caught this, so crash separately if it didn't.
  76. CHECK_NE(0U, HistogramBase::RANGE_CHECKSUM_ERROR & corruption);
  77. CHECK(false); // Crash for the bucket order corruption.
  78. // Ensure that compiler keeps around pointers to |histogram| and its
  79. // internal |bucket_ranges_| for any minidumps.
  80. base::debug::Alias(&ranges_checksum);
  81. base::debug::Alias(&ranges_calc_checksum);
  82. base::debug::Alias(&flags);
  83. }
  84. // Checksum corruption might not have caused order corruption.
  85. CHECK_EQ(0U, HistogramBase::RANGE_CHECKSUM_ERROR & corruption);
  86. // Note, at this point corruption can only be COUNT_HIGH_ERROR or
  87. // COUNT_LOW_ERROR and they never arise together, so we don't need to extract
  88. // bits from corruption.
  89. if (corruption) {
  90. DLOG(ERROR) << "Histogram: \"" << histogram->histogram_name()
  91. << "\" has data corruption: " << corruption;
  92. // Don't record corrupt data to metrics services.
  93. const uint32_t old_corruption = sample_info->inconsistencies;
  94. if (old_corruption == (corruption | old_corruption))
  95. return; // We've already seen this corruption for this histogram.
  96. sample_info->inconsistencies |= corruption;
  97. return;
  98. }
  99. if (samples->TotalCount() > 0)
  100. histogram_flattener_->RecordDelta(*histogram, *samples);
  101. }
  102. } // namespace base