[M120 Migration][VD] Enable direct rendering for TVPlus
[platform/framework/web/chromium-efl.git] / components / metrics / call_stack_profile_builder_unittest.cc
1 // Copyright 2018 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_stack_profile_builder.h"
6
7 #include <memory>
8
9 #include "base/files/file_path.h"
10 #include "base/functional/callback.h"
11 #include "base/profiler/module_cache.h"
12 #include "base/profiler/stack_sampling_profiler_test_util.h"
13 #include "base/test/bind.h"
14 #include "base/test/mock_callback.h"
15 #include "base/time/time.h"
16 #include "build/build_config.h"
17 #include "components/metrics/call_stack_profile_params.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/metrics_proto/sampled_profile.pb.h"
20
21 namespace metrics {
22
23 namespace {
24
25 constexpr CallStackProfileParams kProfileParams = {
26     CallStackProfileParams::Process::kBrowser,
27     CallStackProfileParams::Thread::kMain,
28     CallStackProfileParams::Trigger::kProcessStartup};
29
30 class TestingCallStackProfileBuilder : public CallStackProfileBuilder {
31  public:
32   TestingCallStackProfileBuilder(
33       const CallStackProfileParams& profile_params,
34       const WorkIdRecorder* work_id_recorder = nullptr,
35       base::OnceClosure completed_callback = base::OnceClosure());
36
37   ~TestingCallStackProfileBuilder() override;
38
39   base::TimeTicks test_profile_start_time() const {
40     return test_profile_start_time_;
41   }
42
43   const SampledProfile& test_sampled_profile() const {
44     return test_sampled_profile_;
45   }
46
47  protected:
48   // Overridden for testing.
49   void PassProfilesToMetricsProvider(base::TimeTicks profile_start_time,
50                                      SampledProfile sampled_profile) override;
51
52  private:
53   // The start time and completed profile.
54   base::TimeTicks test_profile_start_time_;
55   SampledProfile test_sampled_profile_;
56 };
57
58 TestingCallStackProfileBuilder::TestingCallStackProfileBuilder(
59     const CallStackProfileParams& profile_params,
60     const WorkIdRecorder* work_id_recorder,
61     base::OnceClosure completed_callback)
62     : CallStackProfileBuilder(profile_params,
63                               work_id_recorder,
64                               std::move(completed_callback)) {}
65
66 TestingCallStackProfileBuilder::~TestingCallStackProfileBuilder() = default;
67
68 void TestingCallStackProfileBuilder::PassProfilesToMetricsProvider(
69     base::TimeTicks profile_start_time,
70     SampledProfile sampled_profile) {
71   test_profile_start_time_ = profile_start_time;
72   test_sampled_profile_ = std::move(sampled_profile);
73 }
74
75 }  // namespace
76
77 TEST(CallStackProfileBuilderTest, ProfilingCompleted) {
78   // Set up a mock completed callback which will be run once.
79   base::MockCallback<base::OnceClosure> mock_closure;
80   EXPECT_CALL(mock_closure, Run()).Times(1);
81
82   auto profile_builder = std::make_unique<TestingCallStackProfileBuilder>(
83       kProfileParams, nullptr, mock_closure.Get());
84   base::MetadataRecorder metadata_recorder;
85
86 #if BUILDFLAG(IS_WIN)
87   uint64_t module_md5 = 0x46C3E4166659AC02ULL;
88   base::FilePath module_path(L"c:\\some\\path\\to\\chrome.exe");
89 #else
90   uint64_t module_md5 = 0x554838A8451AC36CULL;
91   base::FilePath module_path("/some/path/to/chrome");
92 #endif
93
94   const uintptr_t module_base_address1 = 0x1000;
95   base::TestModule module1(module_base_address1);
96   module1.set_id("1");
97   module1.set_debug_basename(module_path);
98   base::Frame frame1 = {module_base_address1 + 0x10, &module1};
99
100   const uintptr_t module_base_address2 = 0x1100;
101   base::TestModule module2(module_base_address2);
102   module2.set_id("2");
103   module2.set_debug_basename(module_path);
104   base::Frame frame2 = {module_base_address2 + 0x10, &module2};
105
106   const uintptr_t module_base_address3 = 0x1010;
107   base::TestModule module3(module_base_address3);
108   module3.set_id("3");
109   module3.set_debug_basename(module_path);
110   base::Frame frame3 = {module_base_address3 + 0x10, &module3};
111
112   std::vector<base::Frame> frames1 = {frame1, frame2};
113   std::vector<base::Frame> frames2 = {frame3};
114
115   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
116       &metadata_recorder, base::PlatformThread::CurrentId()));
117   profile_builder->OnSampleCompleted(frames1, base::TimeTicks());
118   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
119       &metadata_recorder, base::PlatformThread::CurrentId()));
120   profile_builder->OnSampleCompleted(frames2, base::TimeTicks());
121   profile_builder->OnProfileCompleted(base::Milliseconds(500),
122                                       base::Milliseconds(100));
123
124   const SampledProfile& proto = profile_builder->test_sampled_profile();
125
126   ASSERT_TRUE(proto.has_process());
127   ASSERT_EQ(BROWSER_PROCESS, proto.process());
128   ASSERT_TRUE(proto.has_thread());
129   ASSERT_EQ(MAIN_THREAD, proto.thread());
130   ASSERT_TRUE(proto.has_trigger_event());
131   ASSERT_EQ(SampledProfile::PROCESS_STARTUP, proto.trigger_event());
132
133   ASSERT_TRUE(proto.has_call_stack_profile());
134   const CallStackProfile& profile = proto.call_stack_profile();
135
136   ASSERT_EQ(2, profile.stack_size());
137   ASSERT_EQ(2, profile.stack(0).frame_size());
138   ASSERT_TRUE(profile.stack(0).frame(0).has_module_id_index());
139   EXPECT_EQ(0, profile.stack(0).frame(0).module_id_index());
140   ASSERT_TRUE(profile.stack(0).frame(1).has_module_id_index());
141   EXPECT_EQ(1, profile.stack(0).frame(1).module_id_index());
142   ASSERT_EQ(1, profile.stack(1).frame_size());
143   ASSERT_TRUE(profile.stack(1).frame(0).has_module_id_index());
144   EXPECT_EQ(2, profile.stack(1).frame(0).module_id_index());
145
146   ASSERT_EQ(3, profile.module_id().size());
147   ASSERT_TRUE(profile.module_id(0).has_build_id());
148   EXPECT_EQ("1", profile.module_id(0).build_id());
149   ASSERT_TRUE(profile.module_id(0).has_name_md5_prefix());
150   EXPECT_EQ(module_md5, profile.module_id(0).name_md5_prefix());
151   ASSERT_TRUE(profile.module_id(1).has_build_id());
152   EXPECT_EQ("2", profile.module_id(1).build_id());
153   ASSERT_TRUE(profile.module_id(1).has_name_md5_prefix());
154   EXPECT_EQ(module_md5, profile.module_id(1).name_md5_prefix());
155   ASSERT_TRUE(profile.module_id(2).has_build_id());
156   EXPECT_EQ("3", profile.module_id(2).build_id());
157   ASSERT_TRUE(profile.module_id(2).has_name_md5_prefix());
158   EXPECT_EQ(module_md5, profile.module_id(2).name_md5_prefix());
159
160   ASSERT_EQ(2, profile.stack_sample_size());
161   EXPECT_EQ(0, profile.stack_sample(0).stack_index());
162   EXPECT_FALSE(profile.stack_sample(0).has_continued_work());
163   EXPECT_FALSE(profile.stack_sample(0).has_weight());
164   EXPECT_EQ(1, profile.stack_sample(1).stack_index());
165   EXPECT_FALSE(profile.stack_sample(1).has_continued_work());
166   EXPECT_FALSE(profile.stack_sample(1).has_weight());
167
168   ASSERT_TRUE(profile.has_profile_duration_ms());
169   EXPECT_EQ(500, profile.profile_duration_ms());
170   ASSERT_TRUE(profile.has_sampling_period_ms());
171   EXPECT_EQ(100, profile.sampling_period_ms());
172 }
173
174 TEST(CallStackProfileBuilderTest, CustomWeightsAndCounts) {
175   auto profile_builder =
176       std::make_unique<TestingCallStackProfileBuilder>(kProfileParams);
177
178   base::TestModule module1;
179   base::Frame frame1 = {0x10, &module1};
180   std::vector<base::Frame> frames = {frame1};
181
182   profile_builder->OnSampleCompleted(frames, base::TimeTicks(), 42, 3);
183   profile_builder->OnSampleCompleted(frames, base::TimeTicks(), 1, 1);
184   profile_builder->OnSampleCompleted(frames, base::TimeTicks());
185   profile_builder->OnProfileCompleted(base::TimeDelta(), base::TimeDelta());
186
187   const SampledProfile& proto = profile_builder->test_sampled_profile();
188
189   ASSERT_TRUE(proto.has_call_stack_profile());
190   const CallStackProfile& profile = proto.call_stack_profile();
191   ASSERT_EQ(3, profile.stack_sample_size());
192   EXPECT_TRUE(profile.stack_sample(0).has_weight());
193   EXPECT_TRUE(profile.stack_sample(0).has_count());
194   EXPECT_EQ(42, profile.stack_sample(0).weight());
195   EXPECT_EQ(3, profile.stack_sample(0).count());
196   EXPECT_FALSE(profile.stack_sample(1).has_weight());
197   EXPECT_FALSE(profile.stack_sample(1).has_count());
198   EXPECT_FALSE(profile.stack_sample(2).has_weight());
199   EXPECT_FALSE(profile.stack_sample(2).has_count());
200 }
201
202 TEST(CallStackProfileBuilderTest, StacksDeduped) {
203   auto profile_builder =
204       std::make_unique<TestingCallStackProfileBuilder>(kProfileParams);
205   base::MetadataRecorder metadata_recorder;
206
207   base::TestModule module1;
208   base::Frame frame1 = {0x10, &module1};
209
210   base::TestModule module2;
211   base::Frame frame2 = {0x20, &module2};
212
213   std::vector<base::Frame> frames = {frame1, frame2};
214
215   // Two stacks are completed with the same frames therefore they are deduped
216   // to one.
217   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
218       &metadata_recorder, base::PlatformThread::CurrentId()));
219   profile_builder->OnSampleCompleted(frames, base::TimeTicks());
220   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
221       &metadata_recorder, base::PlatformThread::CurrentId()));
222   profile_builder->OnSampleCompleted(frames, base::TimeTicks());
223
224   profile_builder->OnProfileCompleted(base::TimeDelta(), base::TimeDelta());
225
226   const SampledProfile& proto = profile_builder->test_sampled_profile();
227
228   ASSERT_TRUE(proto.has_process());
229   ASSERT_EQ(BROWSER_PROCESS, proto.process());
230   ASSERT_TRUE(proto.has_thread());
231   ASSERT_EQ(MAIN_THREAD, proto.thread());
232   ASSERT_TRUE(proto.has_trigger_event());
233   ASSERT_EQ(SampledProfile::PROCESS_STARTUP, proto.trigger_event());
234
235   ASSERT_TRUE(proto.has_call_stack_profile());
236   const CallStackProfile& profile = proto.call_stack_profile();
237   ASSERT_EQ(1, profile.stack_size());
238   ASSERT_EQ(2, profile.stack_sample_size());
239   EXPECT_EQ(0, profile.stack_sample(0).stack_index());
240   EXPECT_EQ(0, profile.stack_sample(1).stack_index());
241 }
242
243 TEST(CallStackProfileBuilderTest, StacksNotDeduped) {
244   auto profile_builder =
245       std::make_unique<TestingCallStackProfileBuilder>(kProfileParams);
246   base::MetadataRecorder metadata_recorder;
247
248   base::TestModule module1;
249   base::Frame frame1 = {0x10, &module1};
250
251   base::TestModule module2;
252   base::Frame frame2 = {0x20, &module2};
253
254   std::vector<base::Frame> frames1 = {frame1};
255   std::vector<base::Frame> frames2 = {frame2};
256
257   // Two stacks are completed with the different frames therefore not deduped.
258   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
259       &metadata_recorder, base::PlatformThread::CurrentId()));
260   profile_builder->OnSampleCompleted(frames1, base::TimeTicks());
261   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
262       &metadata_recorder, base::PlatformThread::CurrentId()));
263   profile_builder->OnSampleCompleted(frames2, base::TimeTicks());
264
265   profile_builder->OnProfileCompleted(base::TimeDelta(), base::TimeDelta());
266
267   const SampledProfile& proto = profile_builder->test_sampled_profile();
268
269   ASSERT_TRUE(proto.has_process());
270   ASSERT_EQ(BROWSER_PROCESS, proto.process());
271   ASSERT_TRUE(proto.has_thread());
272   ASSERT_EQ(MAIN_THREAD, proto.thread());
273   ASSERT_TRUE(proto.has_trigger_event());
274   ASSERT_EQ(SampledProfile::PROCESS_STARTUP, proto.trigger_event());
275
276   ASSERT_TRUE(proto.has_call_stack_profile());
277   const CallStackProfile& profile = proto.call_stack_profile();
278   ASSERT_EQ(2, profile.stack_size());
279   ASSERT_EQ(2, profile.stack_sample_size());
280   EXPECT_EQ(0, profile.stack_sample(0).stack_index());
281   EXPECT_EQ(1, profile.stack_sample(1).stack_index());
282 }
283
284 TEST(CallStackProfileBuilderTest, Modules) {
285   auto profile_builder =
286       std::make_unique<TestingCallStackProfileBuilder>(kProfileParams);
287   base::MetadataRecorder metadata_recorder;
288
289   // A frame with no module.
290   base::Frame frame1 = {0x1010, nullptr};
291
292   const uintptr_t module_base_address2 = 0x1100;
293 #if BUILDFLAG(IS_WIN)
294   uint64_t module_md5 = 0x46C3E4166659AC02ULL;
295   base::FilePath module_path(L"c:\\some\\path\\to\\chrome.exe");
296 #else
297   uint64_t module_md5 = 0x554838A8451AC36CULL;
298   base::FilePath module_path("/some/path/to/chrome");
299 #endif
300   base::TestModule module2(module_base_address2);
301   module2.set_id("2");
302   module2.set_debug_basename(module_path);
303   base::Frame frame2 = {module_base_address2 + 0x10, &module2};
304
305   std::vector<base::Frame> frames = {frame1, frame2};
306
307   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
308       &metadata_recorder, base::PlatformThread::CurrentId()));
309   profile_builder->OnSampleCompleted(frames, base::TimeTicks());
310   profile_builder->OnProfileCompleted(base::TimeDelta(), base::TimeDelta());
311
312   const SampledProfile& proto = profile_builder->test_sampled_profile();
313
314   ASSERT_TRUE(proto.has_call_stack_profile());
315   const CallStackProfile& profile = proto.call_stack_profile();
316
317   ASSERT_EQ(1, profile.stack_sample_size());
318   EXPECT_EQ(0, profile.stack_sample(0).stack_index());
319
320   ASSERT_EQ(1, profile.stack_size());
321   ASSERT_EQ(2, profile.stack(0).frame_size());
322
323   ASSERT_FALSE(profile.stack(0).frame(0).has_module_id_index());
324   ASSERT_FALSE(profile.stack(0).frame(0).has_address());
325
326   ASSERT_TRUE(profile.stack(0).frame(1).has_module_id_index());
327   EXPECT_EQ(0, profile.stack(0).frame(1).module_id_index());
328   ASSERT_TRUE(profile.stack(0).frame(1).has_address());
329   EXPECT_EQ(0x10ULL, profile.stack(0).frame(1).address());
330
331   ASSERT_EQ(1, profile.module_id().size());
332   ASSERT_TRUE(profile.module_id(0).has_build_id());
333   EXPECT_EQ("2", profile.module_id(0).build_id());
334   ASSERT_TRUE(profile.module_id(0).has_name_md5_prefix());
335   EXPECT_EQ(module_md5, profile.module_id(0).name_md5_prefix());
336 }
337
338 TEST(CallStackProfileBuilderTest, DedupModules) {
339   auto profile_builder =
340       std::make_unique<TestingCallStackProfileBuilder>(kProfileParams);
341   base::MetadataRecorder metadata_recorder;
342
343   const uintptr_t module_base_address = 0x1000;
344
345 #if BUILDFLAG(IS_WIN)
346   uint64_t module_md5 = 0x46C3E4166659AC02ULL;
347   base::FilePath module_path(L"c:\\some\\path\\to\\chrome.exe");
348 #else
349   uint64_t module_md5 = 0x554838A8451AC36CULL;
350   base::FilePath module_path("/some/path/to/chrome");
351 #endif
352
353   base::TestModule module(module_base_address);
354   module.set_id("1");
355   module.set_debug_basename(module_path);
356   base::Frame frame1 = {module_base_address + 0x10, &module};
357   base::Frame frame2 = {module_base_address + 0x20, &module};
358
359   std::vector<base::Frame> frames = {frame1, frame2};
360
361   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
362       &metadata_recorder, base::PlatformThread::CurrentId()));
363   profile_builder->OnSampleCompleted(frames, base::TimeTicks());
364   profile_builder->OnProfileCompleted(base::TimeDelta(), base::TimeDelta());
365
366   const SampledProfile& proto = profile_builder->test_sampled_profile();
367
368   ASSERT_TRUE(proto.has_call_stack_profile());
369   const CallStackProfile& profile = proto.call_stack_profile();
370
371   ASSERT_EQ(1, profile.stack_sample_size());
372   EXPECT_EQ(0, profile.stack_sample(0).stack_index());
373
374   ASSERT_EQ(1, profile.stack_size());
375   ASSERT_EQ(2, profile.stack(0).frame_size());
376
377   // The two frames share the same module, which should be deduped in the
378   // output.
379   ASSERT_TRUE(profile.stack(0).frame(0).has_module_id_index());
380   EXPECT_EQ(0, profile.stack(0).frame(0).module_id_index());
381   ASSERT_TRUE(profile.stack(0).frame(0).has_address());
382   EXPECT_EQ(0x10ULL, profile.stack(0).frame(0).address());
383
384   ASSERT_TRUE(profile.stack(0).frame(1).has_module_id_index());
385   EXPECT_EQ(0, profile.stack(0).frame(1).module_id_index());
386   ASSERT_TRUE(profile.stack(0).frame(1).has_address());
387   EXPECT_EQ(0x20ULL, profile.stack(0).frame(1).address());
388
389   ASSERT_EQ(1, profile.module_id().size());
390   ASSERT_TRUE(profile.module_id(0).has_build_id());
391   EXPECT_EQ("1", profile.module_id(0).build_id());
392   ASSERT_TRUE(profile.module_id(0).has_name_md5_prefix());
393   EXPECT_EQ(module_md5, profile.module_id(0).name_md5_prefix());
394 }
395
396 TEST(CallStackProfileBuilderTest, WorkIds) {
397   class TestWorkIdRecorder : public WorkIdRecorder {
398    public:
399     unsigned int RecordWorkId() const override { return current_id; }
400
401     unsigned int current_id = 0;
402   };
403
404   TestWorkIdRecorder work_id_recorder;
405   auto profile_builder = std::make_unique<TestingCallStackProfileBuilder>(
406       kProfileParams, &work_id_recorder);
407   base::MetadataRecorder metadata_recorder;
408
409   base::TestModule module;
410   base::Frame frame = {0x10, &module};
411
412   // Id 0 means the message loop hasn't been started yet, so the sample should
413   // not have continued_work set.
414   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
415       &metadata_recorder, base::PlatformThread::CurrentId()));
416   profile_builder->OnSampleCompleted({frame}, base::TimeTicks());
417
418   // The second sample with the same id should have continued_work set.
419   work_id_recorder.current_id = 1;
420   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
421       &metadata_recorder, base::PlatformThread::CurrentId()));
422   profile_builder->OnSampleCompleted({frame}, base::TimeTicks());
423   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
424       &metadata_recorder, base::PlatformThread::CurrentId()));
425   profile_builder->OnSampleCompleted({frame}, base::TimeTicks());
426
427   // Ids are in general non-contiguous across multiple samples.
428   work_id_recorder.current_id = 10;
429   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
430       &metadata_recorder, base::PlatformThread::CurrentId()));
431   profile_builder->OnSampleCompleted({frame}, base::TimeTicks());
432   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
433       &metadata_recorder, base::PlatformThread::CurrentId()));
434   profile_builder->OnSampleCompleted({frame}, base::TimeTicks());
435
436   profile_builder->OnProfileCompleted(base::Milliseconds(500),
437                                       base::Milliseconds(100));
438
439   const SampledProfile& proto = profile_builder->test_sampled_profile();
440
441   ASSERT_TRUE(proto.has_call_stack_profile());
442   const CallStackProfile& profile = proto.call_stack_profile();
443
444   ASSERT_EQ(5, profile.stack_sample_size());
445   EXPECT_FALSE(profile.stack_sample(0).has_continued_work());
446   EXPECT_FALSE(profile.stack_sample(1).has_continued_work());
447   EXPECT_TRUE(profile.stack_sample(2).continued_work());
448   EXPECT_FALSE(profile.stack_sample(3).has_continued_work());
449   EXPECT_TRUE(profile.stack_sample(4).continued_work());
450 }
451
452 TEST(CallStackProfileBuilderTest, ProfileStartTime) {
453   auto profile_builder =
454       std::make_unique<TestingCallStackProfileBuilder>(kProfileParams);
455
456   base::TestModule module;
457   const base::Frame frame = {0x10, &module};
458   const base::TimeTicks first_sample_time = base::TimeTicks::UnixEpoch();
459
460   profile_builder->OnSampleCompleted({frame}, first_sample_time);
461   profile_builder->OnSampleCompleted({frame},
462                                      first_sample_time + base::Seconds(1));
463   profile_builder->OnProfileCompleted(base::Seconds(1), base::Seconds(1));
464
465   EXPECT_EQ(first_sample_time, profile_builder->test_profile_start_time());
466 }
467
468 // A basic test of RecordMetadata at the level of the
469 // CallStackProfileBuilder. The underlying implementation in
470 // CallStackProfileMetadata is tested independently.
471 TEST(CallStackProfileBuilderTest, RecordMetadata) {
472   base::MetadataRecorder metadata_recorder;
473   auto profile_builder =
474       std::make_unique<TestingCallStackProfileBuilder>(kProfileParams, nullptr);
475
476   base::TestModule module;
477   base::Frame frame = {0x10, &module};
478
479   metadata_recorder.Set(100, absl::nullopt, absl::nullopt, 10);
480   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
481       &metadata_recorder, base::PlatformThread::CurrentId()));
482   profile_builder->OnSampleCompleted({frame}, base::TimeTicks());
483
484   profile_builder->OnProfileCompleted(base::Milliseconds(500),
485                                       base::Milliseconds(100));
486
487   const SampledProfile& proto = profile_builder->test_sampled_profile();
488
489   ASSERT_TRUE(proto.has_call_stack_profile());
490   const CallStackProfile& profile = proto.call_stack_profile();
491
492   ASSERT_EQ(1, profile.metadata_name_hash_size());
493   EXPECT_EQ(100u, profile.metadata_name_hash(0));
494
495   ASSERT_EQ(1, profile.stack_sample_size());
496
497   auto sample = profile.stack_sample(0);
498   ASSERT_EQ(1, sample.metadata_size());
499   EXPECT_EQ(0, sample.metadata(0).name_hash_index());
500   EXPECT_FALSE(sample.metadata(0).has_key());
501   EXPECT_EQ(10, sample.metadata(0).value());
502 }
503
504 // A basic test of ApplyMetadataRetrospectively at the level of the
505 // CallStackProfileBuilder. The underlying implementation in
506 // CallStackProfileMetadata is tested independently.
507 TEST(CallStackProfileBuilderTest, ApplyMetadataRetrospectively_Basic) {
508   base::MetadataRecorder metadata_recorder;
509   auto profile_builder =
510       std::make_unique<TestingCallStackProfileBuilder>(kProfileParams, nullptr);
511
512   base::TestModule module;
513   base::Frame frame = {0x10, &module};
514   base::TimeTicks profile_start_time = base::TimeTicks::UnixEpoch();
515   base::TimeDelta sample_time_delta = base::Seconds(1);
516
517   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
518       &metadata_recorder, base::PlatformThread::CurrentId()));
519   profile_builder->OnSampleCompleted({frame}, profile_start_time);
520
521   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
522       &metadata_recorder, base::PlatformThread::CurrentId()));
523   profile_builder->OnSampleCompleted({frame},
524                                      profile_start_time + sample_time_delta);
525
526   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
527       &metadata_recorder, base::PlatformThread::CurrentId()));
528   profile_builder->OnSampleCompleted(
529       {frame}, profile_start_time + 2 * sample_time_delta);
530
531   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
532       &metadata_recorder, base::PlatformThread::CurrentId()));
533   profile_builder->OnSampleCompleted(
534       {frame}, profile_start_time + 3 * sample_time_delta);
535
536   // Apply the metadata from the second through third samples.
537   profile_builder->ApplyMetadataRetrospectively(
538       profile_start_time + sample_time_delta,
539       profile_start_time + sample_time_delta * 2,
540       base::MetadataRecorder::Item(3, 30, absl::nullopt, 300));
541
542   profile_builder->OnProfileCompleted(3 * sample_time_delta, sample_time_delta);
543
544   const SampledProfile& proto = profile_builder->test_sampled_profile();
545
546   ASSERT_TRUE(proto.has_call_stack_profile());
547   const CallStackProfile& profile = proto.call_stack_profile();
548
549   ASSERT_EQ(1, profile.metadata_name_hash_size());
550   EXPECT_EQ(3u, profile.metadata_name_hash(0));
551
552   EXPECT_EQ(4, profile.stack_sample_size());
553
554   EXPECT_EQ(0, profile.stack_sample(0).metadata_size());
555
556   ASSERT_EQ(1, profile.stack_sample(1).metadata_size());
557   EXPECT_EQ(0, profile.stack_sample(1).metadata(0).name_hash_index());
558   EXPECT_EQ(30, profile.stack_sample(1).metadata(0).key());
559   EXPECT_EQ(300, profile.stack_sample(1).metadata(0).value());
560
561   EXPECT_EQ(0, profile.stack_sample(2).metadata_size());
562
563   ASSERT_EQ(1, profile.stack_sample(3).metadata_size());
564   EXPECT_EQ(0, profile.stack_sample(3).metadata(0).name_hash_index());
565   EXPECT_EQ(30, profile.stack_sample(3).metadata(0).key());
566   EXPECT_FALSE(profile.stack_sample(3).metadata(0).has_value());
567 }
568
569 // Checks that ApplyMetadataRetrospectively doesn't apply metadata if the
570 // requested start time is before the profile start time.
571 TEST(CallStackProfileBuilderTest,
572      ApplyMetadataRetrospectively_BeforeStartTime) {
573   base::MetadataRecorder metadata_recorder;
574   auto profile_builder =
575       std::make_unique<TestingCallStackProfileBuilder>(kProfileParams, nullptr);
576
577   base::TestModule module;
578   base::Frame frame = {0x10, &module};
579   base::TimeTicks profile_start_time = base::TimeTicks::UnixEpoch();
580   base::TimeDelta sample_time_delta = base::Seconds(1);
581
582   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
583       &metadata_recorder, base::PlatformThread::CurrentId()));
584   profile_builder->OnSampleCompleted({frame}, profile_start_time);
585
586   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
587       &metadata_recorder, base::PlatformThread::CurrentId()));
588   profile_builder->OnSampleCompleted({frame},
589                                      profile_start_time + sample_time_delta);
590
591   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
592       &metadata_recorder, base::PlatformThread::CurrentId()));
593   profile_builder->OnSampleCompleted(
594       {frame}, profile_start_time + 2 * sample_time_delta);
595
596   profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
597       &metadata_recorder, base::PlatformThread::CurrentId()));
598   profile_builder->OnSampleCompleted(
599       {frame}, profile_start_time + 3 * sample_time_delta);
600
601   profile_builder->ApplyMetadataRetrospectively(
602       profile_start_time - base::Microseconds(1),
603       profile_start_time + sample_time_delta,
604       base::MetadataRecorder::Item(3, 30, absl::nullopt, 300));
605
606   profile_builder->OnProfileCompleted(3 * sample_time_delta, sample_time_delta);
607
608   const SampledProfile& proto = profile_builder->test_sampled_profile();
609
610   ASSERT_TRUE(proto.has_call_stack_profile());
611   const CallStackProfile& profile = proto.call_stack_profile();
612
613   EXPECT_EQ(0, profile.metadata_name_hash_size());
614   EXPECT_EQ(4, profile.stack_sample_size());
615
616   for (const CallStackProfile::StackSample& sample : profile.stack_sample())
617     EXPECT_EQ(0, sample.metadata_size());
618 }
619
620 // Test that timestamps are correctly attached.
621 TEST(CallStackProfileBuilderTest, AttachTimestamps) {
622   base::MetadataRecorder metadata_recorder;
623   auto profile_builder =
624       std::make_unique<TestingCallStackProfileBuilder>(kProfileParams, nullptr);
625
626   base::TestModule module;
627   base::Frame frame = {0x10, &module};
628
629   const base::TimeTicks profile_start = base::TimeTicks::Now();
630
631   profile_builder->OnSampleCompleted({frame}, profile_start);
632
633   profile_builder->OnSampleCompleted({frame},
634                                      profile_start + base::Milliseconds(500));
635
636   profile_builder->OnProfileCompleted(base::Milliseconds(500),
637                                       base::Milliseconds(100));
638
639   const SampledProfile& proto = profile_builder->test_sampled_profile();
640
641   ASSERT_TRUE(proto.has_call_stack_profile());
642   const CallStackProfile& profile = proto.call_stack_profile();
643   EXPECT_EQ(profile_start.since_origin().InMilliseconds(),
644             profile.profile_time_offset_ms());
645
646   ASSERT_EQ(2, profile.stack_sample_size());
647   auto sample0 = profile.stack_sample(0);
648   auto sample1 = profile.stack_sample(1);
649   EXPECT_EQ(0, sample0.sample_time_offset_ms());
650   EXPECT_EQ(500, sample1.sample_time_offset_ms());
651 }
652
653 }  // namespace metrics