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