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