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