| Index: components/metrics/call_stack_profile_metrics_provider_unittest.cc
|
| diff --git a/components/metrics/call_stack_profile_metrics_provider_unittest.cc b/components/metrics/call_stack_profile_metrics_provider_unittest.cc
|
| index 3e515b5c2db336cc09e2b1cbf66d5e4437cfa6af..727b506d3891aaffa43c7fc227d548062ad670ab 100644
|
| --- a/components/metrics/call_stack_profile_metrics_provider_unittest.cc
|
| +++ b/components/metrics/call_stack_profile_metrics_provider_unittest.cc
|
| @@ -27,6 +27,94 @@ using Profile = StackSamplingProfiler::CallStackProfile;
|
| using Profiles = StackSamplingProfiler::CallStackProfiles;
|
| using Sample = StackSamplingProfiler::Sample;
|
|
|
| +namespace {
|
| +
|
| +struct ExpectedProtoModule {
|
| + const char* build_id;
|
| + uint64_t name_md5;
|
| + uint64_t base_address;
|
| +};
|
| +
|
| +struct ExpectedProtoEntry {
|
| + int32_t module_index;
|
| + uint64_t address;
|
| +};
|
| +
|
| +struct ExpectedProtoSample {
|
| + uint32_t process_phases; // Bit-field of expected phases.
|
| + const ExpectedProtoEntry* entries;
|
| + int entry_count;
|
| + int64_t entry_repeats;
|
| +};
|
| +
|
| +struct ExpectedProtoProfile {
|
| + int32_t duration_ms;
|
| + int32_t period_ms;
|
| + const ExpectedProtoModule* modules;
|
| + int module_count;
|
| + const ExpectedProtoSample* samples;
|
| + int sample_count;
|
| +};
|
| +
|
| +class ProfilesFactory {
|
| + public:
|
| + ProfilesFactory(){};
|
| + ~ProfilesFactory(){};
|
| +
|
| + ProfilesFactory& AddPhase(int phase);
|
| + ProfilesFactory& NewProfile(int duration_ms, int interval_ms);
|
| + ProfilesFactory& NewSample();
|
| + ProfilesFactory& AddFrame(size_t module, uintptr_t offset);
|
| + ProfilesFactory& DefineModule(const char* name,
|
| + const base::FilePath& path,
|
| + uintptr_t base);
|
| +
|
| + Profiles Build();
|
| +
|
| + private:
|
| + Profiles profiles_;
|
| + uint32_t process_phases_ = 0;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ProfilesFactory);
|
| +};
|
| +
|
| +ProfilesFactory& ProfilesFactory::AddPhase(int phase) {
|
| + process_phases_ |= 1 << phase;
|
| + return *this;
|
| +}
|
| +
|
| +ProfilesFactory& ProfilesFactory::NewProfile(int duration_ms, int interval_ms) {
|
| + profiles_.push_back(Profile());
|
| + Profile* profile = &profiles_.back();
|
| + profile->profile_duration = base::TimeDelta::FromMilliseconds(duration_ms);
|
| + profile->sampling_period = base::TimeDelta::FromMilliseconds(interval_ms);
|
| + return *this;
|
| +}
|
| +
|
| +ProfilesFactory& ProfilesFactory::NewSample() {
|
| + profiles_.back().samples.push_back(Sample());
|
| + profiles_.back().samples.back().process_phases = process_phases_;
|
| + return *this;
|
| +}
|
| +
|
| +ProfilesFactory& ProfilesFactory::AddFrame(size_t module, uintptr_t offset) {
|
| + profiles_.back().samples.back().frames.push_back(Frame(offset, module));
|
| + return *this;
|
| +}
|
| +
|
| +ProfilesFactory& ProfilesFactory::DefineModule(const char* name,
|
| + const base::FilePath& path,
|
| + uintptr_t base) {
|
| + profiles_.back().modules.push_back(Module(base, name, path));
|
| + return *this;
|
| +}
|
| +
|
| +Profiles ProfilesFactory::Build() {
|
| + return std::move(profiles_);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| namespace metrics {
|
|
|
| // This test fixture enables the field trial that
|
| @@ -49,6 +137,9 @@ class CallStackProfileMetricsProviderTest : public testing::Test {
|
| std::move(profiles));
|
| }
|
|
|
| + void VerifyProfileProto(const ExpectedProtoProfile& expected,
|
| + const SampledProfile& proto);
|
| +
|
| private:
|
| // Exposes field trial/group names from the CallStackProfileMetricsProvider.
|
| class TestState : public CallStackProfileMetricsProvider {
|
| @@ -63,54 +154,66 @@ class CallStackProfileMetricsProviderTest : public testing::Test {
|
| DISALLOW_COPY_AND_ASSIGN(CallStackProfileMetricsProviderTest);
|
| };
|
|
|
| +void CallStackProfileMetricsProviderTest::VerifyProfileProto(
|
| + const ExpectedProtoProfile& expected,
|
| + const SampledProfile& proto) {
|
| + ASSERT_TRUE(proto.has_call_stack_profile());
|
| + const CallStackProfile& stack = proto.call_stack_profile();
|
| +
|
| + ASSERT_TRUE(stack.has_profile_duration_ms());
|
| + EXPECT_EQ(expected.duration_ms, stack.profile_duration_ms());
|
| + ASSERT_TRUE(stack.has_sampling_period_ms());
|
| + EXPECT_EQ(expected.period_ms, stack.sampling_period_ms());
|
| +
|
| + ASSERT_EQ(expected.module_count, stack.module_id().size());
|
| + for (int m = 0; m < expected.module_count; ++m) {
|
| + SCOPED_TRACE("module " + base::IntToString(m));
|
| + const CallStackProfile::ModuleIdentifier& module_id =
|
| + stack.module_id().Get(m);
|
| + ASSERT_TRUE(module_id.has_build_id());
|
| + EXPECT_EQ(expected.modules[m].build_id, module_id.build_id());
|
| + ASSERT_TRUE(module_id.has_name_md5_prefix());
|
| + EXPECT_EQ(expected.modules[m].name_md5, module_id.name_md5_prefix());
|
| + }
|
| +
|
| + ASSERT_EQ(expected.sample_count, stack.sample().size());
|
| + for (int s = 0; s < expected.sample_count; ++s) {
|
| + SCOPED_TRACE("sample " + base::IntToString(s));
|
| + const CallStackProfile::Sample& proto_sample = stack.sample().Get(s);
|
| +
|
| + uint32_t process_phases = 0;
|
| + for (int i = 0; i < proto_sample.process_phase().size(); ++i)
|
| + process_phases |= 1U << proto_sample.process_phase().Get(i);
|
| + EXPECT_EQ(expected.samples[s].process_phases, process_phases);
|
| +
|
| + ASSERT_EQ(expected.samples[s].entry_count, proto_sample.entry().size());
|
| + ASSERT_TRUE(proto_sample.has_count());
|
| + EXPECT_EQ(expected.samples[s].entry_repeats, proto_sample.count());
|
| + for (int e = 0; e < expected.samples[s].entry_count; ++e) {
|
| + SCOPED_TRACE("entry " + base::SizeTToString(e));
|
| + const CallStackProfile::Entry& entry = proto_sample.entry().Get(e);
|
| + if (expected.samples[s].entries[e].module_index >= 0) {
|
| + ASSERT_TRUE(entry.has_module_id_index());
|
| + EXPECT_EQ(expected.samples[s].entries[e].module_index,
|
| + entry.module_id_index());
|
| + ASSERT_TRUE(entry.has_address());
|
| + EXPECT_EQ(expected.samples[s].entries[e].address, entry.address());
|
| + } else {
|
| + EXPECT_FALSE(entry.has_module_id_index());
|
| + EXPECT_FALSE(entry.has_address());
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| // Checks that all properties from multiple profiles are filled as expected.
|
| TEST_F(CallStackProfileMetricsProviderTest, MultipleProfiles) {
|
| - const uintptr_t module1_base_address = 0x1000;
|
| - const uintptr_t module2_base_address = 0x2000;
|
| - const uintptr_t module3_base_address = 0x3000;
|
| -
|
| - const Module profile_modules[][2] = {
|
| - {
|
| - Module(
|
| - module1_base_address,
|
| - "ABCD",
|
| -#if defined(OS_WIN)
|
| - base::FilePath(L"c:\\some\\path\\to\\chrome.exe")
|
| -#else
|
| - base::FilePath("/some/path/to/chrome")
|
| -#endif
|
| - ),
|
| - Module(
|
| - module2_base_address,
|
| - "EFGH",
|
| -#if defined(OS_WIN)
|
| - base::FilePath(L"c:\\some\\path\\to\\third_party.dll")
|
| -#else
|
| - base::FilePath("/some/path/to/third_party.so")
|
| -#endif
|
| - ),
|
| - },
|
| - {
|
| - Module(
|
| - module3_base_address,
|
| - "MNOP",
|
| -#if defined(OS_WIN)
|
| - base::FilePath(L"c:\\some\\path\\to\\third_party2.dll")
|
| -#else
|
| - base::FilePath("/some/path/to/third_party2.so")
|
| -#endif
|
| - ),
|
| - Module( // Repeated from the first profile.
|
| - module1_base_address,
|
| - "ABCD",
|
| -#if defined(OS_WIN)
|
| - base::FilePath(L"c:\\some\\path\\to\\chrome.exe")
|
| -#else
|
| - base::FilePath("/some/path/to/chrome")
|
| -#endif
|
| - )
|
| - }
|
| - };
|
| + const uintptr_t moduleA_base_address = 0x1000;
|
| + const uintptr_t moduleB_base_address = 0x2000;
|
| + const uintptr_t moduleC_base_address = 0x3000;
|
| + const char* moduleA_name = "ABCD";
|
| + const char* moduleB_name = "EFGH";
|
| + const char* moduleC_name = "MNOP";
|
|
|
| // Values for Windows generated with:
|
| // perl -MDigest::MD5=md5 -MEncode=encode
|
| @@ -121,21 +224,21 @@ TEST_F(CallStackProfileMetricsProviderTest, MultipleProfiles) {
|
| // perl -MDigest::MD5=md5
|
| // -e 'for(@ARGV){printf "%x\n", unpack "Q>", md5 $_}'
|
| // chrome third_party.so third_party2.so
|
| - const uint64_t profile_expected_name_md5_prefixes[][2] = {
|
| - {
|
| #if defined(OS_WIN)
|
| - 0x46c3e4166659ac02ULL, 0x7e2b8bfddeae1abaULL
|
| + uint64_t moduleA_md5 = 0x46C3E4166659AC02ULL;
|
| + uint64_t moduleB_md5 = 0x7E2B8BFDDEAE1ABAULL;
|
| + uint64_t moduleC_md5 = 0x87B66F4573A4D5CAULL;
|
| + base::FilePath moduleA_path(L"c:\\some\\path\\to\\chrome.exe");
|
| + base::FilePath moduleB_path(L"c:\\some\\path\\to\\third_party.dll");
|
| + base::FilePath moduleC_path(L"c:\\some\\path\\to\\third_party2.dll");
|
| #else
|
| - 0x554838a8451ac36cUL, 0x843661148659c9f8UL
|
| + uint64_t moduleA_md5 = 0x554838A8451AC36CULL;
|
| + uint64_t moduleB_md5 = 0x843661148659C9F8ULL;
|
| + uint64_t moduleC_md5 = 0xB4647E539FA6EC9EULL;
|
| + base::FilePath moduleA_path("/some/path/to/chrome");
|
| + base::FilePath moduleB_path("/some/path/to/third_party.so");
|
| + base::FilePath moduleC_path("/some/path/to/third_party2.so");
|
| #endif
|
| - },
|
| - {
|
| -#if defined(OS_WIN)
|
| - 0x87b66f4573a4d5caULL, 0x46c3e4166659ac02ULL
|
| -#else
|
| - 0xb4647e539fa6ec9eUL, 0x554838a8451ac36cUL
|
| -#endif
|
| - }};
|
|
|
| // Represents two stack samples for each of two profiles, where each stack
|
| // contains three frames. Each frame contains an instruction pointer and a
|
| @@ -146,63 +249,97 @@ TEST_F(CallStackProfileMetricsProviderTest, MultipleProfiles) {
|
| // of 0x10 from the module's base address, the next-to-top frame in module 1
|
| // at an offset of 0x20 from the module's base address, and the bottom frame
|
| // in module 0 at an offset of 0x30 from the module's base address
|
| - const Frame profile_sample_frames[][2][3] = {
|
| - {
|
| + Profiles profiles = ProfilesFactory()
|
| + .NewProfile(100, 10)
|
| + .DefineModule(moduleA_name, moduleA_path, moduleA_base_address)
|
| + .DefineModule(moduleB_name, moduleB_path, moduleB_base_address)
|
| +
|
| + .NewSample()
|
| + .AddFrame(0, moduleA_base_address + 0x10)
|
| + .AddFrame(1, moduleB_base_address + 0x20)
|
| + .AddFrame(0, moduleA_base_address + 0x30)
|
| + .NewSample()
|
| + .AddFrame(1, moduleB_base_address + 0x10)
|
| + .AddFrame(0, moduleA_base_address + 0x20)
|
| + .AddFrame(1, moduleB_base_address + 0x30)
|
| +
|
| + .NewProfile(200, 20)
|
| + .DefineModule(moduleC_name, moduleC_path, moduleC_base_address)
|
| + .DefineModule(moduleA_name, moduleA_path, moduleA_base_address)
|
| +
|
| + .NewSample()
|
| + .AddFrame(0, moduleC_base_address + 0x10)
|
| + .AddFrame(1, moduleA_base_address + 0x20)
|
| + .AddFrame(0, moduleC_base_address + 0x30)
|
| + .NewSample()
|
| + .AddFrame(1, moduleA_base_address + 0x10)
|
| + .AddFrame(0, moduleC_base_address + 0x20)
|
| + .AddFrame(1, moduleA_base_address + 0x30)
|
| +
|
| + .Build();
|
| +
|
| + const ExpectedProtoModule expected_proto_modules1[] = {
|
| + { moduleA_name, moduleA_md5, moduleA_base_address },
|
| + { moduleB_name, moduleB_md5, moduleB_base_address }
|
| + };
|
| +
|
| + const ExpectedProtoEntry expected_proto_entries11[] = {
|
| + { 0, 0x10 },
|
| + { 1, 0x20 },
|
| + { 0, 0x30 },
|
| + };
|
| + const ExpectedProtoEntry expected_proto_entries12[] = {
|
| + { 1, 0x10 },
|
| + { 0, 0x20 },
|
| + { 1, 0x30 },
|
| + };
|
| + const ExpectedProtoSample expected_proto_samples1[] = {
|
| {
|
| - Frame(module1_base_address + 0x10, 0),
|
| - Frame(module2_base_address + 0x20, 1),
|
| - Frame(module1_base_address + 0x30, 0)
|
| + 0, expected_proto_entries11, arraysize(expected_proto_entries11), 1,
|
| },
|
| {
|
| - Frame(module2_base_address + 0x10, 1),
|
| - Frame(module1_base_address + 0x20, 0),
|
| - Frame(module2_base_address + 0x30, 1)
|
| - }
|
| - },
|
| - {
|
| - {
|
| - Frame(module3_base_address + 0x10, 0),
|
| - Frame(module1_base_address + 0x20, 1),
|
| - Frame(module3_base_address + 0x30, 0)
|
| + 0, expected_proto_entries12, arraysize(expected_proto_entries12), 1,
|
| },
|
| - {
|
| - Frame(module1_base_address + 0x10, 1),
|
| - Frame(module3_base_address + 0x20, 0),
|
| - Frame(module1_base_address + 0x30, 1)
|
| - }
|
| - }
|
| };
|
|
|
| - base::TimeDelta profile_durations[2] = {
|
| - base::TimeDelta::FromMilliseconds(100),
|
| - base::TimeDelta::FromMilliseconds(200)
|
| + const ExpectedProtoModule expected_proto_modules2[] = {
|
| + { moduleC_name, moduleC_md5, moduleC_base_address },
|
| + { moduleA_name, moduleA_md5, moduleA_base_address }
|
| };
|
|
|
| - base::TimeDelta profile_sampling_periods[2] = {
|
| - base::TimeDelta::FromMilliseconds(10),
|
| - base::TimeDelta::FromMilliseconds(20)
|
| + const ExpectedProtoEntry expected_proto_entries21[] = {
|
| + { 0, 0x10 },
|
| + { 1, 0x20 },
|
| + { 0, 0x30 },
|
| + };
|
| + const ExpectedProtoEntry expected_proto_entries22[] = {
|
| + { 1, 0x10 },
|
| + { 0, 0x20 },
|
| + { 1, 0x30 },
|
| + };
|
| + const ExpectedProtoSample expected_proto_samples2[] = {
|
| + {
|
| + 0, expected_proto_entries11, arraysize(expected_proto_entries21), 1,
|
| + },
|
| + {
|
| + 0, expected_proto_entries12, arraysize(expected_proto_entries22), 1,
|
| + },
|
| };
|
|
|
| - std::vector<Profile> profiles;
|
| - for (size_t i = 0; i < arraysize(profile_sample_frames); ++i) {
|
| - Profile profile;
|
| - profile.modules.insert(
|
| - profile.modules.end(), &profile_modules[i][0],
|
| - &profile_modules[i][0] + arraysize(profile_modules[i]));
|
| -
|
| - for (size_t j = 0; j < arraysize(profile_sample_frames[i]); ++j) {
|
| - profile.samples.push_back(Sample());
|
| - Sample& sample = profile.samples.back();
|
| - sample.insert(sample.end(), &profile_sample_frames[i][j][0],
|
| - &profile_sample_frames[i][j][0] +
|
| - arraysize(profile_sample_frames[i][j]));
|
| - }
|
| -
|
| - profile.profile_duration = profile_durations[i];
|
| - profile.sampling_period = profile_sampling_periods[i];
|
| + const ExpectedProtoProfile expected_proto_profiles[] = {
|
| + {
|
| + 100, 10,
|
| + expected_proto_modules1, arraysize(expected_proto_modules1),
|
| + expected_proto_samples1, arraysize(expected_proto_samples1),
|
| + },
|
| + {
|
| + 200, 20,
|
| + expected_proto_modules2, arraysize(expected_proto_modules2),
|
| + expected_proto_samples2, arraysize(expected_proto_samples2),
|
| + },
|
| + };
|
|
|
| - profiles.push_back(std::move(profile));
|
| - }
|
| + ASSERT_EQ(arraysize(expected_proto_profiles), profiles.size());
|
|
|
| CallStackProfileMetricsProvider provider;
|
| provider.OnRecordingEnabled();
|
| @@ -215,68 +352,12 @@ TEST_F(CallStackProfileMetricsProviderTest, MultipleProfiles) {
|
| ChromeUserMetricsExtension uma_proto;
|
| provider.ProvideGeneralMetrics(&uma_proto);
|
|
|
| - ASSERT_EQ(static_cast<int>(arraysize(profile_sample_frames)),
|
| + ASSERT_EQ(static_cast<int>(arraysize(expected_proto_profiles)),
|
| uma_proto.sampled_profile().size());
|
| - for (size_t i = 0; i < arraysize(profile_sample_frames); ++i) {
|
| - SCOPED_TRACE("profile " + base::SizeTToString(i));
|
| - const SampledProfile& sampled_profile = uma_proto.sampled_profile().Get(i);
|
| - ASSERT_TRUE(sampled_profile.has_call_stack_profile());
|
| - const CallStackProfile& call_stack_profile =
|
| - sampled_profile.call_stack_profile();
|
| -
|
| - ASSERT_EQ(static_cast<int>(arraysize(profile_sample_frames[i])),
|
| - call_stack_profile.sample().size());
|
| - for (size_t j = 0; j < arraysize(profile_sample_frames[i]); ++j) {
|
| - SCOPED_TRACE("sample " + base::SizeTToString(j));
|
| - const CallStackProfile::Sample& proto_sample =
|
| - call_stack_profile.sample().Get(j);
|
| - ASSERT_EQ(static_cast<int>(arraysize(profile_sample_frames[i][j])),
|
| - proto_sample.entry().size());
|
| - ASSERT_TRUE(proto_sample.has_count());
|
| - EXPECT_EQ(1u, proto_sample.count());
|
| - for (size_t k = 0; k < arraysize(profile_sample_frames[i][j]); ++k) {
|
| - SCOPED_TRACE("frame " + base::SizeTToString(k));
|
| - const CallStackProfile::Entry& entry = proto_sample.entry().Get(k);
|
| - ASSERT_TRUE(entry.has_address());
|
| - const char* instruction_pointer = reinterpret_cast<const char*>(
|
| - profile_sample_frames[i][j][k].instruction_pointer);
|
| - const char* module_base_address = reinterpret_cast<const char*>(
|
| - profile_modules[i][profile_sample_frames[i][j][k].module_index]
|
| - .base_address);
|
| - EXPECT_EQ(
|
| - static_cast<uint64_t>(instruction_pointer - module_base_address),
|
| - entry.address());
|
| - ASSERT_TRUE(entry.has_module_id_index());
|
| - EXPECT_EQ(profile_sample_frames[i][j][k].module_index,
|
| - static_cast<size_t>(entry.module_id_index()));
|
| - }
|
| - }
|
| -
|
| - ASSERT_EQ(static_cast<int>(arraysize(profile_modules[i])),
|
| - call_stack_profile.module_id().size());
|
| - for (size_t j = 0; j < arraysize(profile_modules[i]); ++j) {
|
| - SCOPED_TRACE("module " + base::SizeTToString(j));
|
| - const CallStackProfile::ModuleIdentifier& module_identifier =
|
| - call_stack_profile.module_id().Get(j);
|
| - ASSERT_TRUE(module_identifier.has_build_id());
|
| - EXPECT_EQ(profile_modules[i][j].id, module_identifier.build_id());
|
| - ASSERT_TRUE(module_identifier.has_name_md5_prefix());
|
| - EXPECT_EQ(profile_expected_name_md5_prefixes[i][j],
|
| - module_identifier.name_md5_prefix());
|
| - }
|
| -
|
| - ASSERT_TRUE(call_stack_profile.has_profile_duration_ms());
|
| - EXPECT_EQ(profile_durations[i].InMilliseconds(),
|
| - call_stack_profile.profile_duration_ms());
|
| - ASSERT_TRUE(call_stack_profile.has_sampling_period_ms());
|
| - EXPECT_EQ(profile_sampling_periods[i].InMilliseconds(),
|
| - call_stack_profile.sampling_period_ms());
|
| - ASSERT_TRUE(sampled_profile.has_process());
|
| - EXPECT_EQ(BROWSER_PROCESS, sampled_profile.process());
|
| - ASSERT_TRUE(sampled_profile.has_thread());
|
| - EXPECT_EQ(UI_THREAD, sampled_profile.thread());
|
| - ASSERT_TRUE(sampled_profile.has_trigger_event());
|
| - EXPECT_EQ(SampledProfile::PROCESS_STARTUP, sampled_profile.trigger_event());
|
| + for (size_t p = 0; p < arraysize(expected_proto_profiles); ++p) {
|
| + SCOPED_TRACE("profile " + base::SizeTToString(p));
|
| + VerifyProfileProto(expected_proto_profiles[p],
|
| + uma_proto.sampled_profile().Get(p));
|
| }
|
| }
|
|
|
| @@ -284,42 +365,66 @@ TEST_F(CallStackProfileMetricsProviderTest, MultipleProfiles) {
|
| // preserve_sample_ordering = false.
|
| TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksUnordered) {
|
| const uintptr_t module_base_address = 0x1000;
|
| + const char* module_name = "ABCD";
|
|
|
| - const Module modules[] = {
|
| - Module(
|
| - module_base_address,
|
| - "ABCD",
|
| #if defined(OS_WIN)
|
| - base::FilePath(L"c:\\some\\path\\to\\chrome.exe")
|
| + uint64_t module_md5 = 0x46C3E4166659AC02ULL;
|
| + base::FilePath module_path(L"c:\\some\\path\\to\\chrome.exe");
|
| #else
|
| - base::FilePath("/some/path/to/chrome")
|
| + uint64_t module_md5 = 0x554838A8451AC36CULL;
|
| + base::FilePath module_path("/some/path/to/chrome");
|
| #endif
|
| - )
|
| - };
|
|
|
| - // Duplicate samples in slots 0, 2, and 3.
|
| - const Frame sample_frames[][1] = {
|
| - { Frame(module_base_address + 0x10, 0), },
|
| - { Frame(module_base_address + 0x20, 0), },
|
| - { Frame(module_base_address + 0x10, 0), },
|
| - { Frame(module_base_address + 0x10, 0) }
|
| + Profiles profiles = ProfilesFactory()
|
| + .NewProfile(100, 10)
|
| + .DefineModule(module_name, module_path, module_base_address)
|
| +
|
| + .AddPhase(0)
|
| + .NewSample()
|
| + .AddFrame(0, module_base_address + 0x10)
|
| + .NewSample()
|
| + .AddFrame(0, module_base_address + 0x20)
|
| + .NewSample()
|
| + .AddFrame(0, module_base_address + 0x10)
|
| + .NewSample()
|
| + .AddFrame(0, module_base_address + 0x10)
|
| +
|
| + .AddPhase(1)
|
| + .NewSample()
|
| + .AddFrame(0, module_base_address + 0x10)
|
| + .NewSample()
|
| + .AddFrame(0, module_base_address + 0x20)
|
| + .NewSample()
|
| + .AddFrame(0, module_base_address + 0x10)
|
| + .NewSample()
|
| + .AddFrame(0, module_base_address + 0x10)
|
| +
|
| + .Build();
|
| +
|
| + const ExpectedProtoModule expected_proto_modules[] = {
|
| + { module_name, module_md5, module_base_address },
|
| };
|
|
|
| - Profile profile;
|
| - profile.modules.insert(profile.modules.end(), &modules[0],
|
| - &modules[0] + arraysize(modules));
|
| + const ExpectedProtoEntry expected_proto_entries[] = {
|
| + { 0, 0x10 },
|
| + { 0, 0x20 },
|
| + };
|
| + const ExpectedProtoSample expected_proto_samples[] = {
|
| + { 1, &expected_proto_entries[0], 1, 3 },
|
| + { 0, &expected_proto_entries[1], 1, 1 },
|
| + { 2, &expected_proto_entries[0], 1, 3 },
|
| + { 0, &expected_proto_entries[1], 1, 1 },
|
| + };
|
|
|
| - for (size_t i = 0; i < arraysize(sample_frames); ++i) {
|
| - profile.samples.push_back(Sample());
|
| - Sample& sample = profile.samples.back();
|
| - sample.insert(sample.end(), &sample_frames[i][0],
|
| - &sample_frames[i][0] + arraysize(sample_frames[i]));
|
| - }
|
| + const ExpectedProtoProfile expected_proto_profiles[] = {
|
| + {
|
| + 100, 10,
|
| + expected_proto_modules, arraysize(expected_proto_modules),
|
| + expected_proto_samples, arraysize(expected_proto_samples),
|
| + },
|
| + };
|
|
|
| - profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
|
| - profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
|
| - Profiles profiles;
|
| - profiles.push_back(std::move(profile));
|
| + ASSERT_EQ(arraysize(expected_proto_profiles), profiles.size());
|
|
|
| CallStackProfileMetricsProvider provider;
|
| provider.OnRecordingEnabled();
|
| @@ -332,36 +437,12 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksUnordered) {
|
| ChromeUserMetricsExtension uma_proto;
|
| provider.ProvideGeneralMetrics(&uma_proto);
|
|
|
| - ASSERT_EQ(1, uma_proto.sampled_profile().size());
|
| - const SampledProfile& sampled_profile = uma_proto.sampled_profile().Get(0);
|
| - ASSERT_TRUE(sampled_profile.has_call_stack_profile());
|
| - const CallStackProfile& call_stack_profile =
|
| - sampled_profile.call_stack_profile();
|
| -
|
| - ASSERT_EQ(2, call_stack_profile.sample().size());
|
| - for (int i = 0; i < 2; ++i) {
|
| - SCOPED_TRACE("sample " + base::IntToString(i));
|
| - const CallStackProfile::Sample& proto_sample =
|
| - call_stack_profile.sample().Get(i);
|
| - ASSERT_EQ(static_cast<int>(arraysize(sample_frames[i])),
|
| - proto_sample.entry().size());
|
| - ASSERT_TRUE(proto_sample.has_count());
|
| - EXPECT_EQ(i == 0 ? 3u : 1u, proto_sample.count());
|
| - for (size_t j = 0; j < arraysize(sample_frames[i]); ++j) {
|
| - SCOPED_TRACE("frame " + base::SizeTToString(j));
|
| - const CallStackProfile::Entry& entry = proto_sample.entry().Get(j);
|
| - ASSERT_TRUE(entry.has_address());
|
| - const char* instruction_pointer = reinterpret_cast<const char*>(
|
| - sample_frames[i][j].instruction_pointer);
|
| - const char* module_base_address = reinterpret_cast<const char*>(
|
| - modules[sample_frames[i][j].module_index].base_address);
|
| - EXPECT_EQ(
|
| - static_cast<uint64_t>(instruction_pointer - module_base_address),
|
| - entry.address());
|
| - ASSERT_TRUE(entry.has_module_id_index());
|
| - EXPECT_EQ(sample_frames[i][j].module_index,
|
| - static_cast<size_t>(entry.module_id_index()));
|
| - }
|
| + ASSERT_EQ(static_cast<int>(arraysize(expected_proto_profiles)),
|
| + uma_proto.sampled_profile().size());
|
| + for (size_t p = 0; p < arraysize(expected_proto_profiles); ++p) {
|
| + SCOPED_TRACE("profile " + base::SizeTToString(p));
|
| + VerifyProfileProto(expected_proto_profiles[p],
|
| + uma_proto.sampled_profile().Get(p));
|
| }
|
| }
|
|
|
| @@ -369,42 +450,68 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksUnordered) {
|
| // preserve_sample_ordering = true.
|
| TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksOrdered) {
|
| const uintptr_t module_base_address = 0x1000;
|
| + const char* module_name = "ABCD";
|
|
|
| - const Module modules[] = {
|
| - Module(
|
| - module_base_address,
|
| - "ABCD",
|
| #if defined(OS_WIN)
|
| - base::FilePath(L"c:\\some\\path\\to\\chrome.exe")
|
| + uint64_t module_md5 = 0x46C3E4166659AC02ULL;
|
| + base::FilePath module_path(L"c:\\some\\path\\to\\chrome.exe");
|
| #else
|
| - base::FilePath("/some/path/to/chrome")
|
| + uint64_t module_md5 = 0x554838A8451AC36CULL;
|
| + base::FilePath module_path("/some/path/to/chrome");
|
| #endif
|
| - )
|
| - };
|
|
|
| - // Duplicate samples in slots 0, 2, and 3.
|
| - const Frame sample_frames[][1] = {
|
| - { Frame(module_base_address + 0x10, 0), },
|
| - { Frame(module_base_address + 0x20, 0), },
|
| - { Frame(module_base_address + 0x10, 0), },
|
| - { Frame(module_base_address + 0x10, 0) }
|
| + Profiles profiles = ProfilesFactory()
|
| + .NewProfile(100, 10)
|
| + .DefineModule(module_name, module_path, module_base_address)
|
| +
|
| + .AddPhase(0)
|
| + .NewSample()
|
| + .AddFrame(0, module_base_address + 0x10)
|
| + .NewSample()
|
| + .AddFrame(0, module_base_address + 0x20)
|
| + .NewSample()
|
| + .AddFrame(0, module_base_address + 0x10)
|
| + .NewSample()
|
| + .AddFrame(0, module_base_address + 0x10)
|
| +
|
| + .AddPhase(1)
|
| + .NewSample()
|
| + .AddFrame(0, module_base_address + 0x10)
|
| + .NewSample()
|
| + .AddFrame(0, module_base_address + 0x20)
|
| + .NewSample()
|
| + .AddFrame(0, module_base_address + 0x10)
|
| + .NewSample()
|
| + .AddFrame(0, module_base_address + 0x10)
|
| +
|
| + .Build();
|
| +
|
| + const ExpectedProtoModule expected_proto_modules[] = {
|
| + { module_name, module_md5, module_base_address },
|
| };
|
|
|
| - Profile profile;
|
| - profile.modules.insert(profile.modules.end(), &modules[0],
|
| - &modules[0] + arraysize(modules));
|
| + const ExpectedProtoEntry expected_proto_entries[] = {
|
| + { 0, 0x10 },
|
| + { 0, 0x20 },
|
| + };
|
| + const ExpectedProtoSample expected_proto_samples[] = {
|
| + { 1, &expected_proto_entries[0], 1, 1 },
|
| + { 0, &expected_proto_entries[1], 1, 1 },
|
| + { 0, &expected_proto_entries[0], 1, 2 },
|
| + { 2, &expected_proto_entries[0], 1, 1 },
|
| + { 0, &expected_proto_entries[1], 1, 1 },
|
| + { 0, &expected_proto_entries[0], 1, 2 },
|
| + };
|
|
|
| - for (size_t i = 0; i < arraysize(sample_frames); ++i) {
|
| - profile.samples.push_back(Sample());
|
| - Sample& sample = profile.samples.back();
|
| - sample.insert(sample.end(), &sample_frames[i][0],
|
| - &sample_frames[i][0] + arraysize(sample_frames[i]));
|
| - }
|
| + const ExpectedProtoProfile expected_proto_profiles[] = {
|
| + {
|
| + 100, 10,
|
| + expected_proto_modules, arraysize(expected_proto_modules),
|
| + expected_proto_samples, arraysize(expected_proto_samples),
|
| + },
|
| + };
|
|
|
| - profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
|
| - profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
|
| - Profiles profiles;
|
| - profiles.push_back(std::move(profile));
|
| + ASSERT_EQ(arraysize(expected_proto_profiles), profiles.size());
|
|
|
| CallStackProfileMetricsProvider provider;
|
| provider.OnRecordingEnabled();
|
| @@ -416,51 +523,39 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksOrdered) {
|
| ChromeUserMetricsExtension uma_proto;
|
| provider.ProvideGeneralMetrics(&uma_proto);
|
|
|
| - ASSERT_EQ(1, uma_proto.sampled_profile().size());
|
| - const SampledProfile& sampled_profile = uma_proto.sampled_profile().Get(0);
|
| - ASSERT_TRUE(sampled_profile.has_call_stack_profile());
|
| - const CallStackProfile& call_stack_profile =
|
| - sampled_profile.call_stack_profile();
|
| -
|
| - ASSERT_EQ(3, call_stack_profile.sample().size());
|
| - for (int i = 0; i < 3; ++i) {
|
| - SCOPED_TRACE("sample " + base::IntToString(i));
|
| - const CallStackProfile::Sample& proto_sample =
|
| - call_stack_profile.sample().Get(i);
|
| - ASSERT_EQ(static_cast<int>(arraysize(sample_frames[i])),
|
| - proto_sample.entry().size());
|
| - ASSERT_TRUE(proto_sample.has_count());
|
| - EXPECT_EQ(i == 2 ? 2u : 1u, proto_sample.count());
|
| - for (size_t j = 0; j < arraysize(sample_frames[i]); ++j) {
|
| - SCOPED_TRACE("frame " + base::SizeTToString(j));
|
| - const CallStackProfile::Entry& entry = proto_sample.entry().Get(j);
|
| - ASSERT_TRUE(entry.has_address());
|
| - const char* instruction_pointer = reinterpret_cast<const char*>(
|
| - sample_frames[i][j].instruction_pointer);
|
| - const char* module_base_address = reinterpret_cast<const char*>(
|
| - modules[sample_frames[i][j].module_index].base_address);
|
| - EXPECT_EQ(
|
| - static_cast<uint64_t>(instruction_pointer - module_base_address),
|
| - entry.address());
|
| - ASSERT_TRUE(entry.has_module_id_index());
|
| - EXPECT_EQ(sample_frames[i][j].module_index,
|
| - static_cast<size_t>(entry.module_id_index()));
|
| - }
|
| + ASSERT_EQ(static_cast<int>(arraysize(expected_proto_profiles)),
|
| + uma_proto.sampled_profile().size());
|
| + for (size_t p = 0; p < arraysize(expected_proto_profiles); ++p) {
|
| + SCOPED_TRACE("profile " + base::SizeTToString(p));
|
| + VerifyProfileProto(expected_proto_profiles[p],
|
| + uma_proto.sampled_profile().Get(p));
|
| }
|
| }
|
|
|
| // Checks that unknown modules produce an empty Entry.
|
| TEST_F(CallStackProfileMetricsProviderTest, UnknownModule) {
|
| - const Frame frame(0x1000, Frame::kUnknownModuleIndex);
|
| -
|
| - Profile profile;
|
| + Profiles profiles = ProfilesFactory()
|
| + .NewProfile(100, 10)
|
| + .NewSample()
|
| + .AddFrame(Frame::kUnknownModuleIndex, 0x1234)
|
| + .Build();
|
| +
|
| + const ExpectedProtoEntry expected_proto_entries[] = {
|
| + { -1, 0 },
|
| + };
|
| + const ExpectedProtoSample expected_proto_samples[] = {
|
| + { 0, &expected_proto_entries[0], 1, 1 },
|
| + };
|
|
|
| - profile.samples.push_back(Sample(1, frame));
|
| + const ExpectedProtoProfile expected_proto_profiles[] = {
|
| + {
|
| + 100, 10,
|
| + nullptr, 0,
|
| + expected_proto_samples, arraysize(expected_proto_samples),
|
| + },
|
| + };
|
|
|
| - profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
|
| - profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
|
| - Profiles profiles;
|
| - profiles.push_back(std::move(profile));
|
| + ASSERT_EQ(arraysize(expected_proto_profiles), profiles.size());
|
|
|
| CallStackProfileMetricsProvider provider;
|
| provider.OnRecordingEnabled();
|
| @@ -473,38 +568,30 @@ TEST_F(CallStackProfileMetricsProviderTest, UnknownModule) {
|
| ChromeUserMetricsExtension uma_proto;
|
| provider.ProvideGeneralMetrics(&uma_proto);
|
|
|
| - ASSERT_EQ(1, uma_proto.sampled_profile().size());
|
| - const SampledProfile& sampled_profile = uma_proto.sampled_profile().Get(0);
|
| - ASSERT_TRUE(sampled_profile.has_call_stack_profile());
|
| - const CallStackProfile& call_stack_profile =
|
| - sampled_profile.call_stack_profile();
|
| -
|
| - ASSERT_EQ(1, call_stack_profile.sample().size());
|
| - const CallStackProfile::Sample& proto_sample =
|
| - call_stack_profile.sample().Get(0);
|
| - ASSERT_EQ(1, proto_sample.entry().size());
|
| - ASSERT_TRUE(proto_sample.has_count());
|
| - EXPECT_EQ(1u, proto_sample.count());
|
| - const CallStackProfile::Entry& entry = proto_sample.entry().Get(0);
|
| - EXPECT_FALSE(entry.has_address());
|
| - EXPECT_FALSE(entry.has_module_id_index());
|
| + ASSERT_EQ(static_cast<int>(arraysize(expected_proto_profiles)),
|
| + uma_proto.sampled_profile().size());
|
| + for (size_t p = 0; p < arraysize(expected_proto_profiles); ++p) {
|
| + SCOPED_TRACE("profile " + base::SizeTToString(p));
|
| + VerifyProfileProto(expected_proto_profiles[p],
|
| + uma_proto.sampled_profile().Get(p));
|
| + }
|
| }
|
|
|
| // Checks that pending profiles are only passed back to ProvideGeneralMetrics
|
| // once.
|
| TEST_F(CallStackProfileMetricsProviderTest, ProfilesProvidedOnlyOnce) {
|
| CallStackProfileMetricsProvider provider;
|
| - for (int i = 0; i < 2; ++i) {
|
| - Profile profile;
|
| - profile.samples.push_back(
|
| - Sample(1, Frame(0x1000, Frame::kUnknownModuleIndex)));
|
| + for (int r = 0; r < 2; ++r) {
|
| + Profiles profiles = ProfilesFactory()
|
| + // Use the sampling period to distinguish the two profiles.
|
| + .NewProfile(100, r)
|
| + .NewSample()
|
| + .AddFrame(Frame::kUnknownModuleIndex, 0x1234)
|
| + .Build();
|
|
|
| - profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
|
| - // Use the sampling period to distinguish the two profiles.
|
| - profile.sampling_period = base::TimeDelta::FromMilliseconds(i);
|
| - Profiles profiles;
|
| - profiles.push_back(std::move(profile));
|
| + ASSERT_EQ(1U, profiles.size());
|
|
|
| + CallStackProfileMetricsProvider provider;
|
| provider.OnRecordingEnabled();
|
| AppendProfiles(
|
| CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
|
| @@ -521,7 +608,7 @@ TEST_F(CallStackProfileMetricsProviderTest, ProfilesProvidedOnlyOnce) {
|
| const CallStackProfile& call_stack_profile =
|
| sampled_profile.call_stack_profile();
|
| ASSERT_TRUE(call_stack_profile.has_sampling_period_ms());
|
| - EXPECT_EQ(i, call_stack_profile.sampling_period_ms());
|
| + EXPECT_EQ(r, call_stack_profile.sampling_period_ms());
|
| }
|
| }
|
|
|
| @@ -529,14 +616,13 @@ TEST_F(CallStackProfileMetricsProviderTest, ProfilesProvidedOnlyOnce) {
|
| // when collected before CallStackProfileMetricsProvider is instantiated.
|
| TEST_F(CallStackProfileMetricsProviderTest,
|
| ProfilesProvidedWhenCollectedBeforeInstantiation) {
|
| - Profile profile;
|
| - profile.samples.push_back(
|
| - Sample(1, Frame(0x1000, Frame::kUnknownModuleIndex)));
|
| + Profiles profiles = ProfilesFactory()
|
| + .NewProfile(100, 10)
|
| + .NewSample()
|
| + .AddFrame(Frame::kUnknownModuleIndex, 0x1234)
|
| + .Build();
|
|
|
| - profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
|
| - profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
|
| - Profiles profiles;
|
| - profiles.push_back(std::move(profile));
|
| + ASSERT_EQ(1U, profiles.size());
|
|
|
| AppendProfiles(
|
| CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
|
| @@ -556,14 +642,13 @@ TEST_F(CallStackProfileMetricsProviderTest,
|
| // Checks that pending profiles are not provided to ProvideGeneralMetrics
|
| // while recording is disabled.
|
| TEST_F(CallStackProfileMetricsProviderTest, ProfilesNotProvidedWhileDisabled) {
|
| - Profile profile;
|
| - profile.samples.push_back(
|
| - Sample(1, Frame(0x1000, Frame::kUnknownModuleIndex)));
|
| + Profiles profiles = ProfilesFactory()
|
| + .NewProfile(100, 10)
|
| + .NewSample()
|
| + .AddFrame(Frame::kUnknownModuleIndex, 0x1234)
|
| + .Build();
|
|
|
| - profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
|
| - profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
|
| - Profiles profiles;
|
| - profiles.push_back(std::move(profile));
|
| + ASSERT_EQ(1U, profiles.size());
|
|
|
| CallStackProfileMetricsProvider provider;
|
| provider.OnRecordingDisabled();
|
| @@ -583,13 +668,6 @@ TEST_F(CallStackProfileMetricsProviderTest, ProfilesNotProvidedWhileDisabled) {
|
| // if recording is disabled while profiling.
|
| TEST_F(CallStackProfileMetricsProviderTest,
|
| ProfilesNotProvidedAfterChangeToDisabled) {
|
| - Profile profile;
|
| - profile.samples.push_back(
|
| - Sample(1, Frame(0x1000, Frame::kUnknownModuleIndex)));
|
| -
|
| - profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
|
| - profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
|
| -
|
| CallStackProfileMetricsProvider provider;
|
| provider.OnRecordingEnabled();
|
| base::StackSamplingProfiler::CompletedCallback callback =
|
| @@ -598,10 +676,13 @@ TEST_F(CallStackProfileMetricsProviderTest,
|
| CallStackProfileParams::UI_THREAD,
|
| CallStackProfileParams::PROCESS_STARTUP,
|
| CallStackProfileParams::MAY_SHUFFLE));
|
| -
|
| provider.OnRecordingDisabled();
|
| - Profiles profiles;
|
| - profiles.push_back(std::move(profile));
|
| +
|
| + Profiles profiles = ProfilesFactory()
|
| + .NewProfile(100, 10)
|
| + .NewSample()
|
| + .AddFrame(Frame::kUnknownModuleIndex, 0x1234)
|
| + .Build();
|
| callback.Run(std::move(profiles));
|
| ChromeUserMetricsExtension uma_proto;
|
| provider.ProvideGeneralMetrics(&uma_proto);
|
| @@ -613,13 +694,6 @@ TEST_F(CallStackProfileMetricsProviderTest,
|
| // recording is enabled, but then disabled and reenabled while profiling.
|
| TEST_F(CallStackProfileMetricsProviderTest,
|
| ProfilesNotProvidedAfterChangeToDisabledThenEnabled) {
|
| - Profile profile;
|
| - profile.samples.push_back(
|
| - Sample(1, Frame(0x1000, Frame::kUnknownModuleIndex)));
|
| -
|
| - profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
|
| - profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
|
| -
|
| CallStackProfileMetricsProvider provider;
|
| provider.OnRecordingEnabled();
|
| base::StackSamplingProfiler::CompletedCallback callback =
|
| @@ -628,11 +702,14 @@ TEST_F(CallStackProfileMetricsProviderTest,
|
| CallStackProfileParams::UI_THREAD,
|
| CallStackProfileParams::PROCESS_STARTUP,
|
| CallStackProfileParams::MAY_SHUFFLE));
|
| -
|
| provider.OnRecordingDisabled();
|
| provider.OnRecordingEnabled();
|
| - Profiles profiles;
|
| - profiles.push_back(std::move(profile));
|
| +
|
| + Profiles profiles = ProfilesFactory()
|
| + .NewProfile(100, 10)
|
| + .NewSample()
|
| + .AddFrame(Frame::kUnknownModuleIndex, 0x1234)
|
| + .Build();
|
| callback.Run(std::move(profiles));
|
| ChromeUserMetricsExtension uma_proto;
|
| provider.ProvideGeneralMetrics(&uma_proto);
|
| @@ -644,13 +721,6 @@ TEST_F(CallStackProfileMetricsProviderTest,
|
| // if recording is disabled, but then enabled while profiling.
|
| TEST_F(CallStackProfileMetricsProviderTest,
|
| ProfilesNotProvidedAfterChangeFromDisabled) {
|
| - Profile profile;
|
| - profile.samples.push_back(
|
| - Sample(1, Frame(0x1000, Frame::kUnknownModuleIndex)));
|
| -
|
| - profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
|
| - profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
|
| -
|
| CallStackProfileMetricsProvider provider;
|
| provider.OnRecordingDisabled();
|
| base::StackSamplingProfiler::CompletedCallback callback =
|
| @@ -659,10 +729,13 @@ TEST_F(CallStackProfileMetricsProviderTest,
|
| CallStackProfileParams::UI_THREAD,
|
| CallStackProfileParams::PROCESS_STARTUP,
|
| CallStackProfileParams::MAY_SHUFFLE));
|
| -
|
| provider.OnRecordingEnabled();
|
| - Profiles profiles;
|
| - profiles.push_back(std::move(profile));
|
| +
|
| + Profiles profiles = ProfilesFactory()
|
| + .NewProfile(100, 10)
|
| + .NewSample()
|
| + .AddFrame(Frame::kUnknownModuleIndex, 0x1234)
|
| + .Build();
|
| callback.Run(std::move(profiles));
|
| ChromeUserMetricsExtension uma_proto;
|
| provider.ProvideGeneralMetrics(&uma_proto);
|
|
|