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