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 |