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