summaryrefslogtreecommitdiff
path: root/perfprofd/perf_data_converter.cc
blob: 9d997538f3576bb83a484ca326f1dfb157df0121 (plain)
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