diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2018-01-27 04:07:35 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2018-01-27 04:07:35 +0000 |
commit | 74ffa03189676d35ebd95abded8ea926d83466f5 (patch) | |
tree | 6bed419a99f0107ee8097ef733e3e6a22a63b7f1 | |
parent | bed34e479650536bb12032f11bd819a08c242077 (diff) | |
parent | 3f4cdae63fe239d3cc3b9516578a56455ec3d3e6 (diff) | |
download | extras-74ffa03189676d35ebd95abded8ea926d83466f5.tar.gz |
Merge "Perfprofd: Add process name to sampling"
-rw-r--r-- | perfprofd/perf_data_converter.cc | 74 | ||||
-rw-r--r-- | perfprofd/perf_profile.proto | 11 | ||||
-rw-r--r-- | perfprofd/quipper/perf_parser.cc | 7 | ||||
-rw-r--r-- | perfprofd/quipper/perf_parser.h | 14 | ||||
-rw-r--r-- | perfprofd/scripts/perf_proto_stack.py | 20 | ||||
-rw-r--r-- | perfprofd/tests/perfprofd_test.cc | 34 |
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"); |