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.
5 #include "base/metrics/histogram_snapshot_manager.h"
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"
15 HistogramSnapshotManager::HistogramSnapshotManager(
16 HistogramFlattener
* histogram_flattener
)
17 : histogram_flattener_(histogram_flattener
) {
18 DCHECK(histogram_flattener_
);
21 HistogramSnapshotManager::~HistogramSnapshotManager() {
22 STLDeleteValues(&logged_samples_
);
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
;
33 (*it
)->SetFlags(flag_to_set
);
34 if (((*it
)->flags() & required_flags
) == required_flags
)
39 void HistogramSnapshotManager::PrepareDelta(const HistogramBase
& histogram
) {
40 DCHECK(histogram_flattener_
);
42 // Get up-to-date snapshot of sample stats.
43 scoped_ptr
<HistogramSamples
> snapshot(histogram
.SnapshotSamples());
44 const std::string
& histogram_name
= histogram
.histogram_name();
46 int corruption
= histogram
.FindCorruption(*snapshot
);
48 // Crash if we detect that our histograms have been overwritten. This may be
49 // a fair distance from the memory smasher, but we hope to correlate these
50 // crashes with other events, such as plugins, or usage patterns, etc.
51 if (HistogramBase::BUCKET_ORDER_ERROR
& corruption
) {
52 // The checksum should have caught this, so crash separately if it didn't.
53 CHECK_NE(0, HistogramBase::RANGE_CHECKSUM_ERROR
& corruption
);
54 CHECK(false); // Crash for the bucket order corruption.
56 // Checksum corruption might not have caused order corruption.
57 CHECK_EQ(0, HistogramBase::RANGE_CHECKSUM_ERROR
& corruption
);
59 // Note, at this point corruption can only be COUNT_HIGH_ERROR or
60 // COUNT_LOW_ERROR and they never arise together, so we don't need to extract
61 // bits from corruption.
63 DLOG(ERROR
) << "Histogram: " << histogram_name
64 << " has data corruption: " << corruption
;
65 histogram_flattener_
->InconsistencyDetected(
66 static_cast<HistogramBase::Inconsistency
>(corruption
));
67 // Don't record corrupt data to metrics services.
68 int old_corruption
= inconsistencies_
[histogram_name
];
69 if (old_corruption
== (corruption
| old_corruption
))
70 return; // We've already seen this corruption for this histogram.
71 inconsistencies_
[histogram_name
] |= corruption
;
72 histogram_flattener_
->UniqueInconsistencyDetected(
73 static_cast<HistogramBase::Inconsistency
>(corruption
));
77 HistogramSamples
* to_log
;
78 std::map
<std::string
, HistogramSamples
*>::iterator it
=
79 logged_samples_
.find(histogram_name
);
80 if (it
== logged_samples_
.end()) {
81 to_log
= snapshot
.release();
83 // This histogram has not been logged before, add a new entry.
84 logged_samples_
[histogram_name
] = to_log
;
86 HistogramSamples
* already_logged
= it
->second
;
87 InspectLoggedSamplesInconsistency(*snapshot
, already_logged
);
88 snapshot
->Subtract(*already_logged
);
89 already_logged
->Add(*snapshot
);
90 to_log
= snapshot
.get();
93 if (to_log
->TotalCount() > 0)
94 histogram_flattener_
->RecordDelta(histogram
, *to_log
);
97 void HistogramSnapshotManager::InspectLoggedSamplesInconsistency(
98 const HistogramSamples
& new_snapshot
,
99 HistogramSamples
* logged_samples
) {
100 HistogramBase::Count discrepancy
=
101 logged_samples
->TotalCount() - logged_samples
->redundant_count();
105 histogram_flattener_
->InconsistencyDetectedInLoggedCount(discrepancy
);
106 if (discrepancy
> Histogram::kCommonRaceBasedCountMismatch
) {
107 // Fix logged_samples.
108 logged_samples
->Subtract(*logged_samples
);
109 logged_samples
->Add(new_snapshot
);