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