1 // Copyright 2015 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 "components/metrics/call_stacks/call_stack_profile_metrics_provider.h"
6
7 #include <string>
8 #include <utility>
9
10 #include "base/test/scoped_feature_list.h"
11 #include "execution_context.pb.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
15
16 namespace metrics {
17
18 using ::testing::Eq;
19 using ::testing::Pair;
20 using ::testing::UnorderedElementsAre;
21
22 // This test fixture enables the feature that
23 // CallStackProfileMetricsProvider depends on to report a profile.
24 class CallStackProfileMetricsProviderTest : public testing::Test {
25 public:
CallStackProfileMetricsProviderTest()26 CallStackProfileMetricsProviderTest() {
27 TestState::ResetStaticStateForTesting();
28 scoped_feature_list_.InitAndEnableFeature(kSamplingProfilerReporting);
29 }
30
31 CallStackProfileMetricsProviderTest(
32 const CallStackProfileMetricsProviderTest&) = delete;
33 CallStackProfileMetricsProviderTest& operator=(
34 const CallStackProfileMetricsProviderTest&) = delete;
35
36 protected:
37 // Exposes the feature from the CallStackProfileMetricsProvider.
38 class TestState : public CallStackProfileMetricsProvider {
39 public:
40 using CallStackProfileMetricsProvider::ResetStaticStateForTesting;
41 };
42
43 private:
44 base::test::ScopedFeatureList scoped_feature_list_;
45 };
46
47 // Checks that the unserialized pending profile is encoded in the session data.
TEST_F(CallStackProfileMetricsProviderTest,ProvideCurrentSessionDataUnserialized)48 TEST_F(CallStackProfileMetricsProviderTest,
49 ProvideCurrentSessionDataUnserialized) {
50 CallStackProfileMetricsProvider provider;
51 provider.OnRecordingEnabled();
52 SampledProfile profile;
53 profile.set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
54 CallStackProfileMetricsProvider::ReceiveProfile(base::TimeTicks::Now(),
55 profile);
56 ChromeUserMetricsExtension uma_proto;
57 provider.ProvideCurrentSessionData(&uma_proto);
58 ASSERT_EQ(1, uma_proto.sampled_profile().size());
59 EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION,
60 uma_proto.sampled_profile(0).trigger_event());
61 }
62
63 // Checks that the serialized pending profile is encoded in the session data.
TEST_F(CallStackProfileMetricsProviderTest,ProvideCurrentSessionDataSerialized)64 TEST_F(CallStackProfileMetricsProviderTest,
65 ProvideCurrentSessionDataSerialized) {
66 CallStackProfileMetricsProvider provider;
67 provider.OnRecordingEnabled();
68 std::string contents;
69 {
70 SampledProfile profile;
71 profile.set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
72 profile.SerializeToString(&contents);
73 }
74 CallStackProfileMetricsProvider::ReceiveSerializedProfile(
75 base::TimeTicks::Now(), /*is_heap_profile=*/false, std::move(contents));
76 ChromeUserMetricsExtension uma_proto;
77 provider.ProvideCurrentSessionData(&uma_proto);
78 ASSERT_EQ(1, uma_proto.sampled_profile().size());
79 EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION,
80 uma_proto.sampled_profile(0).trigger_event());
81 }
82
83 // Checks that both the unserialized and serialized pending profiles are
84 // encoded in the session data.
TEST_F(CallStackProfileMetricsProviderTest,ProvideCurrentSessionDataUnserializedAndSerialized)85 TEST_F(CallStackProfileMetricsProviderTest,
86 ProvideCurrentSessionDataUnserializedAndSerialized) {
87 CallStackProfileMetricsProvider provider;
88 provider.OnRecordingEnabled();
89
90 // Receive an unserialized profile.
91 SampledProfile profile;
92 profile.set_trigger_event(SampledProfile::PROCESS_STARTUP);
93 CallStackProfileMetricsProvider::ReceiveProfile(base::TimeTicks::Now(),
94 std::move(profile));
95
96 // Receive a serialized profile.
97 std::string contents;
98 {
99 SampledProfile serialized_profile;
100 serialized_profile.set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
101 serialized_profile.SerializeToString(&contents);
102 }
103 CallStackProfileMetricsProvider::ReceiveSerializedProfile(
104 base::TimeTicks::Now(), /*is_heap_profile=*/false, std::move(contents));
105
106 ChromeUserMetricsExtension uma_proto;
107 provider.ProvideCurrentSessionData(&uma_proto);
108 ASSERT_EQ(2, uma_proto.sampled_profile().size());
109 EXPECT_EQ(SampledProfile::PROCESS_STARTUP,
110 uma_proto.sampled_profile(0).trigger_event());
111 EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION,
112 uma_proto.sampled_profile(1).trigger_event());
113 }
114
115 // Checks that the pending profiles above the total cap are dropped therefore
116 // not encoded in the session data.
TEST_F(CallStackProfileMetricsProviderTest,ProvideCurrentSessionDataExceedTotalCap)117 TEST_F(CallStackProfileMetricsProviderTest,
118 ProvideCurrentSessionDataExceedTotalCap) {
119 // The value must be consistent with that in
120 // call_stack_profile_metrics_provider.cc so that this test is meaningful.
121 const int kMaxPendingProfiles = 1250;
122
123 CallStackProfileMetricsProvider provider;
124 provider.OnRecordingEnabled();
125
126 // Receive (kMaxPendingProfiles + 1) profiles.
127 for (int i = 0; i < kMaxPendingProfiles + 1; ++i) {
128 SampledProfile profile;
129 profile.set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
130 CallStackProfileMetricsProvider::ReceiveProfile(base::TimeTicks::Now(),
131 std::move(profile));
132 }
133
134 ChromeUserMetricsExtension uma_proto;
135 provider.ProvideCurrentSessionData(&uma_proto);
136
137 // Only kMaxPendingProfiles profiles are encoded, with the additional one
138 // dropped.
139 ASSERT_EQ(kMaxPendingProfiles, uma_proto.sampled_profile().size());
140 for (int i = 0; i < kMaxPendingProfiles; ++i) {
141 EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION,
142 uma_proto.sampled_profile(i).trigger_event());
143 }
144 }
145
146 // Checks that the pending profile is provided to ProvideCurrentSessionData
147 // when collected before CallStackProfileMetricsProvider is instantiated.
TEST_F(CallStackProfileMetricsProviderTest,ProfileProvidedWhenCollectedBeforeInstantiation)148 TEST_F(CallStackProfileMetricsProviderTest,
149 ProfileProvidedWhenCollectedBeforeInstantiation) {
150 CallStackProfileMetricsProvider::ReceiveProfile(base::TimeTicks::Now(),
151 SampledProfile());
152 CallStackProfileMetricsProvider provider;
153 provider.OnRecordingEnabled();
154 ChromeUserMetricsExtension uma_proto;
155 provider.ProvideCurrentSessionData(&uma_proto);
156 EXPECT_EQ(1, uma_proto.sampled_profile_size());
157 }
158
159 // Checks that the pending profile is not provided to ProvideCurrentSessionData
160 // while recording is disabled.
TEST_F(CallStackProfileMetricsProviderTest,ProfileNotProvidedWhileDisabled)161 TEST_F(CallStackProfileMetricsProviderTest, ProfileNotProvidedWhileDisabled) {
162 CallStackProfileMetricsProvider provider;
163 provider.OnRecordingDisabled();
164 CallStackProfileMetricsProvider::ReceiveProfile(base::TimeTicks::Now(),
165 SampledProfile());
166 ChromeUserMetricsExtension uma_proto;
167 provider.ProvideCurrentSessionData(&uma_proto);
168 EXPECT_EQ(0, uma_proto.sampled_profile_size());
169 }
170
171 // Checks that the pending profile is not provided to ProvideCurrentSessionData
172 // if recording is disabled while profiling.
TEST_F(CallStackProfileMetricsProviderTest,ProfileNotProvidedAfterChangeToDisabled)173 TEST_F(CallStackProfileMetricsProviderTest,
174 ProfileNotProvidedAfterChangeToDisabled) {
175 CallStackProfileMetricsProvider provider;
176 provider.OnRecordingEnabled();
177 base::TimeTicks profile_start_time = base::TimeTicks::Now();
178 provider.OnRecordingDisabled();
179 CallStackProfileMetricsProvider::ReceiveProfile(profile_start_time,
180 SampledProfile());
181 ChromeUserMetricsExtension uma_proto;
182 provider.ProvideCurrentSessionData(&uma_proto);
183 EXPECT_EQ(0, uma_proto.sampled_profile_size());
184 }
185
186 // Checks that the pending profile is not provided to ProvideCurrentSessionData
187 // if recording is enabled, but then disabled and reenabled while profiling.
TEST_F(CallStackProfileMetricsProviderTest,ProfileNotProvidedAfterChangeToDisabledThenEnabled)188 TEST_F(CallStackProfileMetricsProviderTest,
189 ProfileNotProvidedAfterChangeToDisabledThenEnabled) {
190 CallStackProfileMetricsProvider provider;
191 provider.OnRecordingEnabled();
192 base::TimeTicks profile_start_time = base::TimeTicks::Now();
193 provider.OnRecordingDisabled();
194 provider.OnRecordingEnabled();
195 CallStackProfileMetricsProvider::ReceiveProfile(profile_start_time,
196 SampledProfile());
197 ChromeUserMetricsExtension uma_proto;
198 provider.ProvideCurrentSessionData(&uma_proto);
199 EXPECT_EQ(0, uma_proto.sampled_profile_size());
200 }
201
202 // Checks that the pending profile is provided to ProvideCurrentSessionData
203 // if recording is disabled, but then enabled while profiling.
TEST_F(CallStackProfileMetricsProviderTest,ProfileNotProvidedAfterChangeFromDisabled)204 TEST_F(CallStackProfileMetricsProviderTest,
205 ProfileNotProvidedAfterChangeFromDisabled) {
206 CallStackProfileMetricsProvider provider;
207 provider.OnRecordingDisabled();
208 base::TimeTicks profile_start_time = base::TimeTicks::Now();
209 provider.OnRecordingEnabled();
210 CallStackProfileMetricsProvider::ReceiveProfile(profile_start_time,
211 SampledProfile());
212 ChromeUserMetricsExtension uma_proto;
213 provider.ProvideCurrentSessionData(&uma_proto);
214 EXPECT_EQ(0, uma_proto.sampled_profile_size());
215 }
216
217 // Checks that a heap profile is not reported when recording is disabled.
TEST_F(CallStackProfileMetricsProviderTest,HeapProfileNotProvidedWhenDisabled)218 TEST_F(CallStackProfileMetricsProviderTest,
219 HeapProfileNotProvidedWhenDisabled) {
220 CallStackProfileMetricsProvider provider;
221 provider.OnRecordingDisabled();
222 base::TimeTicks profile_start_time = base::TimeTicks::Now();
223
224 // Unserialized profile.
225 SampledProfile profile;
226 profile.set_trigger_event(SampledProfile::PERIODIC_HEAP_COLLECTION);
227 CallStackProfileMetricsProvider::ReceiveProfile(profile_start_time, profile);
228
229 // Serialized profile.
230 std::string contents;
231 profile.SerializeToString(&contents);
232 CallStackProfileMetricsProvider::ReceiveSerializedProfile(
233 profile_start_time, /*is_heap_profile=*/true, std::move(contents));
234
235 ChromeUserMetricsExtension uma_proto;
236 provider.ProvideCurrentSessionData(&uma_proto);
237 EXPECT_EQ(0, uma_proto.sampled_profile_size());
238 }
239
240 // Checks that a heap profile is provided to ProvideCurrentSessionData
241 // if recording is enabled.
TEST_F(CallStackProfileMetricsProviderTest,HeapProfileProvidedWhenEnabled)242 TEST_F(CallStackProfileMetricsProviderTest, HeapProfileProvidedWhenEnabled) {
243 CallStackProfileMetricsProvider provider;
244 provider.OnRecordingEnabled();
245 base::TimeTicks profile_start_time = base::TimeTicks::Now();
246
247 // Unserialized profile.
248 SampledProfile profile;
249 profile.set_trigger_event(SampledProfile::PERIODIC_HEAP_COLLECTION);
250 CallStackProfileMetricsProvider::ReceiveProfile(profile_start_time, profile);
251
252 // Serialized profile.
253 std::string contents;
254 profile.SerializeToString(&contents);
255 CallStackProfileMetricsProvider::ReceiveSerializedProfile(
256 profile_start_time, /*is_heap_profile=*/true, std::move(contents));
257
258 ChromeUserMetricsExtension uma_proto;
259 provider.ProvideCurrentSessionData(&uma_proto);
260 EXPECT_EQ(2, uma_proto.sampled_profile_size());
261 }
262
263 // Checks that heap profiles but not CPU profiles are reported when sampling CPU
264 // Finch is disabled.
TEST_F(CallStackProfileMetricsProviderTest,CpuProfileNotProvidedWithoutFinch)265 TEST_F(CallStackProfileMetricsProviderTest, CpuProfileNotProvidedWithoutFinch) {
266 base::test::ScopedFeatureList scoped_feature_list;
267 scoped_feature_list.InitAndDisableFeature(kSamplingProfilerReporting);
268 CallStackProfileMetricsProvider provider;
269 base::TimeTicks profile_start_time = base::TimeTicks::Now();
270
271 // Unserialized profiles.
272 SampledProfile profile;
273 profile.set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
274 CallStackProfileMetricsProvider::ReceiveProfile(profile_start_time, profile);
275
276 SampledProfile heap_profile;
277 heap_profile.set_trigger_event(SampledProfile::PERIODIC_HEAP_COLLECTION);
278 CallStackProfileMetricsProvider::ReceiveProfile(profile_start_time,
279 heap_profile);
280
281 // Serialized profiles.
282 std::string contents;
283 profile.SerializeToString(&contents);
284 CallStackProfileMetricsProvider::ReceiveSerializedProfile(
285 profile_start_time, /*is_heap_profile=*/false, std::move(contents));
286
287 std::string heap_contents;
288 heap_profile.SerializeToString(&heap_contents);
289 CallStackProfileMetricsProvider::ReceiveSerializedProfile(
290 profile_start_time, /*is_heap_profile=*/true, std::move(heap_contents));
291
292 ChromeUserMetricsExtension uma_proto;
293 provider.ProvideCurrentSessionData(&uma_proto);
294 ASSERT_EQ(2, uma_proto.sampled_profile_size());
295 EXPECT_EQ(SampledProfile::PERIODIC_HEAP_COLLECTION,
296 uma_proto.sampled_profile(0).trigger_event());
297 EXPECT_EQ(SampledProfile::PERIODIC_HEAP_COLLECTION,
298 uma_proto.sampled_profile(1).trigger_event());
299 }
300
301 #if BUILDFLAG(IS_CHROMEOS)
302
303 namespace {
304
305 // Sets |call_stack_profile| up enough to pass WasMinimallySuccessful()
MakeMinimallySuccessfulCallStackProfile(CallStackProfile * call_stack_profile)306 void MakeMinimallySuccessfulCallStackProfile(
307 CallStackProfile* call_stack_profile) {
308 CallStackProfile::Stack* stack = call_stack_profile->add_stack();
309 CallStackProfile::Location* frame = stack->add_frame();
310 frame->set_address(123);
311 frame->set_module_id_index(1);
312 frame = stack->add_frame();
313 frame->set_address(456);
314 frame->set_module_id_index(0);
315 }
316
317 // Makes a minimally successful SampledProfile and sends it to ReceiveProfile.
RecieveProfile(metrics::Process process,metrics::Thread thread)318 void RecieveProfile(metrics::Process process, metrics::Thread thread) {
319 SampledProfile profile;
320 profile.set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
321 profile.set_process(process);
322 profile.set_thread(thread);
323 MakeMinimallySuccessfulCallStackProfile(profile.mutable_call_stack_profile());
324 CallStackProfileMetricsProvider::ReceiveProfile(base::TimeTicks::Now(),
325 profile);
326 }
327
328 // Makes a minimally successful SampledProfile and sends it to
329 // ReceiveSerializedProfile.
ReceiveSerializedProfile(metrics::Process process,metrics::Thread thread)330 void ReceiveSerializedProfile(metrics::Process process,
331 metrics::Thread thread) {
332 SampledProfile profile;
333 profile.set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
334 profile.set_process(process);
335 profile.set_thread(thread);
336 MakeMinimallySuccessfulCallStackProfile(profile.mutable_call_stack_profile());
337 std::string serialized_profile;
338 profile.SerializeToString(&serialized_profile);
339 CallStackProfileMetricsProvider::ReceiveSerializedProfile(
340 base::TimeTicks::Now(), /*is_heap_profile=*/false,
341 std::move(serialized_profile));
342 }
343
344 } // namespace
345
346 // Checks that profiles which have been received but not send out are listed
347 // as successfully collected.
TEST_F(CallStackProfileMetricsProviderTest,SuccessfullyCollectedOnReceivedNotSent)348 TEST_F(CallStackProfileMetricsProviderTest,
349 SuccessfullyCollectedOnReceivedNotSent) {
350 CallStackProfileMetricsProvider provider;
351 provider.OnRecordingEnabled();
352 RecieveProfile(metrics::GPU_PROCESS, metrics::IO_THREAD);
353 ReceiveSerializedProfile(metrics::GPU_PROCESS, metrics::MAIN_THREAD);
354
355 EXPECT_THAT(
356 CallStackProfileMetricsProvider::GetSuccessfullyCollectedCounts(),
357 UnorderedElementsAre(
358 Pair(Eq(metrics::GPU_PROCESS),
359 UnorderedElementsAre(Pair(Eq(metrics::IO_THREAD), Eq(1)),
360 Pair(Eq(metrics::MAIN_THREAD), Eq(1))))));
361 }
362
363 // Checks that profiles which have been send out are listed as successfully
364 // collected.
TEST_F(CallStackProfileMetricsProviderTest,SuccessfullyCollectedOnSent)365 TEST_F(CallStackProfileMetricsProviderTest, SuccessfullyCollectedOnSent) {
366 CallStackProfileMetricsProvider provider;
367 provider.OnRecordingEnabled();
368 RecieveProfile(metrics::GPU_PROCESS, metrics::IO_THREAD);
369 ReceiveSerializedProfile(metrics::BROWSER_PROCESS, metrics::IO_THREAD);
370
371 ChromeUserMetricsExtension uma_proto;
372 provider.ProvideCurrentSessionData(&uma_proto);
373 EXPECT_EQ(2, uma_proto.sampled_profile().size());
374
375 EXPECT_THAT(
376 CallStackProfileMetricsProvider::GetSuccessfullyCollectedCounts(),
377 UnorderedElementsAre(
378 Pair(Eq(metrics::GPU_PROCESS),
379 UnorderedElementsAre(Pair(Eq(metrics::IO_THREAD), Eq(1)))),
380 Pair(Eq(metrics::BROWSER_PROCESS),
381 UnorderedElementsAre(Pair(Eq(metrics::IO_THREAD), Eq(1))))));
382 }
383
384 // Checks that profiles which are send and profiles which are unsent are
385 // correctly summed together.
TEST_F(CallStackProfileMetricsProviderTest,SuccessfullyCollectedMixedSentUnsent)386 TEST_F(CallStackProfileMetricsProviderTest,
387 SuccessfullyCollectedMixedSentUnsent) {
388 CallStackProfileMetricsProvider provider;
389 provider.OnRecordingEnabled();
390 RecieveProfile(metrics::GPU_PROCESS, metrics::IO_THREAD);
391 ReceiveSerializedProfile(metrics::BROWSER_PROCESS, metrics::IO_THREAD);
392
393 // Send the first 2 metrics.
394 ChromeUserMetricsExtension uma_proto;
395 provider.ProvideCurrentSessionData(&uma_proto);
396 EXPECT_EQ(2, uma_proto.sampled_profile().size());
397
398 RecieveProfile(metrics::GPU_PROCESS, metrics::IO_THREAD);
399 ReceiveSerializedProfile(metrics::BROWSER_PROCESS, metrics::MAIN_THREAD);
400
401 EXPECT_THAT(
402 CallStackProfileMetricsProvider::GetSuccessfullyCollectedCounts(),
403 UnorderedElementsAre(
404 Pair(Eq(metrics::GPU_PROCESS),
405 UnorderedElementsAre(Pair(Eq(metrics::IO_THREAD), Eq(2)))),
406 Pair(Eq(metrics::BROWSER_PROCESS),
407 UnorderedElementsAre(Pair(Eq(metrics::IO_THREAD), Eq(1)),
408 Pair(Eq(metrics::MAIN_THREAD), Eq(1))))));
409 }
410
411 // Checks that "unsuccessful" profiles (profiles with 1 or no stack) are not
412 // counted.
TEST_F(CallStackProfileMetricsProviderTest,SuccessfullyCollectedIgnoresUnsuccessful)413 TEST_F(CallStackProfileMetricsProviderTest,
414 SuccessfullyCollectedIgnoresUnsuccessful) {
415 CallStackProfileMetricsProvider provider;
416 provider.OnRecordingEnabled();
417 RecieveProfile(metrics::GPU_PROCESS, metrics::IO_THREAD);
418 ReceiveSerializedProfile(metrics::GPU_PROCESS, metrics::IO_THREAD);
419
420 {
421 SampledProfile no_stack_profile;
422 no_stack_profile.set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
423 no_stack_profile.set_process(metrics::BROWSER_PROCESS);
424 no_stack_profile.set_thread(metrics::MAIN_THREAD);
425 CallStackProfileMetricsProvider::ReceiveProfile(base::TimeTicks::Now(),
426 no_stack_profile);
427 std::string serialized_no_stack_profile;
428 no_stack_profile.SerializeToString(&serialized_no_stack_profile);
429 CallStackProfileMetricsProvider::ReceiveSerializedProfile(
430 base::TimeTicks::Now(), /*is_heap_profile=*/false,
431 std::move(serialized_no_stack_profile));
432 }
433
434 {
435 SampledProfile one_frame_profile;
436 one_frame_profile.set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
437 one_frame_profile.set_process(metrics::BROWSER_PROCESS);
438 one_frame_profile.set_thread(metrics::MAIN_THREAD);
439 CallStackProfile::Stack* stack =
440 one_frame_profile.mutable_call_stack_profile()->add_stack();
441 CallStackProfile::Location* frame = stack->add_frame();
442 frame->set_address(123);
443 frame->set_module_id_index(1);
444 CallStackProfileMetricsProvider::ReceiveProfile(base::TimeTicks::Now(),
445 one_frame_profile);
446 std::string serialized_one_frame_profile;
447 one_frame_profile.SerializeToString(&serialized_one_frame_profile);
448 CallStackProfileMetricsProvider::ReceiveSerializedProfile(
449 base::TimeTicks::Now(), /*is_heap_profile=*/false,
450 std::move(serialized_one_frame_profile));
451 }
452
453 // All the BROWSER_PROCESS profiles were unsuccessful, so only the GPU_PROCESS
454 // profiles should be counted.
455
456 EXPECT_THAT(CallStackProfileMetricsProvider::GetSuccessfullyCollectedCounts(),
457 UnorderedElementsAre(Pair(
458 Eq(metrics::GPU_PROCESS),
459 UnorderedElementsAre(Pair(Eq(metrics::IO_THREAD), Eq(2))))));
460 }
461 #endif // BUILDFLAG(IS_CHROMEOS)
462
463 } // namespace metrics
464