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"
18 HistogramSnapshotManager::HistogramSnapshotManager(
19 HistogramFlattener
* histogram_flattener
)
20 : histogram_flattener_(histogram_flattener
) {
21 DCHECK(histogram_flattener_
);
24 HistogramSnapshotManager::~HistogramSnapshotManager() {
25 STLDeleteValues(&logged_samples_
);
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
;
35 (*it
)->SetFlags(flag_to_set
);
36 if (record_only_uma
&&
37 0 == ((*it
)->flags() & Histogram::kUmaTargetedHistogramFlag
))
43 void HistogramSnapshotManager::PrepareDelta(const HistogramBase
& histogram
) {
44 DCHECK(histogram_flattener_
);
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();
50 int corruption
= histogram
.FindCorruption(*snapshot
);
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.
60 // Checksum corruption might not have caused order corruption.
61 CHECK_EQ(0, HistogramBase::RANGE_CHECKSUM_ERROR
& corruption
);
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.
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
));
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();
87 // This histogram has not been logged before, add a new entry.
88 logged_samples_
[histogram_name
] = to_log
;
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();
97 if (to_log
->redundant_count() > 0)
98 histogram_flattener_
->RecordDelta(histogram
, *to_log
);
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();
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
);