Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/metrics/histogram_snapshot_manager.h" | 5 #include "base/metrics/histogram_snapshot_manager.h" |
| 6 | 6 |
| 7 #include "base/memory/scoped_ptr.h" | 7 #include "base/memory/scoped_ptr.h" |
| 8 #include "base/metrics/histogram_flattener.h" | 8 #include "base/metrics/histogram_flattener.h" |
| 9 #include "base/metrics/histogram_samples.h" | 9 #include "base/metrics/histogram_samples.h" |
| 10 #include "base/metrics/statistics_recorder.h" | 10 #include "base/metrics/statistics_recorder.h" |
| 11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 12 | 12 |
| 13 namespace { | |
| 14 const int kNewInconsistency = (int)0x80000000; | |
| 15 } // namespace | |
| 16 | |
| 13 namespace base { | 17 namespace base { |
| 14 | 18 |
| 15 HistogramSnapshotManager::HistogramSnapshotManager( | 19 HistogramSnapshotManager::HistogramSnapshotManager( |
| 16 HistogramFlattener* histogram_flattener) | 20 HistogramFlattener* histogram_flattener) |
| 17 : histogram_flattener_(histogram_flattener) { | 21 : histogram_flattener_(histogram_flattener) { |
| 18 DCHECK(histogram_flattener_); | 22 DCHECK(histogram_flattener_); |
| 19 } | 23 } |
| 20 | 24 |
| 21 HistogramSnapshotManager::~HistogramSnapshotManager() { | 25 HistogramSnapshotManager::~HistogramSnapshotManager() { |
| 22 STLDeleteValues(&logged_samples_); | |
| 23 } | 26 } |
| 24 | 27 |
| 25 void HistogramSnapshotManager::PrepareDelta(const HistogramBase& histogram) { | 28 void HistogramSnapshotManager::StartDeltas() { |
| 29 #ifdef DEBUG | |
| 30 for (HashInfoMap::iterator iter = known_histograms_.begin(); | |
| 31 iter != known_histograms_.end(); | |
| 32 ++iter) { | |
| 33 CHECK(!iter->second.histogram); | |
| 34 CHECK(!iter->second.accumulated); | |
| 35 CHECK(!(iter->second.inconsistencies & kNewInconsistency)); | |
| 36 } | |
| 37 #endif | |
| 38 } | |
| 39 | |
| 40 void HistogramSnapshotManager::PrepareDelta(const HistogramBase* histogram) { | |
| 26 DCHECK(histogram_flattener_); | 41 DCHECK(histogram_flattener_); |
| 27 | 42 |
| 28 // Get up-to-date snapshot of sample stats. | 43 // Get up-to-date snapshot of sample stats. |
| 29 scoped_ptr<HistogramSamples> snapshot(histogram.SnapshotSamples()); | 44 scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples()); |
| 30 const std::string& histogram_name = histogram.histogram_name(); | |
| 31 const uint64_t histogram_hash = histogram.name_hash(); | |
| 32 | 45 |
| 33 int corruption = histogram.FindCorruption(*snapshot); | 46 // Get information known about this histogram. |
| 47 const std::string& histogram_name = histogram->histogram_name(); | |
| 48 SampleInfo& sample_info = known_histograms_[histogram->name_hash()]; | |
|
Alexei Svitkine (slow)
2015/12/04 18:30:11
Nit: Make this a pointer, since non-const refs are
bcwhite
2015/12/08 17:32:18
Done.
| |
| 49 if (sample_info.histogram) { | |
| 50 DCHECK_EQ(sample_info.histogram->histogram_name(), histogram_name) | |
| 51 << "hash collision"; | |
| 52 } else { | |
| 53 // First time this histogram has been seen; datafill. | |
| 54 sample_info.histogram = histogram; | |
| 55 } | |
| 34 | 56 |
| 35 // Crash if we detect that our histograms have been overwritten. This may be | 57 // Crash if we detect that our histograms have been overwritten. This may be |
| 36 // a fair distance from the memory smasher, but we hope to correlate these | 58 // a fair distance from the memory smasher, but we hope to correlate these |
| 37 // crashes with other events, such as plugins, or usage patterns, etc. | 59 // crashes with other events, such as plugins, or usage patterns, etc. |
| 60 int corruption = histogram->FindCorruption(*snapshot); | |
| 38 if (HistogramBase::BUCKET_ORDER_ERROR & corruption) { | 61 if (HistogramBase::BUCKET_ORDER_ERROR & corruption) { |
| 39 // The checksum should have caught this, so crash separately if it didn't. | 62 // The checksum should have caught this, so crash separately if it didn't. |
| 40 CHECK_NE(0, HistogramBase::RANGE_CHECKSUM_ERROR & corruption); | 63 CHECK_NE(0, HistogramBase::RANGE_CHECKSUM_ERROR & corruption); |
| 41 CHECK(false); // Crash for the bucket order corruption. | 64 CHECK(false); // Crash for the bucket order corruption. |
| 42 } | 65 } |
| 43 // Checksum corruption might not have caused order corruption. | 66 // Checksum corruption might not have caused order corruption. |
| 44 CHECK_EQ(0, HistogramBase::RANGE_CHECKSUM_ERROR & corruption); | 67 CHECK_EQ(0, HistogramBase::RANGE_CHECKSUM_ERROR & corruption); |
| 45 | 68 |
| 46 // Note, at this point corruption can only be COUNT_HIGH_ERROR or | 69 // Note, at this point corruption can only be COUNT_HIGH_ERROR or |
| 47 // COUNT_LOW_ERROR and they never arise together, so we don't need to extract | 70 // COUNT_LOW_ERROR and they never arise together, so we don't need to extract |
| 48 // bits from corruption. | 71 // bits from corruption. |
| 49 if (corruption) { | 72 if (corruption) { |
| 50 DLOG(ERROR) << "Histogram: " << histogram_name | 73 DLOG(ERROR) << "Histogram \"" << histogram_name |
| 51 << " has data corruption: " << corruption; | 74 << "\" has data corruption: " << corruption; |
| 52 histogram_flattener_->InconsistencyDetected( | 75 histogram_flattener_->InconsistencyDetected( |
| 53 static_cast<HistogramBase::Inconsistency>(corruption)); | 76 static_cast<HistogramBase::Inconsistency>(corruption)); |
| 54 // Don't record corrupt data to metrics services. | 77 // Don't record corrupt data to metrics services. |
| 55 int old_corruption = inconsistencies_[histogram_hash]; | 78 const int old_corruption = sample_info.inconsistencies; |
| 56 if (old_corruption == (corruption | old_corruption)) | 79 if (old_corruption == (corruption | old_corruption)) |
| 57 return; // We've already seen this corruption for this histogram. | 80 return; // We've already seen this corruption for this histogram. |
| 58 inconsistencies_[histogram_hash] |= corruption; | 81 sample_info.inconsistencies |= corruption | kNewInconsistency; |
| 59 histogram_flattener_->UniqueInconsistencyDetected( | 82 // TODO(bcwhite): Can we clear the inconsistency for future collection? |
| 60 static_cast<HistogramBase::Inconsistency>(corruption)); | |
| 61 return; | 83 return; |
| 62 } | 84 } |
| 63 | 85 |
| 64 HistogramSamples* to_log; | 86 if (!sample_info.accumulated) { |
| 65 std::map<uint64_t, HistogramSamples*>::iterator it = | 87 // This histogram has not been seen before; add a new entry. |
| 66 logged_samples_.find(histogram_hash); | 88 sample_info.accumulated = snapshot.release(); |
| 67 if (it == logged_samples_.end()) { | 89 } else { |
| 68 to_log = snapshot.release(); | 90 // There are previous values from this histogram; add them together. |
| 91 sample_info.accumulated->Add(*snapshot); | |
| 92 } | |
| 93 } | |
| 69 | 94 |
| 70 // This histogram has not been logged before, add a new entry. | 95 void HistogramSnapshotManager::FinishDeltas() { |
| 71 logged_samples_[histogram_hash] = to_log; | 96 // Iterate over all known histograms to see what should be recorded. |
| 72 } else { | 97 for (HashInfoMap::iterator iter = known_histograms_.begin(); |
| 73 HistogramSamples* already_logged = it->second; | 98 iter != known_histograms_.end(); |
| 74 InspectLoggedSamplesInconsistency(*snapshot, already_logged); | 99 ++iter) { |
|
Alexei Svitkine (slow)
2015/12/04 18:30:11
Nit: Can this use C++11 for syntax?
bcwhite
2015/12/08 17:32:18
Done.
| |
| 75 snapshot->Subtract(*already_logged); | 100 SampleInfo& sample_info = iter->second; |
| 76 already_logged->Add(*snapshot); | 101 |
| 77 to_log = snapshot.get(); | 102 // First, record any histograms in which corruption was detected. |
| 103 if (sample_info.inconsistencies & kNewInconsistency) { | |
| 104 sample_info.inconsistencies &= ~kNewInconsistency; | |
| 105 histogram_flattener_->UniqueInconsistencyDetected( | |
| 106 static_cast<HistogramBase::Inconsistency>( | |
| 107 sample_info.inconsistencies)); | |
| 108 } | |
| 109 | |
| 110 // Second, record actual sample data. | |
| 111 if (sample_info.accumulated) { | |
| 112 if (sample_info.logged) { | |
| 113 // Subtract the previous report from this one and report that. Since | |
| 114 // the existing sum will be required for the next reporting cycle, | |
| 115 // perform subtraction in-place with the previous values (to be | |
| 116 // released later). LOGGED = CURRENT - LOGGED = -LOGGED + CURRENT | |
| 117 InspectLoggedSamplesInconsistency(*sample_info.accumulated, | |
| 118 sample_info.logged.get()); | |
| 119 sample_info.logged->Negate(); | |
| 120 sample_info.logged->Add(*sample_info.accumulated); | |
| 121 } else { | |
| 122 // This histogram has no previous report; log as-is. | |
| 123 sample_info.logged.reset(sample_info.accumulated); | |
| 124 sample_info.accumulated = nullptr; | |
| 125 } | |
| 126 | |
| 127 if (sample_info.logged->TotalCount() > 0) { | |
| 128 histogram_flattener_->RecordDelta(*sample_info.histogram, | |
| 129 *sample_info.logged.get()); | |
| 130 } | |
| 131 | |
| 132 if (sample_info.accumulated) { | |
| 133 sample_info.logged.reset(sample_info.accumulated); | |
| 134 sample_info.accumulated = nullptr; | |
| 135 } | |
| 136 } else if (sample_info.logged) { | |
| 137 DLOG(ERROR) << "Histogram \"" << sample_info.histogram->histogram_name() | |
| 138 << "\" was lost since previous report"; | |
| 139 sample_info.logged.reset(); | |
| 140 } | |
| 78 } | 141 } |
| 79 | |
| 80 if (to_log->TotalCount() > 0) | |
| 81 histogram_flattener_->RecordDelta(histogram, *to_log); | |
| 82 } | 142 } |
| 83 | 143 |
| 84 void HistogramSnapshotManager::InspectLoggedSamplesInconsistency( | 144 void HistogramSnapshotManager::InspectLoggedSamplesInconsistency( |
| 85 const HistogramSamples& new_snapshot, | 145 const HistogramSamples& new_snapshot, |
| 86 HistogramSamples* logged_samples) { | 146 HistogramSamples* logged_samples) { |
| 87 HistogramBase::Count discrepancy = | 147 HistogramBase::Count discrepancy = |
| 88 logged_samples->TotalCount() - logged_samples->redundant_count(); | 148 logged_samples->TotalCount() - logged_samples->redundant_count(); |
| 89 if (!discrepancy) | 149 if (!discrepancy) |
| 90 return; | 150 return; |
| 91 | 151 |
| 92 histogram_flattener_->InconsistencyDetectedInLoggedCount(discrepancy); | 152 histogram_flattener_->InconsistencyDetectedInLoggedCount(discrepancy); |
| 93 if (discrepancy > Histogram::kCommonRaceBasedCountMismatch) { | 153 if (discrepancy > Histogram::kCommonRaceBasedCountMismatch) { |
| 94 // Fix logged_samples. | 154 // Fix logged_samples. |
| 95 logged_samples->Subtract(*logged_samples); | 155 logged_samples->Subtract(*logged_samples); |
| 96 logged_samples->Add(new_snapshot); | 156 logged_samples->Add(new_snapshot); |
| 97 } | 157 } |
| 98 } | 158 } |
| 99 | 159 |
| 100 } // namespace base | 160 } // namespace base |
| OLD | NEW |