Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(558)

Unified Diff: components/metrics/call_stack_profile_metrics_provider_unittest.cc

Issue 2444143002: Add process lifetime annotations to stack samples. (Closed)
Patch Set: fixed non-windows constant Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..eadfd377e26602185c1a07258f19e422ad67af6c 100644
--- a/components/metrics/call_stack_profile_metrics_provider_unittest.cc
+++ b/components/metrics/call_stack_profile_metrics_provider_unittest.cc
@@ -27,6 +27,64 @@ using Profile = StackSamplingProfiler::CallStackProfile;
using Profiles = StackSamplingProfiler::CallStackProfiles;
using Sample = StackSamplingProfiler::Sample;
+namespace {
+
+using ProfilesGenerator = uint64_t;
+
+enum : ProfilesGenerator {
+ kEndOfGenerator,
+ kAddPhase,
+ kBeginActivity,
+ kEndActivity,
+ kNewProfile,
+ kNewSample,
+ kNextFrame,
+ kDefineModule,
+};
+
+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.
+ uint32_t activities_begun; // Bit-field of expected activities begun.
+ uint32_t activities_ended; // Bit-field of expected activities ended.
+ 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;
+};
+
+} // namespace
+
+#define GEN_ADD_PHASE(phase) kAddPhase, phase
Alexei Svitkine (slow) 2016/11/07 23:22:07 What is this for? I don't see it being used.
bcwhite 2016/11/08 01:02:36 It's not... yet. It'll be needed when the remaini
+#define GEN_BEGIN_ACTIVITY(activity) kBeginActivity, activity
+#define GEN_END_ACTIVITY(activity) kEndActivity activity
+#define GEN_NEW_PROFILE(duration_ms, interval_ms) \
+ kNewProfile, duration_ms, interval_ms
+#define GEN_NEW_SAMPLE() kNewSample
+#define GEN_FRAME(module, offset) kNextFrame, module, offset
+#define GEN_DEFINE_MODULE(name, path, base) \
+ kDefineModule, reinterpret_cast<uintptr_t>(name), \
+ reinterpret_cast<uintptr_t>(&path), base
+#define GEN_END() kEndOfGenerator
+
namespace metrics {
// This test fixture enables the field trial that
@@ -49,6 +107,13 @@ class CallStackProfileMetricsProviderTest : public testing::Test {
std::move(profiles));
}
+ // Utility to create a Profiles list from a generator constant.
+ void GenerateProfiles(std::vector<Profile>* profiles,
+ const ProfilesGenerator* generator);
+
+ void VerifyProfileProto(const SampledProfile& proto,
+ const ExpectedProtoProfile& expected);
+
private:
// Exposes field trial/group names from the CallStackProfileMetricsProvider.
class TestState : public CallStackProfileMetricsProvider {
@@ -63,54 +128,120 @@ class CallStackProfileMetricsProviderTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(CallStackProfileMetricsProviderTest);
};
+void CallStackProfileMetricsProviderTest::GenerateProfiles(
+ std::vector<Profile>* profiles,
+ const ProfilesGenerator* generator) {
+ uint32_t process_phases = 0;
+ uint32_t current_activities = 0;
+ Profile* profile = nullptr;
+
+ while (true) {
+ switch (*generator++) {
+ case kEndOfGenerator:
+ return;
+ case kAddPhase:
+ process_phases |= 1 << *generator++;
+ break;
+ case kBeginActivity:
+ current_activities |= 1 << *generator++;
+ break;
+ case kEndActivity:
+ current_activities &= ~(1 << *generator++);
+ break;
+ case kNewProfile:
+ profiles->push_back(Profile());
+ profile = &profiles->back();
+ profile->profile_duration =
+ base::TimeDelta::FromMilliseconds(*generator++);
+ profile->sampling_period =
+ base::TimeDelta::FromMilliseconds(*generator++);
+ break;
+ case kNewSample:
+ profile->samples.push_back(Sample());
+ break;
+ case kNextFrame: {
+ size_t index = static_cast<size_t>(*generator++);
+ uintptr_t address = static_cast<uintptr_t>(*generator++);
+ profile->samples.back().frames.push_back(Frame(address, index));
+ } break;
+ case kDefineModule: {
+ const char* name =
+ reinterpret_cast<const char*>(static_cast<uintptr_t>(*generator++));
+ const base::FilePath* path = reinterpret_cast<const base::FilePath*>(
+ static_cast<uintptr_t>(*generator++));
+ uintptr_t base = static_cast<uintptr_t>(*generator++);
+ profile->modules.push_back(Module(base, name, *path));
+ } break;
+ default:
+ NOTREACHED();
+ };
+ }
+}
+
+void CallStackProfileMetricsProviderTest::VerifyProfileProto(
+ const SampledProfile& proto,
+ const ExpectedProtoProfile& expected) {
+ 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;
+ uint32_t activities_begun = 0;
+ uint32_t activities_ended = 0;
+ for (int i = 0; i < proto_sample.process_phase().size(); ++i)
+ process_phases |= 1U << proto_sample.process_phase().Get(i);
+ for (int i = 0; i < proto_sample.activity_begun().size(); ++i)
+ activities_begun |= 1U << proto_sample.activity_begun().Get(i);
+ for (int i = 0; i < proto_sample.activity_ended().size(); ++i)
+ activities_ended |= 1U << proto_sample.activity_ended().Get(i);
+ EXPECT_EQ(expected.samples[s].process_phases, process_phases);
+ EXPECT_EQ(expected.samples[s].activities_begun, activities_begun);
+ EXPECT_EQ(expected.samples[s].activities_ended, activities_ended);
+
+ 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);
+ 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());
+ }
+ }
+}
+
// 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 size_t profiles_count = 2;
+ 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 +252,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
-#else
- 0x554838a8451ac36cUL, 0x843661148659c9f8UL
-#endif
- },
- {
#if defined(OS_WIN)
- 0x87b66f4573a4d5caULL, 0x46c3e4166659ac02ULL
+ 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
- 0xb4647e539fa6ec9eUL, 0x554838a8451ac36cUL
+ 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
- }};
// 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 +277,104 @@ 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] = {
- {
+ const ProfilesGenerator test_profiles_generator[] = {
+ GEN_NEW_PROFILE(100, 10),
+ GEN_DEFINE_MODULE(moduleA_name, moduleA_path, moduleA_base_address),
+ GEN_DEFINE_MODULE(moduleB_name, moduleB_path, moduleB_base_address),
+
+ GEN_NEW_SAMPLE(),
+ GEN_FRAME(0, moduleA_base_address + 0x10),
+ GEN_FRAME(1, moduleB_base_address + 0x20),
+ GEN_FRAME(0, moduleA_base_address + 0x30),
+ GEN_NEW_SAMPLE(),
+ GEN_FRAME(1, moduleB_base_address + 0x10),
+ GEN_FRAME(0, moduleA_base_address + 0x20),
+ GEN_FRAME(1, moduleB_base_address + 0x30),
+
+ GEN_NEW_PROFILE(200, 20),
+ GEN_DEFINE_MODULE(moduleC_name, moduleC_path, moduleC_base_address),
+ GEN_DEFINE_MODULE(moduleA_name, moduleA_path, moduleA_base_address),
+
+ GEN_NEW_SAMPLE(),
+ GEN_FRAME(0, moduleC_base_address + 0x10),
+ GEN_FRAME(1, moduleA_base_address + 0x20),
+ GEN_FRAME(0, moduleC_base_address + 0x30),
+ GEN_NEW_SAMPLE(),
+ GEN_FRAME(1, moduleA_base_address + 0x10),
+ GEN_FRAME(0, moduleC_base_address + 0x20),
+ GEN_FRAME(1, moduleA_base_address + 0x30),
+
+ GEN_END(),
+ };
+
+ 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, 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, 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, 0, 0,
+ expected_proto_entries11, arraysize(expected_proto_entries21), 1,
+ },
+ {
+ 0, 0, 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));
- }
+ std::vector<Profile> profiles;
+ GenerateProfiles(&profiles, test_profiles_generator);
+ ASSERT_EQ(profiles_count, profiles.size());
CallStackProfileMetricsProvider provider;
provider.OnRecordingEnabled();
@@ -215,68 +387,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>(profiles_count),
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 < profiles_count; ++p) {
+ SCOPED_TRACE("profile " + base::SizeTToString(p));
+ VerifyProfileProto(uma_proto.sampled_profile().Get(p),
+ expected_proto_profiles[p]);
}
}
@@ -297,12 +413,32 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksUnordered) {
)
};
- // Duplicate samples in slots 0, 2, and 3.
+ // Samples are unique only if the phase, activity, and frame all match.
+ const uint32_t profile_phases_and_activities[][2] = {
+ { 1, 0 },
+ { 1, 0 },
+ { 3, 0 },
+ { 3, 0 },
+ { 3, 1 },
+ // Unique above, duplicates below.
+ { 1, 0 },
+ { 1, 0 },
+ { 3, 0 },
+ };
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) }
+ { Frame(module_base_address + 0x20, 0), },
+ { Frame(module_base_address + 0x10, 0), },
+ // Unique above, duplicates below.
+ { Frame(module_base_address + 0x10, 0), },
+ { Frame(module_base_address + 0x10, 0), },
+ { Frame(module_base_address + 0x10, 0), },
+ };
+
+ const int duplicate_counts[] = {
+ 3, 1, 2, 1, 1,
};
Profile profile;
@@ -312,8 +448,10 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksUnordered) {
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]));
+ sample.process_phases = profile_phases_and_activities[i][0];
+ sample.current_activities = profile_phases_and_activities[i][1];
+ sample.frames.insert(sample.frames.end(), &sample_frames[i][0],
+ &sample_frames[i][0] + arraysize(sample_frames[i]));
}
profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
@@ -338,15 +476,21 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksUnordered) {
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));
+ ASSERT_EQ(static_cast<int>(arraysize(duplicate_counts)),
+ call_stack_profile.sample().size());
+ for (size_t i = 0; i < arraysize(duplicate_counts); ++i) {
+ SCOPED_TRACE("sample " + base::SizeTToString(i));
const CallStackProfile::Sample& proto_sample =
call_stack_profile.sample().Get(i);
+
+ // For MAY_SHUFFLE, these are reset with every sample.
+ uint32_t process_phase = 0;
+ uint32_t current_activities = 0;
+
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());
+ EXPECT_EQ(duplicate_counts[i], 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);
@@ -362,6 +506,19 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksUnordered) {
EXPECT_EQ(sample_frames[i][j].module_index,
static_cast<size_t>(entry.module_id_index()));
}
+
+ for (int x = 0; x < proto_sample.process_phase_size(); ++x) {
+ process_phase |= 1 << proto_sample.process_phase(x);
+ }
+ EXPECT_EQ(profile_phases_and_activities[i][0], process_phase);
+
+ for (int x = 0; x < proto_sample.activity_begun_size(); ++x) {
+ current_activities |= 1 << proto_sample.activity_begun(x);
+ }
+ for (int x = 0; x < proto_sample.activity_ended_size(); ++x) {
+ current_activities &= ~(1 << proto_sample.activity_ended(x));
+ }
+ EXPECT_EQ(profile_phases_and_activities[i][1], current_activities);
}
}
@@ -382,12 +539,32 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksOrdered) {
)
};
- // Duplicate samples in slots 0, 2, and 3.
+ // Samples are unique only if the phase, activity, and frame all match.
+ const uint32_t profile_phases_and_activities[][2] = {
+ { 1, 0 },
+ { 1, 0 },
+ { 1, 0 },
+ { 1, 0 },
+
+ { 3, 0 },
+ { 3, 1 },
+ { 3, 0 },
+ { 3, 0 },
+ };
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) }
+ { Frame(module_base_address + 0x10, 0), },
+
+ { Frame(module_base_address + 0x10, 0), },
+ { Frame(module_base_address + 0x20, 0), },
+ { Frame(module_base_address + 0x10, 0), },
+ { Frame(module_base_address + 0x10, 0), },
+ };
+
+ const int duplicate_counts[] = {
+ 1, 1, 2, 1, 1, 2
};
Profile profile;
@@ -397,8 +574,10 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksOrdered) {
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]));
+ sample.process_phases = profile_phases_and_activities[i][0];
+ sample.current_activities = profile_phases_and_activities[i][1];
+ sample.frames.insert(sample.frames.end(), &sample_frames[i][0],
+ &sample_frames[i][0] + arraysize(sample_frames[i]));
}
profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
@@ -422,41 +601,57 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksOrdered) {
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));
+ // For PRESERVE_ORDER, these are reset with every profile.
+ uint32_t process_phase = 0;
+ uint32_t current_activities = 0;
+
+ ASSERT_EQ(static_cast<int>(arraysize(duplicate_counts)),
+ call_stack_profile.sample().size());
+ for (size_t i = 0, d = 0; i < arraysize(duplicate_counts);
+ d += duplicate_counts[i], ++i) {
+ // |d| is the index after compensating for duplicate compression.
+ SCOPED_TRACE("sample " + base::SizeTToString(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) {
+ EXPECT_EQ(duplicate_counts[i], proto_sample.count());
+ for (size_t j = 0; j < arraysize(sample_frames[d]); ++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);
+ sample_frames[d][j].instruction_pointer);
const char* module_base_address = reinterpret_cast<const char*>(
- modules[sample_frames[i][j].module_index].base_address);
+ modules[sample_frames[d][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,
+ EXPECT_EQ(sample_frames[d][j].module_index,
static_cast<size_t>(entry.module_id_index()));
}
+
+ for (int x = 0; x < proto_sample.process_phase_size(); ++x) {
+ process_phase |= 1 << proto_sample.process_phase(x);
+ }
+ EXPECT_EQ(profile_phases_and_activities[d][0], process_phase);
+
+ for (int x = 0; x < proto_sample.activity_begun_size(); ++x) {
+ current_activities |= 1 << proto_sample.activity_begun(x);
+ }
+ for (int x = 0; x < proto_sample.activity_ended_size(); ++x) {
+ current_activities &= ~(1 << proto_sample.activity_ended(x));
+ }
+ EXPECT_EQ(profile_phases_and_activities[d][1], current_activities);
}
}
// Checks that unknown modules produce an empty Entry.
TEST_F(CallStackProfileMetricsProviderTest, UnknownModule) {
- const Frame frame(0x1000, Frame::kUnknownModuleIndex);
-
Profile profile;
-
- profile.samples.push_back(Sample(1, frame));
-
+ profile.samples.push_back(Sample(Frame(0x1000, Frame::kUnknownModuleIndex)));
profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
Profiles profiles;
@@ -497,7 +692,7 @@ TEST_F(CallStackProfileMetricsProviderTest, ProfilesProvidedOnlyOnce) {
for (int i = 0; i < 2; ++i) {
Profile profile;
profile.samples.push_back(
- Sample(1, Frame(0x1000, Frame::kUnknownModuleIndex)));
+ Sample((Frame(0x1000, Frame::kUnknownModuleIndex))));
profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
// Use the sampling period to distinguish the two profiles.
@@ -530,9 +725,7 @@ TEST_F(CallStackProfileMetricsProviderTest, ProfilesProvidedOnlyOnce) {
TEST_F(CallStackProfileMetricsProviderTest,
ProfilesProvidedWhenCollectedBeforeInstantiation) {
Profile profile;
- profile.samples.push_back(
- Sample(1, Frame(0x1000, Frame::kUnknownModuleIndex)));
-
+ profile.samples.push_back(Sample(Frame(0x1000, Frame::kUnknownModuleIndex)));
profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
Profiles profiles;
@@ -557,9 +750,7 @@ TEST_F(CallStackProfileMetricsProviderTest,
// while recording is disabled.
TEST_F(CallStackProfileMetricsProviderTest, ProfilesNotProvidedWhileDisabled) {
Profile profile;
- profile.samples.push_back(
- Sample(1, Frame(0x1000, Frame::kUnknownModuleIndex)));
-
+ profile.samples.push_back(Sample(Frame(0x1000, Frame::kUnknownModuleIndex)));
profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
Profiles profiles;
@@ -584,9 +775,7 @@ TEST_F(CallStackProfileMetricsProviderTest, ProfilesNotProvidedWhileDisabled) {
TEST_F(CallStackProfileMetricsProviderTest,
ProfilesNotProvidedAfterChangeToDisabled) {
Profile profile;
- profile.samples.push_back(
- Sample(1, Frame(0x1000, Frame::kUnknownModuleIndex)));
-
+ profile.samples.push_back(Sample(Frame(0x1000, Frame::kUnknownModuleIndex)));
profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
@@ -614,9 +803,7 @@ TEST_F(CallStackProfileMetricsProviderTest,
TEST_F(CallStackProfileMetricsProviderTest,
ProfilesNotProvidedAfterChangeToDisabledThenEnabled) {
Profile profile;
- profile.samples.push_back(
- Sample(1, Frame(0x1000, Frame::kUnknownModuleIndex)));
-
+ profile.samples.push_back(Sample(Frame(0x1000, Frame::kUnknownModuleIndex)));
profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
@@ -645,9 +832,7 @@ TEST_F(CallStackProfileMetricsProviderTest,
TEST_F(CallStackProfileMetricsProviderTest,
ProfilesNotProvidedAfterChangeFromDisabled) {
Profile profile;
- profile.samples.push_back(
- Sample(1, Frame(0x1000, Frame::kUnknownModuleIndex)));
-
+ profile.samples.push_back(Sample(Frame(0x1000, Frame::kUnknownModuleIndex)));
profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
profile.sampling_period = base::TimeDelta::FromMilliseconds(10);

Powered by Google App Engine
This is Rietveld 408576698