call_stack_profile_builder_unittest.cc 25 KB

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