blob: 9d997538f3576bb83a484ca326f1dfb157df0121 [file] [log] [blame]
Than McIntosh7e2f4e92015-03-05 11:05:02 -05001
2#include "perf_data_converter.h"
3#include "quipper/perf_parser.h"
4#include <map>
5
6using std::map;
7
8namespace wireless_android_logging_awp {
9
10struct 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
28struct BinaryProfile {
29 map<uint64, uint64> address_count_map;
30 map<RangeTarget, uint64> range_count_map;
31};
32
33wireless_android_play_playlog::AndroidPerfProfile
34RawPerfDataToAndroidPerfProfile(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