123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/metrics/call_stack_profile_builder.h"
- #include <memory>
- #include "base/callback.h"
- #include "base/files/file_path.h"
- #include "base/profiler/module_cache.h"
- #include "base/profiler/stack_sampling_profiler_test_util.h"
- #include "base/test/bind.h"
- #include "base/test/mock_callback.h"
- #include "base/time/time.h"
- #include "build/build_config.h"
- #include "components/metrics/call_stack_profile_params.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/metrics_proto/sampled_profile.pb.h"
- namespace metrics {
- namespace {
- constexpr CallStackProfileParams kProfileParams = {
- CallStackProfileParams::Process::kBrowser,
- CallStackProfileParams::Thread::kMain,
- CallStackProfileParams::Trigger::kProcessStartup};
- class TestingCallStackProfileBuilder : public CallStackProfileBuilder {
- public:
- TestingCallStackProfileBuilder(
- const CallStackProfileParams& profile_params,
- const WorkIdRecorder* work_id_recorder = nullptr,
- base::OnceClosure completed_callback = base::OnceClosure());
- ~TestingCallStackProfileBuilder() override;
- base::TimeTicks test_profile_start_time() const {
- return test_profile_start_time_;
- }
- const SampledProfile& test_sampled_profile() const {
- return test_sampled_profile_;
- }
- protected:
- // Overridden for testing.
- void PassProfilesToMetricsProvider(base::TimeTicks profile_start_time,
- SampledProfile sampled_profile) override;
- private:
- // The start time and completed profile.
- base::TimeTicks test_profile_start_time_;
- SampledProfile test_sampled_profile_;
- };
- TestingCallStackProfileBuilder::TestingCallStackProfileBuilder(
- const CallStackProfileParams& profile_params,
- const WorkIdRecorder* work_id_recorder,
- base::OnceClosure completed_callback)
- : CallStackProfileBuilder(profile_params,
- work_id_recorder,
- std::move(completed_callback)) {}
- TestingCallStackProfileBuilder::~TestingCallStackProfileBuilder() = default;
- void TestingCallStackProfileBuilder::PassProfilesToMetricsProvider(
- base::TimeTicks profile_start_time,
- SampledProfile sampled_profile) {
- test_profile_start_time_ = profile_start_time;
- test_sampled_profile_ = std::move(sampled_profile);
- }
- } // namespace
- TEST(CallStackProfileBuilderTest, ProfilingCompleted) {
- // Set up a mock completed callback which will be run once.
- base::MockCallback<base::OnceClosure> mock_closure;
- EXPECT_CALL(mock_closure, Run()).Times(1);
- auto profile_builder = std::make_unique<TestingCallStackProfileBuilder>(
- kProfileParams, nullptr, mock_closure.Get());
- base::MetadataRecorder metadata_recorder;
- #if BUILDFLAG(IS_WIN)
- uint64_t module_md5 = 0x46C3E4166659AC02ULL;
- base::FilePath module_path(L"c:\\some\\path\\to\\chrome.exe");
- #else
- uint64_t module_md5 = 0x554838A8451AC36CULL;
- base::FilePath module_path("/some/path/to/chrome");
- #endif
- const uintptr_t module_base_address1 = 0x1000;
- base::TestModule module1(module_base_address1);
- module1.set_id("1");
- module1.set_debug_basename(module_path);
- base::Frame frame1 = {module_base_address1 + 0x10, &module1};
- const uintptr_t module_base_address2 = 0x1100;
- base::TestModule module2(module_base_address2);
- module2.set_id("2");
- module2.set_debug_basename(module_path);
- base::Frame frame2 = {module_base_address2 + 0x10, &module2};
- const uintptr_t module_base_address3 = 0x1010;
- base::TestModule module3(module_base_address3);
- module3.set_id("3");
- module3.set_debug_basename(module_path);
- base::Frame frame3 = {module_base_address3 + 0x10, &module3};
- std::vector<base::Frame> frames1 = {frame1, frame2};
- std::vector<base::Frame> frames2 = {frame3};
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted(frames1, base::TimeTicks());
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted(frames2, base::TimeTicks());
- profile_builder->OnProfileCompleted(base::Milliseconds(500),
- base::Milliseconds(100));
- const SampledProfile& proto = profile_builder->test_sampled_profile();
- ASSERT_TRUE(proto.has_process());
- ASSERT_EQ(BROWSER_PROCESS, proto.process());
- ASSERT_TRUE(proto.has_thread());
- ASSERT_EQ(MAIN_THREAD, proto.thread());
- ASSERT_TRUE(proto.has_trigger_event());
- ASSERT_EQ(SampledProfile::PROCESS_STARTUP, proto.trigger_event());
- ASSERT_TRUE(proto.has_call_stack_profile());
- const CallStackProfile& profile = proto.call_stack_profile();
- ASSERT_EQ(2, profile.stack_size());
- ASSERT_EQ(2, profile.stack(0).frame_size());
- ASSERT_TRUE(profile.stack(0).frame(0).has_module_id_index());
- EXPECT_EQ(0, profile.stack(0).frame(0).module_id_index());
- ASSERT_TRUE(profile.stack(0).frame(1).has_module_id_index());
- EXPECT_EQ(1, profile.stack(0).frame(1).module_id_index());
- ASSERT_EQ(1, profile.stack(1).frame_size());
- ASSERT_TRUE(profile.stack(1).frame(0).has_module_id_index());
- EXPECT_EQ(2, profile.stack(1).frame(0).module_id_index());
- ASSERT_EQ(3, profile.module_id().size());
- ASSERT_TRUE(profile.module_id(0).has_build_id());
- EXPECT_EQ("1", profile.module_id(0).build_id());
- ASSERT_TRUE(profile.module_id(0).has_name_md5_prefix());
- EXPECT_EQ(module_md5, profile.module_id(0).name_md5_prefix());
- ASSERT_TRUE(profile.module_id(1).has_build_id());
- EXPECT_EQ("2", profile.module_id(1).build_id());
- ASSERT_TRUE(profile.module_id(1).has_name_md5_prefix());
- EXPECT_EQ(module_md5, profile.module_id(1).name_md5_prefix());
- ASSERT_TRUE(profile.module_id(2).has_build_id());
- EXPECT_EQ("3", profile.module_id(2).build_id());
- ASSERT_TRUE(profile.module_id(2).has_name_md5_prefix());
- EXPECT_EQ(module_md5, profile.module_id(2).name_md5_prefix());
- ASSERT_EQ(2, profile.stack_sample_size());
- EXPECT_EQ(0, profile.stack_sample(0).stack_index());
- EXPECT_FALSE(profile.stack_sample(0).has_continued_work());
- EXPECT_FALSE(profile.stack_sample(0).has_weight());
- EXPECT_EQ(1, profile.stack_sample(1).stack_index());
- EXPECT_FALSE(profile.stack_sample(1).has_continued_work());
- EXPECT_FALSE(profile.stack_sample(1).has_weight());
- ASSERT_TRUE(profile.has_profile_duration_ms());
- EXPECT_EQ(500, profile.profile_duration_ms());
- ASSERT_TRUE(profile.has_sampling_period_ms());
- EXPECT_EQ(100, profile.sampling_period_ms());
- }
- TEST(CallStackProfileBuilderTest, CustomWeightsAndCounts) {
- auto profile_builder =
- std::make_unique<TestingCallStackProfileBuilder>(kProfileParams);
- base::TestModule module1;
- base::Frame frame1 = {0x10, &module1};
- std::vector<base::Frame> frames = {frame1};
- profile_builder->OnSampleCompleted(frames, base::TimeTicks(), 42, 3);
- profile_builder->OnSampleCompleted(frames, base::TimeTicks(), 1, 1);
- profile_builder->OnSampleCompleted(frames, base::TimeTicks());
- profile_builder->OnProfileCompleted(base::TimeDelta(), base::TimeDelta());
- const SampledProfile& proto = profile_builder->test_sampled_profile();
- ASSERT_TRUE(proto.has_call_stack_profile());
- const CallStackProfile& profile = proto.call_stack_profile();
- ASSERT_EQ(3, profile.stack_sample_size());
- EXPECT_TRUE(profile.stack_sample(0).has_weight());
- EXPECT_TRUE(profile.stack_sample(0).has_count());
- EXPECT_EQ(42, profile.stack_sample(0).weight());
- EXPECT_EQ(3, profile.stack_sample(0).count());
- EXPECT_FALSE(profile.stack_sample(1).has_weight());
- EXPECT_FALSE(profile.stack_sample(1).has_count());
- EXPECT_FALSE(profile.stack_sample(2).has_weight());
- EXPECT_FALSE(profile.stack_sample(2).has_count());
- }
- TEST(CallStackProfileBuilderTest, StacksDeduped) {
- auto profile_builder =
- std::make_unique<TestingCallStackProfileBuilder>(kProfileParams);
- base::MetadataRecorder metadata_recorder;
- base::TestModule module1;
- base::Frame frame1 = {0x10, &module1};
- base::TestModule module2;
- base::Frame frame2 = {0x20, &module2};
- std::vector<base::Frame> frames = {frame1, frame2};
- // Two stacks are completed with the same frames therefore they are deduped
- // to one.
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted(frames, base::TimeTicks());
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted(frames, base::TimeTicks());
- profile_builder->OnProfileCompleted(base::TimeDelta(), base::TimeDelta());
- const SampledProfile& proto = profile_builder->test_sampled_profile();
- ASSERT_TRUE(proto.has_process());
- ASSERT_EQ(BROWSER_PROCESS, proto.process());
- ASSERT_TRUE(proto.has_thread());
- ASSERT_EQ(MAIN_THREAD, proto.thread());
- ASSERT_TRUE(proto.has_trigger_event());
- ASSERT_EQ(SampledProfile::PROCESS_STARTUP, proto.trigger_event());
- ASSERT_TRUE(proto.has_call_stack_profile());
- const CallStackProfile& profile = proto.call_stack_profile();
- ASSERT_EQ(1, profile.stack_size());
- ASSERT_EQ(2, profile.stack_sample_size());
- EXPECT_EQ(0, profile.stack_sample(0).stack_index());
- EXPECT_EQ(0, profile.stack_sample(1).stack_index());
- }
- TEST(CallStackProfileBuilderTest, StacksNotDeduped) {
- auto profile_builder =
- std::make_unique<TestingCallStackProfileBuilder>(kProfileParams);
- base::MetadataRecorder metadata_recorder;
- base::TestModule module1;
- base::Frame frame1 = {0x10, &module1};
- base::TestModule module2;
- base::Frame frame2 = {0x20, &module2};
- std::vector<base::Frame> frames1 = {frame1};
- std::vector<base::Frame> frames2 = {frame2};
- // Two stacks are completed with the different frames therefore not deduped.
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted(frames1, base::TimeTicks());
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted(frames2, base::TimeTicks());
- profile_builder->OnProfileCompleted(base::TimeDelta(), base::TimeDelta());
- const SampledProfile& proto = profile_builder->test_sampled_profile();
- ASSERT_TRUE(proto.has_process());
- ASSERT_EQ(BROWSER_PROCESS, proto.process());
- ASSERT_TRUE(proto.has_thread());
- ASSERT_EQ(MAIN_THREAD, proto.thread());
- ASSERT_TRUE(proto.has_trigger_event());
- ASSERT_EQ(SampledProfile::PROCESS_STARTUP, proto.trigger_event());
- ASSERT_TRUE(proto.has_call_stack_profile());
- const CallStackProfile& profile = proto.call_stack_profile();
- ASSERT_EQ(2, profile.stack_size());
- ASSERT_EQ(2, profile.stack_sample_size());
- EXPECT_EQ(0, profile.stack_sample(0).stack_index());
- EXPECT_EQ(1, profile.stack_sample(1).stack_index());
- }
- TEST(CallStackProfileBuilderTest, Modules) {
- auto profile_builder =
- std::make_unique<TestingCallStackProfileBuilder>(kProfileParams);
- base::MetadataRecorder metadata_recorder;
- // A frame with no module.
- base::Frame frame1 = {0x1010, nullptr};
- const uintptr_t module_base_address2 = 0x1100;
- #if BUILDFLAG(IS_WIN)
- uint64_t module_md5 = 0x46C3E4166659AC02ULL;
- base::FilePath module_path(L"c:\\some\\path\\to\\chrome.exe");
- #else
- uint64_t module_md5 = 0x554838A8451AC36CULL;
- base::FilePath module_path("/some/path/to/chrome");
- #endif
- base::TestModule module2(module_base_address2);
- module2.set_id("2");
- module2.set_debug_basename(module_path);
- base::Frame frame2 = {module_base_address2 + 0x10, &module2};
- std::vector<base::Frame> frames = {frame1, frame2};
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted(frames, base::TimeTicks());
- profile_builder->OnProfileCompleted(base::TimeDelta(), base::TimeDelta());
- const SampledProfile& proto = profile_builder->test_sampled_profile();
- ASSERT_TRUE(proto.has_call_stack_profile());
- const CallStackProfile& profile = proto.call_stack_profile();
- ASSERT_EQ(1, profile.stack_sample_size());
- EXPECT_EQ(0, profile.stack_sample(0).stack_index());
- ASSERT_EQ(1, profile.stack_size());
- ASSERT_EQ(2, profile.stack(0).frame_size());
- ASSERT_FALSE(profile.stack(0).frame(0).has_module_id_index());
- ASSERT_FALSE(profile.stack(0).frame(0).has_address());
- ASSERT_TRUE(profile.stack(0).frame(1).has_module_id_index());
- EXPECT_EQ(0, profile.stack(0).frame(1).module_id_index());
- ASSERT_TRUE(profile.stack(0).frame(1).has_address());
- EXPECT_EQ(0x10ULL, profile.stack(0).frame(1).address());
- ASSERT_EQ(1, profile.module_id().size());
- ASSERT_TRUE(profile.module_id(0).has_build_id());
- EXPECT_EQ("2", profile.module_id(0).build_id());
- ASSERT_TRUE(profile.module_id(0).has_name_md5_prefix());
- EXPECT_EQ(module_md5, profile.module_id(0).name_md5_prefix());
- }
- TEST(CallStackProfileBuilderTest, DedupModules) {
- auto profile_builder =
- std::make_unique<TestingCallStackProfileBuilder>(kProfileParams);
- base::MetadataRecorder metadata_recorder;
- const uintptr_t module_base_address = 0x1000;
- #if BUILDFLAG(IS_WIN)
- uint64_t module_md5 = 0x46C3E4166659AC02ULL;
- base::FilePath module_path(L"c:\\some\\path\\to\\chrome.exe");
- #else
- uint64_t module_md5 = 0x554838A8451AC36CULL;
- base::FilePath module_path("/some/path/to/chrome");
- #endif
- base::TestModule module(module_base_address);
- module.set_id("1");
- module.set_debug_basename(module_path);
- base::Frame frame1 = {module_base_address + 0x10, &module};
- base::Frame frame2 = {module_base_address + 0x20, &module};
- std::vector<base::Frame> frames = {frame1, frame2};
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted(frames, base::TimeTicks());
- profile_builder->OnProfileCompleted(base::TimeDelta(), base::TimeDelta());
- const SampledProfile& proto = profile_builder->test_sampled_profile();
- ASSERT_TRUE(proto.has_call_stack_profile());
- const CallStackProfile& profile = proto.call_stack_profile();
- ASSERT_EQ(1, profile.stack_sample_size());
- EXPECT_EQ(0, profile.stack_sample(0).stack_index());
- ASSERT_EQ(1, profile.stack_size());
- ASSERT_EQ(2, profile.stack(0).frame_size());
- // The two frames share the same module, which should be deduped in the
- // output.
- ASSERT_TRUE(profile.stack(0).frame(0).has_module_id_index());
- EXPECT_EQ(0, profile.stack(0).frame(0).module_id_index());
- ASSERT_TRUE(profile.stack(0).frame(0).has_address());
- EXPECT_EQ(0x10ULL, profile.stack(0).frame(0).address());
- ASSERT_TRUE(profile.stack(0).frame(1).has_module_id_index());
- EXPECT_EQ(0, profile.stack(0).frame(1).module_id_index());
- ASSERT_TRUE(profile.stack(0).frame(1).has_address());
- EXPECT_EQ(0x20ULL, profile.stack(0).frame(1).address());
- ASSERT_EQ(1, profile.module_id().size());
- ASSERT_TRUE(profile.module_id(0).has_build_id());
- EXPECT_EQ("1", profile.module_id(0).build_id());
- ASSERT_TRUE(profile.module_id(0).has_name_md5_prefix());
- EXPECT_EQ(module_md5, profile.module_id(0).name_md5_prefix());
- }
- TEST(CallStackProfileBuilderTest, WorkIds) {
- class TestWorkIdRecorder : public WorkIdRecorder {
- public:
- unsigned int RecordWorkId() const override { return current_id; }
- unsigned int current_id = 0;
- };
- TestWorkIdRecorder work_id_recorder;
- auto profile_builder = std::make_unique<TestingCallStackProfileBuilder>(
- kProfileParams, &work_id_recorder);
- base::MetadataRecorder metadata_recorder;
- base::TestModule module;
- base::Frame frame = {0x10, &module};
- // Id 0 means the message loop hasn't been started yet, so the sample should
- // not have continued_work set.
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted({frame}, base::TimeTicks());
- // The second sample with the same id should have continued_work set.
- work_id_recorder.current_id = 1;
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted({frame}, base::TimeTicks());
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted({frame}, base::TimeTicks());
- // Ids are in general non-contiguous across multiple samples.
- work_id_recorder.current_id = 10;
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted({frame}, base::TimeTicks());
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted({frame}, base::TimeTicks());
- profile_builder->OnProfileCompleted(base::Milliseconds(500),
- base::Milliseconds(100));
- const SampledProfile& proto = profile_builder->test_sampled_profile();
- ASSERT_TRUE(proto.has_call_stack_profile());
- const CallStackProfile& profile = proto.call_stack_profile();
- ASSERT_EQ(5, profile.stack_sample_size());
- EXPECT_FALSE(profile.stack_sample(0).has_continued_work());
- EXPECT_FALSE(profile.stack_sample(1).has_continued_work());
- EXPECT_TRUE(profile.stack_sample(2).continued_work());
- EXPECT_FALSE(profile.stack_sample(3).has_continued_work());
- EXPECT_TRUE(profile.stack_sample(4).continued_work());
- }
- TEST(CallStackProfileBuilderTest, ProfileStartTime) {
- auto profile_builder =
- std::make_unique<TestingCallStackProfileBuilder>(kProfileParams);
- base::TestModule module;
- const base::Frame frame = {0x10, &module};
- const base::TimeTicks first_sample_time = base::TimeTicks::UnixEpoch();
- profile_builder->OnSampleCompleted({frame}, first_sample_time);
- profile_builder->OnSampleCompleted({frame},
- first_sample_time + base::Seconds(1));
- profile_builder->OnProfileCompleted(base::Seconds(1), base::Seconds(1));
- EXPECT_EQ(first_sample_time, profile_builder->test_profile_start_time());
- }
- // A basic test of RecordMetadata at the level of the
- // CallStackProfileBuilder. The underlying implementation in
- // CallStackProfileMetadata is tested independently.
- TEST(CallStackProfileBuilderTest, RecordMetadata) {
- base::MetadataRecorder metadata_recorder;
- auto profile_builder =
- std::make_unique<TestingCallStackProfileBuilder>(kProfileParams, nullptr);
- base::TestModule module;
- base::Frame frame = {0x10, &module};
- metadata_recorder.Set(100, absl::nullopt, absl::nullopt, 10);
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted({frame}, base::TimeTicks());
- profile_builder->OnProfileCompleted(base::Milliseconds(500),
- base::Milliseconds(100));
- const SampledProfile& proto = profile_builder->test_sampled_profile();
- ASSERT_TRUE(proto.has_call_stack_profile());
- const CallStackProfile& profile = proto.call_stack_profile();
- ASSERT_EQ(1, profile.metadata_name_hash_size());
- EXPECT_EQ(100u, profile.metadata_name_hash(0));
- ASSERT_EQ(1, profile.stack_sample_size());
- auto sample = profile.stack_sample(0);
- ASSERT_EQ(1, sample.metadata_size());
- EXPECT_EQ(0, sample.metadata(0).name_hash_index());
- EXPECT_FALSE(sample.metadata(0).has_key());
- EXPECT_EQ(10, sample.metadata(0).value());
- }
- // A basic test of ApplyMetadataRetrospectively at the level of the
- // CallStackProfileBuilder. The underlying implementation in
- // CallStackProfileMetadata is tested independently.
- TEST(CallStackProfileBuilderTest, ApplyMetadataRetrospectively_Basic) {
- base::MetadataRecorder metadata_recorder;
- auto profile_builder =
- std::make_unique<TestingCallStackProfileBuilder>(kProfileParams, nullptr);
- base::TestModule module;
- base::Frame frame = {0x10, &module};
- base::TimeTicks profile_start_time = base::TimeTicks::UnixEpoch();
- base::TimeDelta sample_time_delta = base::Seconds(1);
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted({frame}, profile_start_time);
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted({frame},
- profile_start_time + sample_time_delta);
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted(
- {frame}, profile_start_time + 2 * sample_time_delta);
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted(
- {frame}, profile_start_time + 3 * sample_time_delta);
- // Apply the metadata from the second through third samples.
- profile_builder->ApplyMetadataRetrospectively(
- profile_start_time + sample_time_delta,
- profile_start_time + sample_time_delta * 2,
- base::MetadataRecorder::Item(3, 30, absl::nullopt, 300));
- profile_builder->OnProfileCompleted(3 * sample_time_delta, sample_time_delta);
- const SampledProfile& proto = profile_builder->test_sampled_profile();
- ASSERT_TRUE(proto.has_call_stack_profile());
- const CallStackProfile& profile = proto.call_stack_profile();
- ASSERT_EQ(1, profile.metadata_name_hash_size());
- EXPECT_EQ(3u, profile.metadata_name_hash(0));
- EXPECT_EQ(4, profile.stack_sample_size());
- EXPECT_EQ(0, profile.stack_sample(0).metadata_size());
- ASSERT_EQ(1, profile.stack_sample(1).metadata_size());
- EXPECT_EQ(0, profile.stack_sample(1).metadata(0).name_hash_index());
- EXPECT_EQ(30, profile.stack_sample(1).metadata(0).key());
- EXPECT_EQ(300, profile.stack_sample(1).metadata(0).value());
- EXPECT_EQ(0, profile.stack_sample(2).metadata_size());
- ASSERT_EQ(1, profile.stack_sample(3).metadata_size());
- EXPECT_EQ(0, profile.stack_sample(3).metadata(0).name_hash_index());
- EXPECT_EQ(30, profile.stack_sample(3).metadata(0).key());
- EXPECT_FALSE(profile.stack_sample(3).metadata(0).has_value());
- }
- // Checks that ApplyMetadataRetrospectively doesn't apply metadata if the
- // requested start time is before the profile start time.
- TEST(CallStackProfileBuilderTest,
- ApplyMetadataRetrospectively_BeforeStartTime) {
- base::MetadataRecorder metadata_recorder;
- auto profile_builder =
- std::make_unique<TestingCallStackProfileBuilder>(kProfileParams, nullptr);
- base::TestModule module;
- base::Frame frame = {0x10, &module};
- base::TimeTicks profile_start_time = base::TimeTicks::UnixEpoch();
- base::TimeDelta sample_time_delta = base::Seconds(1);
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted({frame}, profile_start_time);
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted({frame},
- profile_start_time + sample_time_delta);
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted(
- {frame}, profile_start_time + 2 * sample_time_delta);
- profile_builder->RecordMetadata(base::MetadataRecorder::MetadataProvider(
- &metadata_recorder, base::PlatformThread::CurrentId()));
- profile_builder->OnSampleCompleted(
- {frame}, profile_start_time + 3 * sample_time_delta);
- profile_builder->ApplyMetadataRetrospectively(
- profile_start_time - base::Microseconds(1),
- profile_start_time + sample_time_delta,
- base::MetadataRecorder::Item(3, 30, absl::nullopt, 300));
- profile_builder->OnProfileCompleted(3 * sample_time_delta, sample_time_delta);
- const SampledProfile& proto = profile_builder->test_sampled_profile();
- ASSERT_TRUE(proto.has_call_stack_profile());
- const CallStackProfile& profile = proto.call_stack_profile();
- EXPECT_EQ(0, profile.metadata_name_hash_size());
- EXPECT_EQ(4, profile.stack_sample_size());
- for (const CallStackProfile::StackSample& sample : profile.stack_sample())
- EXPECT_EQ(0, sample.metadata_size());
- }
- } // namespace metrics
|