summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2018-01-27 04:07:35 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2018-01-27 04:07:35 +0000
commit74ffa03189676d35ebd95abded8ea926d83466f5 (patch)
tree6bed419a99f0107ee8097ef733e3e6a22a63b7f1
parentbed34e479650536bb12032f11bd819a08c242077 (diff)
parent3f4cdae63fe239d3cc3b9516578a56455ec3d3e6 (diff)
downloadextras-74ffa03189676d35ebd95abded8ea926d83466f5.tar.gz
Merge "Perfprofd: Add process name to sampling"
-rw-r--r--perfprofd/perf_data_converter.cc74
-rw-r--r--perfprofd/perf_profile.proto11
-rw-r--r--perfprofd/quipper/perf_parser.cc7
-rw-r--r--perfprofd/quipper/perf_parser.h14
-rw-r--r--perfprofd/scripts/perf_proto_stack.py20
-rw-r--r--perfprofd/tests/perfprofd_test.cc34
6 files changed, 124 insertions, 36 deletions
diff --git a/perfprofd/perf_data_converter.cc b/perfprofd/perf_data_converter.cc
index f9a245d6..9d35d337 100644
--- a/perfprofd/perf_data_converter.cc
+++ b/perfprofd/perf_data_converter.cc
@@ -84,8 +84,17 @@ RawPerfDataToAndroidPerfProfile(const string &perf_file,
std::unique_ptr<wireless_android_play_playlog::AndroidPerfProfile> ret(
new wireless_android_play_playlog::AndroidPerfProfile());
- typedef map<string, BinaryProfile> ModuleProfileMap;
- typedef map<string, ModuleProfileMap> ProgramProfileMap;
+ using ModuleProfileMap = std::map<string, BinaryProfile>;
+ using Program = std::pair<uint32_t /* index into process name table, or uint32_t max */,
+ std::string /* program name = comm of thread */>;
+ using ProgramProfileMap = std::map<Program, ModuleProfileMap>;
+
+ struct ProcessNameTable {
+ std::vector<std::string> names;
+ std::unordered_map<std::string, uint32_t> index_lookup;
+ };
+ constexpr uint32_t kNoProcessNameTableEntry = std::numeric_limits<uint32_t>::max();
+ ProcessNameTable process_name_table;
// Note: the callchain_count_map member in BinaryProfile contains
// pointers into callchains owned by "parser" above, meaning
@@ -116,20 +125,38 @@ RawPerfDataToAndroidPerfProfile(const string &perf_file,
continue;
}
string dso_name = event.dso_and_offset.dso_name();
- string program_name = event.command();
- const string kernel_name = "[kernel.kallsyms]";
- if (android::base::StartsWith(dso_name, kernel_name)) {
- dso_name = kernel_name;
- if (program_name == "") {
- program_name = "kernel";
+ Program program_id;
+ {
+ std::string program_name = event.command();
+ const std::string kernel_name = "[kernel.kallsyms]";
+ if (android::base::StartsWith(dso_name, kernel_name)) {
+ dso_name = kernel_name;
+ if (program_name == "") {
+ program_name = "kernel";
+ }
+ } else if (program_name == "") {
+ if (is_kernel_dso(dso_name)) {
+ program_name = "kernel";
+ } else {
+ program_name = "unknown_program";
+ }
}
- } else if (program_name == "") {
- if (is_kernel_dso(dso_name)) {
- program_name = "kernel";
- } else {
- program_name = "unknown_program";
+ std::string process_name = event.process_command();
+ uint32_t process_name_index = kNoProcessNameTableEntry;
+ if (!process_name.empty()) {
+ auto name_iter = process_name_table.index_lookup.find(process_name);
+ if (name_iter == process_name_table.index_lookup.end()) {
+ process_name_index = process_name_table.names.size();
+ process_name_table.index_lookup.emplace(process_name, process_name_index);
+ process_name_table.names.push_back(process_name);
+ } else {
+ process_name_index = name_iter->second;
+ }
}
+ program_id = std::make_pair(process_name_index, program_name);
}
+ ModuleProfileMap& module_profile_map = name_profile_map[program_id];
+
total_samples++;
// We expect to see either all callchain events, all branch stack
// events, or all flat sample events, not a mix. For callchains,
@@ -140,14 +167,14 @@ RawPerfDataToAndroidPerfProfile(const string &perf_file,
CHECK(!seen_branch_stack && "examining callchain");
seen_callchain = true;
const callchain *cc = &event.callchain;
- name_profile_map[program_name][dso_name].callchain_count_map[cc]++;
+ module_profile_map[dso_name].callchain_count_map[cc]++;
} else if (!event.branch_stack.empty()) {
CHECK(!seen_callchain && "examining branch stack");
seen_branch_stack = true;
- name_profile_map[program_name][dso_name].address_count_map[
+ module_profile_map[dso_name].address_count_map[
event.dso_and_offset.offset()]++;
} else {
- name_profile_map[program_name][dso_name].address_count_map[
+ module_profile_map[dso_name].address_count_map[
event.dso_and_offset.offset()]++;
}
for (size_t i = 1; i < event.branch_stack.size(); i++) {
@@ -160,7 +187,7 @@ RawPerfDataToAndroidPerfProfile(const string &perf_file,
LOG(WARNING) << "Bogus LBR data: " << start << "->" << end;
continue;
}
- name_profile_map[program_name][dso_name].range_count_map[
+ module_profile_map[dso_name].range_count_map[
RangeTarget(start, end, to)]++;
}
}
@@ -244,7 +271,11 @@ RawPerfDataToAndroidPerfProfile(const string &perf_file,
for (const auto &program_profile : name_profile_map) {
auto program = ret->add_programs();
- program->set_name(program_profile.first);
+ const Program& program_id = program_profile.first;
+ program->set_name(program_id.second);
+ if (program_id.first != kNoProcessNameTableEntry) {
+ program->set_process_name_id(program_id.first);
+ }
for (const auto &module_profile : program_profile.second) {
ModuleData& module_data = name_data_map[module_profile.first];
int32 module_id = module_data.index;
@@ -289,6 +320,13 @@ RawPerfDataToAndroidPerfProfile(const string &perf_file,
}
}
+ if (!process_name_table.names.empty()) {
+ wireless_android_play_playlog::ProcessNames* process_names = ret->mutable_process_names();
+ for (const std::string& name : process_name_table.names) {
+ process_names->add_name(name);
+ }
+ }
+
return ret.release();
}
diff --git a/perfprofd/perf_profile.proto b/perfprofd/perf_profile.proto
index 8981eadc..65c9c39a 100644
--- a/perfprofd/perf_profile.proto
+++ b/perfprofd/perf_profile.proto
@@ -63,6 +63,11 @@ message LoadModuleSamples {
repeated RangeSample range_samples = 3;
}
+// A table of program names.
+message ProcessNames {
+ repeated string name = 1;
+}
+
// All samples for a program.
message ProgramSamples {
// Name of the program.
@@ -70,6 +75,9 @@ message ProgramSamples {
// Load module profiles.
repeated LoadModuleSamples modules = 2;
+
+ // Index into ProcessNames for the name of the process.
+ optional uint32 process_name_id = 3;
}
// A compressed representation of a perf profile, which contains samples from
@@ -95,6 +103,9 @@ message AndroidPerfProfile {
// List of all load modules.
repeated LoadModule load_modules = 4;
+ // Table of process names.
+ optional ProcessNames process_names = 11;
+
// is device screen on at point when profile is collected?
optional bool display_on = 5;
diff --git a/perfprofd/quipper/perf_parser.cc b/perfprofd/quipper/perf_parser.cc
index c9ec1891..c529d25b 100644
--- a/perfprofd/quipper/perf_parser.cc
+++ b/perfprofd/quipper/perf_parser.cc
@@ -265,6 +265,13 @@ bool PerfParser::MapSampleEvent(ParsedEvent* parsed_event) {
if (comm_iter != pidtid_to_comm_map_.end()) {
parsed_event->set_command(comm_iter->second);
}
+ {
+ PidTid pidtid_main = std::make_pair(sample_info.pid, sample_info.pid);
+ const auto main_iter = pidtid_to_comm_map_.find(pidtid_main);
+ if (main_iter != pidtid_to_comm_map_.end()) {
+ parsed_event->set_process_command(main_iter->second);
+ }
+ }
const uint64_t unmapped_event_ip = sample_info.ip;
diff --git a/perfprofd/quipper/perf_parser.h b/perfprofd/quipper/perf_parser.h
index bb66de20..28644832 100644
--- a/perfprofd/quipper/perf_parser.h
+++ b/perfprofd/quipper/perf_parser.h
@@ -50,6 +50,9 @@ struct ParsedEvent {
// Command associated with this sample.
const string* command_;
+ // Process' name (command where pid = tid for this thread's pid).
+ const string* process_command_;
+
// Accessor for command string.
const string command() const {
if (command_)
@@ -61,6 +64,17 @@ struct ParsedEvent {
command_ = command;
}
+ // Accessor for process_command string.
+ const string process_command() const {
+ if (process_command_)
+ return *process_command_;
+ return string();
+ }
+
+ void set_process_command(const string* command) {
+ process_command_ = command;
+ }
+
// A struct that contains a DSO + offset pair.
struct DSOAndOffset {
const DSOInfo* dso_info_;
diff --git a/perfprofd/scripts/perf_proto_stack.py b/perfprofd/scripts/perf_proto_stack.py
index 4a576b47..03693589 100644
--- a/perfprofd/scripts/perf_proto_stack.py
+++ b/perfprofd/scripts/perf_proto_stack.py
@@ -47,10 +47,13 @@ def indent(txt, stops = 1):
return '\n'.join(' ' * stops + line for line in txt.splitlines())
-def print_samples(module_list, programs, counters):
+def print_samples(module_list, programs, process_names, counters):
print 'Samples:'
for program in programs:
- print indent(program.name, 1)
+ process_name = '?'
+ if program.HasField('process_name_id'):
+ process_name = process_names[program.process_name_id]
+ print indent('%s (%s)' % (program.name, process_name), 1)
for module in program.modules:
if module.HasField('load_module_id'):
module_descr = module_list[module.load_module_id]
@@ -118,6 +121,17 @@ def print_modules(module_list):
for symbol in module.symbol:
print indent(symbol, 3)
-print_samples(module_list, profile.programs, counters)
+def print_process_names(process_names):
+ print 'Processes:'
+ for proc in process_names:
+ print indent(proc, 1)
+
+if profile.HasField('process_names'):
+ process_names = profile.process_names.name
+else:
+ process_names = []
+
+print_samples(module_list, profile.programs, process_names, counters)
print_modules(module_list)
print_histogram(counters, 100)
+print_process_names(process_names)
diff --git a/perfprofd/tests/perfprofd_test.cc b/perfprofd/tests/perfprofd_test.cc
index 1ee1f777..599bb501 100644
--- a/perfprofd/tests/perfprofd_test.cc
+++ b/perfprofd/tests/perfprofd_test.cc
@@ -90,22 +90,26 @@ static std::string JoinTestLog(const char* delimiter) {
class PerfProfdTest : public testing::Test {
protected:
- virtual void SetUp() {
+ void SetUp() override {
InitTestLog();
android::base::SetLogger(TestLogFunction);
create_dirs();
}
- virtual void TearDown() {
+ void TearDown() override {
android::base::SetLogger(android::base::StderrLogger);
ClearTestLog();
// TODO: proper management of test files. For now, use old system() code.
- for (const auto dir : { &dest_dir, &conf_dir }) {
- std::string cmd("rm -rf ");
- cmd += *dir;
- int ret = system(cmd.c_str());
- CHECK_EQ(0, ret);
+ if (!HasFailure()) {
+ for (const auto dir : { &dest_dir, &conf_dir }) {
+ std::string cmd("rm -rf ");
+ cmd += *dir;
+ int ret = system(cmd.c_str());
+ CHECK_EQ(0, ret);
+ }
+ } else {
+ std::cerr << "Failed test: conf_dir=" << conf_dir << " dest_dir=" << dest_dir;
}
}
@@ -624,8 +628,8 @@ TEST_F(PerfProfdTest, BasicRunWithCannedPerf)
"BasicRunWithCannedPerf",
encodedProfile);
- // Expect 45 programs
- EXPECT_EQ(45, encodedProfile.programs_size());
+ // Expect 48 programs
+ EXPECT_EQ(48, encodedProfile.programs_size());
// Check a couple of load modules
{ const auto &lm0 = encodedProfile.load_modules(0);
@@ -648,7 +652,7 @@ TEST_F(PerfProfdTest, BasicRunWithCannedPerf)
}
// Examine some of the samples now
- { const auto &p1 = encodedProfile.programs(0);
+ { const auto &p1 = encodedProfile.programs(9);
const auto &lm1 = p1.modules(0);
std::string act_lm1 = encodedModuleSamplesToString(lm1);
std::string sqact1 = squeezeWhite(act_lm1, "actual for lm1");
@@ -658,7 +662,7 @@ TEST_F(PerfProfdTest, BasicRunWithCannedPerf)
std::string sqexp1 = squeezeWhite(expected_lm1, "expected_lm1");
EXPECT_STREQ(sqexp1.c_str(), sqact1.c_str());
}
- { const auto &p1 = encodedProfile.programs(2);
+ { const auto &p1 = encodedProfile.programs(11);
const auto &lm2 = p1.modules(0);
std::string act_lm2 = encodedModuleSamplesToString(lm2);
std::string sqact2 = squeezeWhite(act_lm2, "actual for lm2");
@@ -713,7 +717,7 @@ TEST_F(PerfProfdTest, BasicRunWithCannedPerfWithSymbolizer)
encodedProfile);
// Expect 45 programs
- EXPECT_EQ(45, encodedProfile.programs_size());
+ EXPECT_EQ(48, encodedProfile.programs_size());
// Check a couple of load modules
{ const auto &lm0 = encodedProfile.load_modules(0);
@@ -738,7 +742,7 @@ TEST_F(PerfProfdTest, BasicRunWithCannedPerfWithSymbolizer)
}
// Examine some of the samples now
- { const auto &p1 = encodedProfile.programs(0);
+ { const auto &p1 = encodedProfile.programs(9);
const auto &lm1 = p1.modules(0);
std::string act_lm1 = encodedModuleSamplesToString(lm1);
std::string sqact1 = squeezeWhite(act_lm1, "actual for lm1");
@@ -748,7 +752,7 @@ TEST_F(PerfProfdTest, BasicRunWithCannedPerfWithSymbolizer)
std::string sqexp1 = squeezeWhite(expected_lm1, "expected_lm1");
EXPECT_STREQ(sqexp1.c_str(), sqact1.c_str());
}
- { const auto &p1 = encodedProfile.programs(2);
+ { const auto &p1 = encodedProfile.programs(11);
const auto &lm2 = p1.modules(0);
std::string act_lm2 = encodedModuleSamplesToString(lm2);
std::string sqact2 = squeezeWhite(act_lm2, "actual for lm2");
@@ -817,7 +821,7 @@ TEST_F(PerfProfdTest, CallchainRunWithCannedPerf)
}
// Examine some of the samples now
- { const auto &p0 = encodedProfile.programs(0);
+ { const auto &p0 = encodedProfile.programs(1);
const auto &lm1 = p0.modules(0);
std::string act_lm1 = encodedModuleSamplesToString(lm1);
std::string sqact1 = squeezeWhite(act_lm1, "actual for lm1");