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