OSDN Git Service

simpleperf: support raw event types.
[android-x86/system-extras.git] / perfprofd / perf_data_converter.cc
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 typedef quipper::ParsedEvent::DSOAndOffset DSOAndOffset;
11 typedef std::vector<DSOAndOffset> callchain;
12
13 struct callchain_lt {
14   bool operator()(const callchain *c1, const callchain *c2) const {
15     if (c1->size() != c2->size()) {
16       return c1->size() < c2->size();
17     }
18     for (unsigned idx = 0; idx < c1->size(); ++idx) {
19       const DSOAndOffset *do1 = &(*c1)[idx];
20       const DSOAndOffset *do2 = &(*c2)[idx];
21       if (do1->offset() != do2->offset()) {
22         return do1->offset() < do2->offset();
23       }
24       int rc = do1->dso_name().compare(do2->dso_name());
25       if (rc) {
26         return rc < 0;
27       }
28     }
29     return false;
30   }
31 };
32
33 struct RangeTarget {
34   RangeTarget(uint64 start, uint64 end, uint64 to)
35       : start(start), end(end), to(to) {}
36
37   bool operator<(const RangeTarget &r) const {
38     if (start != r.start) {
39       return start < r.start;
40     } else if (end != r.end) {
41       return end < r.end;
42     } else {
43       return to < r.to;
44     }
45   }
46   uint64 start;
47   uint64 end;
48   uint64 to;
49 };
50
51 struct BinaryProfile {
52   map<uint64, uint64> address_count_map;
53   map<RangeTarget, uint64> range_count_map;
54   map<const callchain *, uint64, callchain_lt> callchain_count_map;
55 };
56
57 wireless_android_play_playlog::AndroidPerfProfile
58 RawPerfDataToAndroidPerfProfile(const string &perf_file) {
59   wireless_android_play_playlog::AndroidPerfProfile ret;
60   quipper::PerfParser parser;
61   if (!parser.ReadFile(perf_file) || !parser.ParseRawEvents()) {
62     return ret;
63   }
64
65   typedef map<string, BinaryProfile> ModuleProfileMap;
66   typedef map<string, ModuleProfileMap> ProgramProfileMap;
67
68   // Note: the callchain_count_map member in BinaryProfile contains
69   // pointers into callchains owned by "parser" above, meaning
70   // that once the parser is destroyed, callchain pointers in
71   // name_profile_map will become stale (e.g. keep these two
72   // together in the same region).
73   ProgramProfileMap name_profile_map;
74   uint64 total_samples = 0;
75   bool seen_branch_stack = false;
76   bool seen_callchain = false;
77   for (const auto &event : parser.parsed_events()) {
78     if (!event.raw_event ||
79         event.raw_event->header.type != PERF_RECORD_SAMPLE) {
80       continue;
81     }
82     string dso_name = event.dso_and_offset.dso_name();
83     string program_name = event.command();
84     const string kernel_name = "[kernel.kallsyms]";
85     if (dso_name.substr(0, kernel_name.length()) == kernel_name) {
86       dso_name = kernel_name;
87       if (program_name == "") {
88         program_name = "kernel";
89       }
90     } else if (program_name == "") {
91       program_name = "unknown_program";
92     }
93     total_samples++;
94     // We expect to see either all callchain events, all branch stack
95     // events, or all flat sample events, not a mix. For callchains,
96     // however, it can be the case that none of the IPs in a chain
97     // are mappable, in which case the parsed/mapped chain will appear
98     // empty (appearing as a flat sample).
99     if (!event.callchain.empty()) {
100       CHECK(!seen_branch_stack && "examining callchain");
101       seen_callchain = true;
102       const callchain *cc = &event.callchain;
103       name_profile_map[program_name][dso_name].callchain_count_map[cc]++;
104     } else if (!event.branch_stack.empty()) {
105       CHECK(!seen_callchain && "examining branch stack");
106       seen_branch_stack = true;
107       name_profile_map[program_name][dso_name].address_count_map[
108           event.dso_and_offset.offset()]++;
109     } else {
110       name_profile_map[program_name][dso_name].address_count_map[
111           event.dso_and_offset.offset()]++;
112     }
113     for (size_t i = 1; i < event.branch_stack.size(); i++) {
114       if (dso_name == event.branch_stack[i - 1].to.dso_name()) {
115         uint64 start = event.branch_stack[i].to.offset();
116         uint64 end = event.branch_stack[i - 1].from.offset();
117         uint64 to = event.branch_stack[i - 1].to.offset();
118         // The interval between two taken branches should not be too large.
119         if (end < start || end - start > (1 << 20)) {
120           LOG(WARNING) << "Bogus LBR data: " << start << "->" << end;
121           continue;
122         }
123         name_profile_map[program_name][dso_name].range_count_map[
124             RangeTarget(start, end, to)]++;
125       }
126     }
127   }
128
129   map<string, int> name_id_map;
130   for (const auto &program_profile : name_profile_map) {
131     for (const auto &module_profile : program_profile.second) {
132       name_id_map[module_profile.first] = 0;
133     }
134   }
135   int current_index = 0;
136   for (auto iter = name_id_map.begin(); iter != name_id_map.end(); ++iter) {
137     iter->second = current_index++;
138   }
139
140   map<string, string> name_buildid_map;
141   parser.GetFilenamesToBuildIDs(&name_buildid_map);
142   ret.set_total_samples(total_samples);
143   for (const auto &name_id : name_id_map) {
144     auto load_module = ret.add_load_modules();
145     load_module->set_name(name_id.first);
146     auto nbmi = name_buildid_map.find(name_id.first);
147     if (nbmi != name_buildid_map.end()) {
148       const std::string &build_id = nbmi->second;
149       if (build_id.size() == 40 && build_id.substr(32) == "00000000") {
150         load_module->set_build_id(build_id.substr(0, 32));
151       } else {
152         load_module->set_build_id(build_id);
153       }
154     }
155   }
156   for (const auto &program_profile : name_profile_map) {
157     auto program = ret.add_programs();
158     program->set_name(program_profile.first);
159     for (const auto &module_profile : program_profile.second) {
160       int32 module_id = name_id_map[module_profile.first];
161       auto module = program->add_modules();
162       module->set_load_module_id(module_id);
163       for (const auto &addr_count : module_profile.second.address_count_map) {
164         auto address_samples = module->add_address_samples();
165         address_samples->add_address(addr_count.first);
166         address_samples->set_count(addr_count.second);
167       }
168       for (const auto &range_count : module_profile.second.range_count_map) {
169         auto range_samples = module->add_range_samples();
170         range_samples->set_start(range_count.first.start);
171         range_samples->set_end(range_count.first.end);
172         range_samples->set_to(range_count.first.to);
173         range_samples->set_count(range_count.second);
174       }
175       for (const auto &callchain_count :
176                module_profile.second.callchain_count_map) {
177         auto address_samples = module->add_address_samples();
178         address_samples->set_count(callchain_count.second);
179         for (const auto &d_o : *callchain_count.first) {
180           int32 module_id = name_id_map[d_o.dso_name()];
181           address_samples->add_load_module_id(module_id);
182           address_samples->add_address(d_o.offset());
183         }
184       }
185     }
186   }
187   return ret;
188 }
189
190 }  // namespace wireless_android_logging_awp