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 "base/memory/scoped_ptr.h" 8 #include "base/metrics/histogram_flattener.h" 9 #include "base/metrics/histogram_samples.h" 10 #include "base/metrics/statistics_recorder.h" 11 #include "base/stl_util.h" 12 13 namespace base { 14 15 HistogramSnapshotManager::HistogramSnapshotManager( 16 HistogramFlattener* histogram_flattener) 17 : histogram_flattener_(histogram_flattener) { 18 DCHECK(histogram_flattener_); 19 } 20 21 HistogramSnapshotManager::~HistogramSnapshotManager() { 22 STLDeleteValues(&logged_samples_); 23 } 24 25 void HistogramSnapshotManager::PrepareDeltas( 26 HistogramBase::Flags flag_to_set, 27 HistogramBase::Flags required_flags) { 28 StatisticsRecorder::Histograms histograms; 29 StatisticsRecorder::GetHistograms(&histograms); 30 for (StatisticsRecorder::Histograms::const_iterator it = histograms.begin(); 31 histograms.end() != it; 32 ++it) { 33 (*it)->SetFlags(flag_to_set); 34 if (((*it)->flags() & required_flags) == required_flags) 35 PrepareDelta(**it); 36 } 37 } 38 39 void HistogramSnapshotManager::PrepareDelta(const HistogramBase& histogram) { 40 DCHECK(histogram_flattener_); 41 42 // Get up-to-date snapshot of sample stats. 43 scoped_ptr<HistogramSamples> snapshot(histogram.SnapshotSamples()); 44 45 // Crash if we detect that our histograms have been overwritten. This may be 46 // a fair distance from the memory smasher, but we hope to correlate these 47 // crashes with other events, such as plugins, or usage patterns, etc. 48 int corruption = histogram.FindCorruption(*snapshot); 49 if (HistogramBase::BUCKET_ORDER_ERROR & corruption) { 50 // The checksum should have caught this, so crash separately if it didn't. 51 CHECK_NE(0, HistogramBase::RANGE_CHECKSUM_ERROR & corruption); 52 CHECK(false); // Crash for the bucket order corruption. 53 } 54 // Checksum corruption might not have caused order corruption. 55 CHECK_EQ(0, HistogramBase::RANGE_CHECKSUM_ERROR & corruption); 56 57 // Note, at this point corruption can only be COUNT_HIGH_ERROR or 58 // COUNT_LOW_ERROR and they never arise together, so we don't need to extract 59 // bits from corruption. 60 const uint64_t histogram_hash = histogram.name_hash(); 61 if (corruption) { 62 DLOG(ERROR) << "Histogram: " << histogram.histogram_name() 63 << " has data corruption: " << corruption; 64 histogram_flattener_->InconsistencyDetected( 65 static_cast<HistogramBase::Inconsistency>(corruption)); 66 // Don't record corrupt data to metrics services. 67 int old_corruption = inconsistencies_[histogram_hash]; 68 if (old_corruption == (corruption | old_corruption)) 69 return; // We've already seen this corruption for this histogram. 70 inconsistencies_[histogram_hash] |= corruption; 71 histogram_flattener_->UniqueInconsistencyDetected( 72 static_cast<HistogramBase::Inconsistency>(corruption)); 73 return; 74 } 75 76 HistogramSamples* to_log; 77 auto it = logged_samples_.find(histogram_hash); 78 if (it == logged_samples_.end()) { 79 to_log = snapshot.release(); 80 81 // This histogram has not been logged before, add a new entry. 82 logged_samples_[histogram_hash] = to_log; 83 } else { 84 HistogramSamples* already_logged = it->second; 85 InspectLoggedSamplesInconsistency(*snapshot, already_logged); 86 snapshot->Subtract(*already_logged); 87 already_logged->Add(*snapshot); 88 to_log = snapshot.get(); 89 } 90 91 if (to_log->TotalCount() > 0) 92 histogram_flattener_->RecordDelta(histogram, *to_log); 93 } 94 95 void HistogramSnapshotManager::InspectLoggedSamplesInconsistency( 96 const HistogramSamples& new_snapshot, 97 HistogramSamples* logged_samples) { 98 HistogramBase::Count discrepancy = 99 logged_samples->TotalCount() - logged_samples->redundant_count(); 100 if (!discrepancy) 101 return; 102 103 histogram_flattener_->InconsistencyDetectedInLoggedCount(discrepancy); 104 if (discrepancy > Histogram::kCommonRaceBasedCountMismatch) { 105 // Fix logged_samples. 106 logged_samples->Subtract(*logged_samples); 107 logged_samples->Add(new_snapshot); 108 } 109 } 110 111 } // namespace base 112