xref: /aosp_15_r20/external/cronet/base/metrics/histogram_snapshot_manager.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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