Than McIntosh | 7e2f4e9 | 2015-03-05 11:05:02 -0500 | [diff] [blame] | 1 | |
| 2 | #include "perf_data_converter.h" |
| 3 | #include "quipper/perf_parser.h" |
| 4 | #include <map> |
| 5 | |
| 6 | using std::map; |
| 7 | |
| 8 | namespace wireless_android_logging_awp { |
| 9 | |
| 10 | struct RangeTarget { |
| 11 | RangeTarget(uint64 start, uint64 end, uint64 to) |
| 12 | : start(start), end(end), to(to) {} |
| 13 | |
| 14 | bool operator<(const RangeTarget &r) const { |
| 15 | if (start != r.start) { |
| 16 | return start < r.start; |
| 17 | } else if (end != r.end) { |
| 18 | return end < r.end; |
| 19 | } else { |
| 20 | return to < r.to; |
| 21 | } |
| 22 | } |
| 23 | uint64 start; |
| 24 | uint64 end; |
| 25 | uint64 to; |
| 26 | }; |
| 27 | |
| 28 | struct BinaryProfile { |
| 29 | map<uint64, uint64> address_count_map; |
| 30 | map<RangeTarget, uint64> range_count_map; |
| 31 | }; |
| 32 | |
| 33 | wireless_android_play_playlog::AndroidPerfProfile |
| 34 | RawPerfDataToAndroidPerfProfile(const string &perf_file) { |
| 35 | wireless_android_play_playlog::AndroidPerfProfile ret; |
| 36 | quipper::PerfParser parser; |
| 37 | if (!parser.ReadFile(perf_file) || !parser.ParseRawEvents()) { |
| 38 | return ret; |
| 39 | } |
| 40 | |
| 41 | typedef map<string, BinaryProfile> ModuleProfileMap; |
| 42 | typedef map<string, ModuleProfileMap> ProgramProfileMap; |
| 43 | ProgramProfileMap name_profile_map; |
| 44 | uint64 total_samples = 0; |
| 45 | for (const auto &event : parser.parsed_events()) { |
| 46 | if (!event.raw_event || |
| 47 | event.raw_event->header.type != PERF_RECORD_SAMPLE) { |
| 48 | continue; |
| 49 | } |
| 50 | string dso_name = event.dso_and_offset.dso_name(); |
| 51 | string program_name; |
| 52 | if (dso_name == "[kernel.kallsyms]_text") { |
| 53 | program_name = "kernel"; |
| 54 | dso_name = "[kernel.kallsyms]"; |
| 55 | } else if (event.command() == "") { |
| 56 | program_name = "unknown_program"; |
| 57 | } else { |
| 58 | program_name = event.command(); |
| 59 | } |
| 60 | name_profile_map[program_name][dso_name].address_count_map[ |
| 61 | event.dso_and_offset.offset()]++; |
| 62 | total_samples++; |
| 63 | for (size_t i = 1; i < event.branch_stack.size(); i++) { |
| 64 | if (dso_name == event.branch_stack[i - 1].to.dso_name()) { |
| 65 | uint64 start = event.branch_stack[i].to.offset(); |
| 66 | uint64 end = event.branch_stack[i - 1].from.offset(); |
| 67 | uint64 to = event.branch_stack[i - 1].to.offset(); |
| 68 | // The interval between two taken branches should not be too large. |
| 69 | if (end < start || end - start > (1 << 20)) { |
| 70 | LOG(WARNING) << "Bogus LBR data: " << start << "->" << end; |
| 71 | continue; |
| 72 | } |
| 73 | name_profile_map[program_name][dso_name].range_count_map[ |
| 74 | RangeTarget(start, end, to)]++; |
| 75 | } |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | map<string, int> name_id_map; |
| 80 | for (const auto &program_profile : name_profile_map) { |
| 81 | for (const auto &module_profile : program_profile.second) { |
| 82 | name_id_map[module_profile.first] = 0; |
| 83 | } |
| 84 | } |
| 85 | int current_index = 0; |
| 86 | for (auto iter = name_id_map.begin(); iter != name_id_map.end(); ++iter) { |
| 87 | iter->second = current_index++; |
| 88 | } |
| 89 | |
| 90 | map<string, string> name_buildid_map; |
| 91 | parser.GetFilenamesToBuildIDs(&name_buildid_map); |
| 92 | ret.set_total_samples(total_samples); |
| 93 | for (const auto &name_id : name_id_map) { |
| 94 | auto load_module = ret.add_load_modules(); |
| 95 | load_module->set_name(name_id.first); |
| 96 | auto nbmi = name_buildid_map.find(name_id.first); |
| 97 | if (nbmi != name_buildid_map.end()) { |
| 98 | const std::string &build_id = nbmi->second; |
| 99 | if (build_id.size() == 40 && build_id.substr(32) == "00000000") { |
| 100 | load_module->set_build_id(build_id.substr(0, 32)); |
| 101 | } else { |
| 102 | load_module->set_build_id(build_id); |
| 103 | } |
| 104 | } |
| 105 | } |
| 106 | for (const auto &program_profile : name_profile_map) { |
| 107 | auto program = ret.add_programs(); |
| 108 | program->set_name(program_profile.first); |
| 109 | for (const auto &module_profile : program_profile.second) { |
| 110 | int32 module_id = name_id_map[module_profile.first]; |
| 111 | auto module = program->add_modules(); |
| 112 | module->set_load_module_id(module_id); |
| 113 | for (const auto &addr_count : module_profile.second.address_count_map) { |
| 114 | auto address_samples = module->add_address_samples(); |
| 115 | address_samples->add_address(addr_count.first); |
| 116 | address_samples->set_count(addr_count.second); |
| 117 | } |
| 118 | for (const auto &range_count : module_profile.second.range_count_map) { |
| 119 | auto range_samples = module->add_range_samples(); |
| 120 | range_samples->set_start(range_count.first.start); |
| 121 | range_samples->set_end(range_count.first.end); |
| 122 | range_samples->set_to(range_count.first.to); |
| 123 | range_samples->set_count(range_count.second); |
| 124 | } |
| 125 | } |
| 126 | } |
| 127 | return ret; |
| 128 | } |
| 129 | |
| 130 | } // namespace wireless_android_logging_awp |