1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/metrics/histogram_snapshot_manager.h"
6
7 #include <memory>
8
9 #include "base/debug/alias.h"
10 #include "base/logging.h"
11 #include "base/memory/raw_ptr.h"
12 #include "base/metrics/histogram_flattener.h"
13 #include "base/metrics/histogram_samples.h"
14
15 namespace base {
16
HistogramSnapshotManager(HistogramFlattener * histogram_flattener)17 HistogramSnapshotManager::HistogramSnapshotManager(
18 HistogramFlattener* histogram_flattener)
19 : histogram_flattener_(histogram_flattener) {
20 DCHECK(histogram_flattener_);
21 }
22
23 HistogramSnapshotManager::~HistogramSnapshotManager() = default;
24
PrepareDeltas(const std::vector<HistogramBase * > & histograms,HistogramBase::Flags flags_to_set,HistogramBase::Flags required_flags)25 void HistogramSnapshotManager::PrepareDeltas(
26 const std::vector<HistogramBase*>& histograms,
27 HistogramBase::Flags flags_to_set,
28 HistogramBase::Flags required_flags) {
29 for (HistogramBase* const histogram : histograms) {
30 histogram->SetFlags(flags_to_set);
31 if (histogram->HasFlags(required_flags)) {
32 PrepareDelta(histogram);
33 }
34 }
35 }
36
SnapshotUnloggedSamples(const std::vector<HistogramBase * > & histograms,HistogramBase::Flags required_flags)37 void HistogramSnapshotManager::SnapshotUnloggedSamples(
38 const std::vector<HistogramBase*>& histograms,
39 HistogramBase::Flags required_flags) {
40 DCHECK(!unlogged_samples_snapshot_taken_);
41 unlogged_samples_snapshot_taken_ = true;
42 for (HistogramBase* const histogram : histograms) {
43 if (histogram->HasFlags(required_flags)) {
44 const HistogramSnapshotPair& histogram_snapshot_pair =
45 histograms_and_snapshots_.emplace_back(
46 histogram, histogram->SnapshotUnloggedSamples());
47 PrepareSamples(histogram_snapshot_pair.first,
48 *histogram_snapshot_pair.second);
49 }
50 }
51 }
52
MarkUnloggedSamplesAsLogged()53 void HistogramSnapshotManager::MarkUnloggedSamplesAsLogged() {
54 DCHECK(unlogged_samples_snapshot_taken_);
55 unlogged_samples_snapshot_taken_ = false;
56 std::vector<HistogramSnapshotPair> histograms_and_snapshots;
57 histograms_and_snapshots.swap(histograms_and_snapshots_);
58 for (auto& [histogram, snapshot] : histograms_and_snapshots) {
59 histogram->MarkSamplesAsLogged(*snapshot);
60 }
61 }
62
PrepareDelta(HistogramBase * histogram)63 void HistogramSnapshotManager::PrepareDelta(HistogramBase* histogram) {
64 std::unique_ptr<HistogramSamples> samples = histogram->SnapshotDelta();
65 PrepareSamples(histogram, *samples);
66 }
67
PrepareFinalDelta(const HistogramBase * histogram)68 void HistogramSnapshotManager::PrepareFinalDelta(
69 const HistogramBase* histogram) {
70 std::unique_ptr<HistogramSamples> samples = histogram->SnapshotFinalDelta();
71 PrepareSamples(histogram, *samples);
72 }
73
PrepareSamples(const HistogramBase * histogram,const HistogramSamples & samples)74 void HistogramSnapshotManager::PrepareSamples(const HistogramBase* histogram,
75 const HistogramSamples& samples) {
76 DCHECK(histogram_flattener_);
77
78 // Crash if we detect that our histograms have been overwritten. This may be
79 // a fair distance from the memory smasher, but we hope to correlate these
80 // crashes with other events, such as plugins, or usage patterns, etc.
81 uint32_t corruption = histogram->FindCorruption(samples);
82 if (HistogramBase::BUCKET_ORDER_ERROR & corruption) {
83 // Extract fields useful during debug.
84 const BucketRanges* ranges =
85 static_cast<const Histogram*>(histogram)->bucket_ranges();
86 uint32_t ranges_checksum = ranges->checksum();
87 uint32_t ranges_calc_checksum = ranges->CalculateChecksum();
88 int32_t flags = histogram->flags();
89 // The checksum should have caught this, so crash separately if it didn't.
90 CHECK_NE(0U, HistogramBase::RANGE_CHECKSUM_ERROR & corruption);
91 CHECK(false); // Crash for the bucket order corruption.
92 // Ensure that compiler keeps around pointers to |histogram| and its
93 // internal |bucket_ranges_| for any minidumps.
94 base::debug::Alias(&ranges_checksum);
95 base::debug::Alias(&ranges_calc_checksum);
96 base::debug::Alias(&flags);
97 }
98 // Checksum corruption might not have caused order corruption.
99 CHECK_EQ(0U, HistogramBase::RANGE_CHECKSUM_ERROR & corruption);
100
101 // Note, at this point corruption can only be COUNT_HIGH_ERROR or
102 // COUNT_LOW_ERROR and they never arise together, so we don't need to extract
103 // bits from corruption.
104 if (corruption) {
105 DLOG(ERROR) << "Histogram: \"" << histogram->histogram_name()
106 << "\" has data corruption: " << corruption;
107 // Don't record corrupt data to metrics services.
108 return;
109 }
110
111 if (samples.TotalCount() > 0)
112 histogram_flattener_->RecordDelta(*histogram, samples);
113 }
114
115 } // namespace base
116