1 // Copyright 2014 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 #include <string>
9 #include <vector>
10
11 #include "base/containers/contains.h"
12 #include "base/memory/raw_ptr.h"
13 #include "base/metrics/histogram_delta_serialization.h"
14 #include "base/metrics/histogram_functions.h"
15 #include "base/metrics/sample_vector.h"
16 #include "base/metrics/statistics_recorder.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 namespace base {
20
21 namespace {
22
23 const std::string kHistogramName = "UmaHistogram";
24
25 const std::string kStabilityHistogramName = "UmaStabilityHistogram";
26
UmaStabilityHistogramBoolean(const std::string & name,bool sample)27 void UmaStabilityHistogramBoolean(const std::string& name, bool sample) {
28 HistogramBase* histogram = BooleanHistogram::FactoryGet(
29 name, HistogramBase::kUmaStabilityHistogramFlag);
30 histogram->Add(sample);
31 }
32
33 } // namespace
34
35 class HistogramFlattenerDeltaRecorder : public HistogramFlattener {
36 public:
37 HistogramFlattenerDeltaRecorder() = default;
38
39 HistogramFlattenerDeltaRecorder(const HistogramFlattenerDeltaRecorder&) =
40 delete;
41 HistogramFlattenerDeltaRecorder& operator=(
42 const HistogramFlattenerDeltaRecorder&) = delete;
43
RecordDelta(const HistogramBase & histogram,const HistogramSamples & snapshot)44 void RecordDelta(const HistogramBase& histogram,
45 const HistogramSamples& snapshot) override {
46 recorded_delta_histograms_.push_back(&histogram);
47 // Use CHECK instead of ASSERT to get full stack-trace and thus origin.
48 CHECK(!Contains(recorded_delta_histogram_sum_, histogram.histogram_name()));
49 // Keep pointer to snapshot for testing. This really isn't ideal but the
50 // snapshot-manager keeps the snapshot alive until it's "forgotten".
51 recorded_delta_histogram_sum_[histogram.histogram_name()] = snapshot.sum();
52 }
53
Reset()54 void Reset() {
55 recorded_delta_histograms_.clear();
56 recorded_delta_histogram_sum_.clear();
57 }
58
59 std::vector<raw_ptr<const HistogramBase, VectorExperimental>>&
GetRecordedDeltaHistograms()60 GetRecordedDeltaHistograms() {
61 return recorded_delta_histograms_;
62 }
63
GetRecordedDeltaHistogramSum(const std::string & name)64 int64_t GetRecordedDeltaHistogramSum(const std::string& name) {
65 EXPECT_TRUE(Contains(recorded_delta_histogram_sum_, name));
66 return recorded_delta_histogram_sum_[name];
67 }
68
69 private:
70 std::vector<raw_ptr<const HistogramBase, VectorExperimental>>
71 recorded_delta_histograms_;
72 std::map<std::string, int64_t> recorded_delta_histogram_sum_;
73 };
74
75 class HistogramSnapshotManagerTest : public testing::Test {
76 protected:
HistogramSnapshotManagerTest()77 HistogramSnapshotManagerTest()
78 : statistics_recorder_(StatisticsRecorder::CreateTemporaryForTesting()),
79 histogram_snapshot_manager_(&histogram_flattener_delta_recorder_) {}
80
81 ~HistogramSnapshotManagerTest() override = default;
82
GetRecordedDeltaHistogramSum(const std::string & name)83 int64_t GetRecordedDeltaHistogramSum(const std::string& name) {
84 return histogram_flattener_delta_recorder_.GetRecordedDeltaHistogramSum(
85 name);
86 }
87
88 std::unique_ptr<StatisticsRecorder> statistics_recorder_;
89 HistogramFlattenerDeltaRecorder histogram_flattener_delta_recorder_;
90 HistogramSnapshotManager histogram_snapshot_manager_;
91 };
92
TEST_F(HistogramSnapshotManagerTest,PrepareDeltasNoFlagsFilter)93 TEST_F(HistogramSnapshotManagerTest, PrepareDeltasNoFlagsFilter) {
94 // kNoFlags filter should record all histograms.
95 base::UmaHistogramBoolean(kHistogramName, true);
96 UmaStabilityHistogramBoolean(kStabilityHistogramName, true);
97
98 StatisticsRecorder::PrepareDeltas(
99 /*include_persistent=*/false, /*flags_to_set=*/HistogramBase::kNoFlags,
100 /*required_flags=*/HistogramBase::kNoFlags, &histogram_snapshot_manager_);
101
102 // Verify that the snapshots were recorded.
103 const std::vector<raw_ptr<const HistogramBase, VectorExperimental>>&
104 histograms =
105 histogram_flattener_delta_recorder_.GetRecordedDeltaHistograms();
106 ASSERT_EQ(2U, histograms.size());
107 ASSERT_EQ(kHistogramName, histograms[0]->histogram_name());
108 EXPECT_EQ(GetRecordedDeltaHistogramSum(kHistogramName), 1);
109 ASSERT_EQ(kStabilityHistogramName, histograms[1]->histogram_name());
110 EXPECT_EQ(GetRecordedDeltaHistogramSum(kStabilityHistogramName), 1);
111
112 // The samples should have been marked as logged.
113 EXPECT_EQ(histograms[0]->SnapshotUnloggedSamples()->TotalCount(), 0);
114 EXPECT_EQ(histograms[1]->SnapshotUnloggedSamples()->TotalCount(), 0);
115 }
116
TEST_F(HistogramSnapshotManagerTest,PrepareDeltasUmaHistogramFlagFilter)117 TEST_F(HistogramSnapshotManagerTest, PrepareDeltasUmaHistogramFlagFilter) {
118 // Note that kUmaStabilityHistogramFlag includes kUmaTargetedHistogramFlag.
119 base::UmaHistogramBoolean(kHistogramName, true);
120 UmaStabilityHistogramBoolean(kStabilityHistogramName, true);
121
122 StatisticsRecorder::PrepareDeltas(
123 /*include_persistent=*/false, /*flags_to_set=*/HistogramBase::kNoFlags,
124 /*required_flags=*/HistogramBase::kUmaTargetedHistogramFlag,
125 &histogram_snapshot_manager_);
126
127 // Verify that the snapshots were recorded.
128 const std::vector<raw_ptr<const HistogramBase, VectorExperimental>>&
129 histograms =
130 histogram_flattener_delta_recorder_.GetRecordedDeltaHistograms();
131 ASSERT_EQ(2U, histograms.size());
132 ASSERT_EQ(kHistogramName, histograms[0]->histogram_name());
133 EXPECT_EQ(GetRecordedDeltaHistogramSum(kHistogramName), 1);
134 ASSERT_EQ(kStabilityHistogramName, histograms[1]->histogram_name());
135 EXPECT_EQ(GetRecordedDeltaHistogramSum(kStabilityHistogramName), 1);
136
137 // The samples should have been marked as logged.
138 EXPECT_EQ(histograms[0]->SnapshotUnloggedSamples()->TotalCount(), 0);
139 EXPECT_EQ(histograms[1]->SnapshotUnloggedSamples()->TotalCount(), 0);
140 }
141
TEST_F(HistogramSnapshotManagerTest,PrepareDeltasUmaStabilityHistogramFlagFilter)142 TEST_F(HistogramSnapshotManagerTest,
143 PrepareDeltasUmaStabilityHistogramFlagFilter) {
144 base::UmaHistogramBoolean(kHistogramName, true);
145 UmaStabilityHistogramBoolean(kStabilityHistogramName, true);
146
147 StatisticsRecorder::PrepareDeltas(
148 /*include_persistent=*/false, /*flags_to_set=*/HistogramBase::kNoFlags,
149 /*required_flags=*/HistogramBase::kUmaStabilityHistogramFlag,
150 &histogram_snapshot_manager_);
151
152 // Verify that only the stability histogram was snapshotted and recorded.
153 const std::vector<raw_ptr<const HistogramBase, VectorExperimental>>&
154 histograms =
155 histogram_flattener_delta_recorder_.GetRecordedDeltaHistograms();
156 ASSERT_EQ(1U, histograms.size());
157 ASSERT_EQ(kStabilityHistogramName, histograms[0]->histogram_name());
158 EXPECT_EQ(GetRecordedDeltaHistogramSum(kStabilityHistogramName), 1);
159
160 // The samples should have been marked as logged.
161 EXPECT_EQ(histograms[0]->SnapshotUnloggedSamples()->TotalCount(), 0);
162 }
163
TEST_F(HistogramSnapshotManagerTest,SnapshotUnloggedSamplesNoFlagsFilter)164 TEST_F(HistogramSnapshotManagerTest, SnapshotUnloggedSamplesNoFlagsFilter) {
165 // kNoFlags filter should record all histograms.
166 base::UmaHistogramBoolean(kHistogramName, true);
167 UmaStabilityHistogramBoolean(kStabilityHistogramName, true);
168
169 StatisticsRecorder::SnapshotUnloggedSamples(
170 /*required_flags=*/HistogramBase::kNoFlags, &histogram_snapshot_manager_);
171
172 // Verify that the snapshots were recorded.
173 const std::vector<raw_ptr<const HistogramBase, VectorExperimental>>&
174 histograms =
175 histogram_flattener_delta_recorder_.GetRecordedDeltaHistograms();
176 ASSERT_EQ(2U, histograms.size());
177 ASSERT_EQ(kHistogramName, histograms[0]->histogram_name());
178 EXPECT_EQ(GetRecordedDeltaHistogramSum(kHistogramName), 1);
179 ASSERT_EQ(kStabilityHistogramName, histograms[1]->histogram_name());
180 EXPECT_EQ(GetRecordedDeltaHistogramSum(kStabilityHistogramName), 1);
181
182 // The samples should NOT have been marked as logged.
183 std::unique_ptr<HistogramSamples> samples =
184 histograms[0]->SnapshotUnloggedSamples();
185 EXPECT_EQ(samples->TotalCount(), 1);
186 EXPECT_EQ(samples->sum(), 1);
187 samples = histograms[1]->SnapshotUnloggedSamples();
188 EXPECT_EQ(samples->TotalCount(), 1);
189 EXPECT_EQ(samples->sum(), 1);
190
191 // Mark the samples as logged and verify that they are correctly marked as so.
192 histogram_snapshot_manager_.MarkUnloggedSamplesAsLogged();
193 EXPECT_EQ(histograms[0]->SnapshotUnloggedSamples()->TotalCount(), 0);
194 EXPECT_EQ(histograms[1]->SnapshotUnloggedSamples()->TotalCount(), 0);
195 }
196
TEST_F(HistogramSnapshotManagerTest,SnapshotUnloggedSamplesUmaHistogramFlagFilter)197 TEST_F(HistogramSnapshotManagerTest,
198 SnapshotUnloggedSamplesUmaHistogramFlagFilter) {
199 // Note that kUmaStabilityHistogramFlag includes kUmaTargetedHistogramFlag.
200 base::UmaHistogramBoolean(kHistogramName, true);
201 UmaStabilityHistogramBoolean(kStabilityHistogramName, true);
202
203 StatisticsRecorder::SnapshotUnloggedSamples(
204 /*required_flags=*/HistogramBase::kUmaTargetedHistogramFlag,
205 &histogram_snapshot_manager_);
206
207 // Verify that the snapshots were recorded.
208 const std::vector<raw_ptr<const HistogramBase, VectorExperimental>>&
209 histograms =
210 histogram_flattener_delta_recorder_.GetRecordedDeltaHistograms();
211 ASSERT_EQ(2U, histograms.size());
212 ASSERT_EQ(kHistogramName, histograms[0]->histogram_name());
213 EXPECT_EQ(GetRecordedDeltaHistogramSum(kHistogramName), 1);
214 ASSERT_EQ(kStabilityHistogramName, histograms[1]->histogram_name());
215 EXPECT_EQ(GetRecordedDeltaHistogramSum(kStabilityHistogramName), 1);
216
217 // The samples should NOT have been marked as logged.
218 std::unique_ptr<HistogramSamples> samples =
219 histograms[0]->SnapshotUnloggedSamples();
220 EXPECT_EQ(samples->TotalCount(), 1);
221 EXPECT_EQ(samples->sum(), 1);
222 samples = histograms[1]->SnapshotUnloggedSamples();
223 EXPECT_EQ(samples->TotalCount(), 1);
224 EXPECT_EQ(samples->sum(), 1);
225
226 // Mark the samples as logged and verify that they are correctly marked as so.
227 histogram_snapshot_manager_.MarkUnloggedSamplesAsLogged();
228 EXPECT_EQ(histograms[0]->SnapshotUnloggedSamples()->TotalCount(), 0);
229 EXPECT_EQ(histograms[1]->SnapshotUnloggedSamples()->TotalCount(), 0);
230 }
231
TEST_F(HistogramSnapshotManagerTest,SnapshotUnloggedSamplesUmaStabilityHistogramFlagFilter)232 TEST_F(HistogramSnapshotManagerTest,
233 SnapshotUnloggedSamplesUmaStabilityHistogramFlagFilter) {
234 base::UmaHistogramBoolean(kHistogramName, true);
235 UmaStabilityHistogramBoolean(kStabilityHistogramName, true);
236
237 StatisticsRecorder::SnapshotUnloggedSamples(
238 /*required_flags=*/HistogramBase::kUmaStabilityHistogramFlag,
239 &histogram_snapshot_manager_);
240
241 // Verify that only the stability histogram was snapshotted and recorded.
242 const std::vector<raw_ptr<const HistogramBase, VectorExperimental>>&
243 histograms =
244 histogram_flattener_delta_recorder_.GetRecordedDeltaHistograms();
245 ASSERT_EQ(1U, histograms.size());
246 ASSERT_EQ(kStabilityHistogramName, histograms[0]->histogram_name());
247 EXPECT_EQ(GetRecordedDeltaHistogramSum(kStabilityHistogramName), 1);
248
249 // The samples should NOT have been marked as logged.
250 std::unique_ptr<HistogramSamples> samples =
251 histograms[0]->SnapshotUnloggedSamples();
252 EXPECT_EQ(samples->TotalCount(), 1);
253 EXPECT_EQ(samples->sum(), 1);
254
255 // Mark the samples as logged and verify that they are correctly marked as so.
256 histogram_snapshot_manager_.MarkUnloggedSamplesAsLogged();
257 EXPECT_EQ(histograms[0]->SnapshotUnloggedSamples()->TotalCount(), 0);
258 }
259
260 } // namespace base
261