17 #include <sys/ioctl.h>
19 #include <sys/prctl.h>
22 #include <sys/types.h>
25 #include <linux/unistd.h>
26 #include <linux/types.h>
28 #include "../../include/linux/perf_counter.h"
35 static char const *input_name = "output.perf";
38 static unsigned long page_size;
39 static unsigned long mmap_window = 32;
42 struct perf_event_header header;
47 struct perf_event_header header;
52 char filename[PATH_MAX];
55 struct perf_event_header header;
60 typedef union event_union {
61 struct perf_event_header header;
63 struct mmap_event mmap;
64 struct comm_event comm;
77 section(uint64_t stab) : end(stab) { };
79 section(uint64_t start, uint64_t size, uint64_t offset, std::string name) :
80 start(start), end(start + size), offset(offset), name(name)
83 bool operator < (const struct section &s) const {
88 typedef std::set<struct section> sections_t;
98 symbol(uint64_t ip) : start(ip) { }
100 symbol(uint64_t start, uint64_t len, std::string name) :
101 start(start), end(start + len), name(name)
104 bool operator < (const struct symbol &s) const {
105 return start < s.start;
109 typedef std::set<struct symbol> symbols_t;
116 static std::map<std::string, struct dso> dsos;
118 static void load_dso_sections(std::string dso_name)
120 struct dso &dso = dsos[dso_name];
122 std::string cmd = "readelf -DSW " + dso_name;
124 FILE *file = popen(cmd.c_str(), "r");
126 perror("failed to open pipe");
133 while (!feof(file)) {
134 uint64_t addr, off, size;
137 if (getline(&line, &n, file) < 0)
142 if (sscanf(line, " [%*2d] %16s %*14s %Lx %Lx %Lx",
143 name, &addr, &off, &size) == 4) {
145 dso.sections.insert(section(addr, size, addr - off, name));
149 * for reading readelf symbols (-s), however these don't seem
150 * to include nearly everything, so use nm for that.
152 if (sscanf(line, " %*4d %*3d: %Lx %5Lu %*7s %*6s %*7s %3d %s",
153 &start, &size, §ion, sym) == 4) {
155 start -= dso.section_offsets[section];
157 dso.syms.insert(symbol(start, size, std::string(sym)));
164 static void load_dso_symbols(std::string dso_name, std::string args)
166 struct dso &dso = dsos[dso_name];
168 std::string cmd = "nm -nSC " + args + " " + dso_name;
170 FILE *file = popen(cmd.c_str(), "r");
172 perror("failed to open pipe");
179 while (!feof(file)) {
180 uint64_t start, size;
184 if (getline(&line, &n, file) < 0)
190 if (sscanf(line, "%Lx %Lx %c %s", &start, &size, &c, sym) == 4) {
191 sections_t::const_iterator si =
192 dso.sections.upper_bound(section(start));
193 if (si == dso.sections.end()) {
194 printf("symbol in unknown section: %s\n", sym);
200 dso.syms.insert(symbol(start, size, sym));
206 static void load_dso(std::string dso_name)
208 load_dso_sections(dso_name);
209 load_dso_symbols(dso_name, "-D"); /* dynamic symbols */
210 load_dso_symbols(dso_name, ""); /* regular ones */
213 void load_kallsyms(void)
215 struct dso &dso = dsos["[kernel]"];
217 FILE *file = fopen("/proc/kallsyms", "r");
219 perror("failed to open kallsyms");
226 while (!feof(file)) {
231 if (getline(&line, &n, file) < 0)
236 if (sscanf(line, "%Lx %c %s", &start, &c, sym) == 3)
237 dso.syms.insert(symbol(start, 0x1000000, std::string(sym)));
251 map(uint64_t ip) : end(ip) { }
253 map(mmap_event *mmap) {
255 end = mmap->start + mmap->len;
258 dso = std::string(mmap->filename);
260 if (dsos.find(dso) == dsos.end())
264 bool operator < (const struct map &m) const {
269 typedef std::set<struct map> maps_t;
271 static std::map<int, maps_t> maps;
273 static std::map<int, std::string> comms;
275 static std::map<std::string, int> hist;
276 static std::multimap<int, std::string> rev_hist;
278 static std::string resolve_comm(int pid)
282 std::map<int, std::string>::const_iterator ci = comms.find(pid);
283 if (ci != comms.end()) {
288 sprintf(pid_str, ":%d", pid);
295 static std::string resolve_user_symbol(int pid, uint64_t ip)
297 std::string sym = "<unknown>";
299 maps_t &m = maps[pid];
300 maps_t::const_iterator mi = m.upper_bound(map(ip));
304 ip -= mi->start + mi->pgoff;
306 symbols_t &s = dsos[mi->dso].syms;
307 symbols_t::const_iterator si = s.upper_bound(symbol(ip));
309 sym = mi->dso + ": <unknown>";
315 if (si->start <= ip && ip < si->end)
316 sym = mi->dso + ": " + si->name;
318 else if (si->start <= ip)
319 sym = mi->dso + ": ?" + si->name;
325 static std::string resolve_kernel_symbol(uint64_t ip)
327 std::string sym = "<unknown>";
329 symbols_t &s = dsos["[kernel]"].syms;
330 symbols_t::const_iterator si = s.upper_bound(symbol(ip));
336 if (si->start <= ip && ip < si->end)
342 static void display_help(void)
345 "Usage: perf-report [<options>]\n"
346 " -i file --input=<file> # input file\n"
352 static void process_options(int argc, char *argv[])
357 int option_index = 0;
358 /** Options for getopt */
359 static struct option long_options[] = {
360 {"input", required_argument, NULL, 'i'},
363 int c = getopt_long(argc, argv, "+:i:",
364 long_options, &option_index);
369 case 'i': input_name = strdup(optarg); break;
370 default: error = 1; break;
378 int main(int argc, char *argv[])
380 unsigned long offset = 0;
381 unsigned long head = 0;
386 unsigned long total = 0;
388 page_size = getpagesize();
390 process_options(argc, argv);
392 input = open(input_name, O_RDONLY);
394 perror("failed to open file");
398 ret = fstat(input, &stat);
400 perror("failed to stat file");
407 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
408 MAP_SHARED, input, offset);
409 if (buf == MAP_FAILED) {
410 perror("failed to mmap file");
415 event = (event_t *)(buf + head);
417 if (head + event->header.size >= page_size * mmap_window) {
418 unsigned long shift = page_size * (head / page_size);
420 munmap(buf, page_size * mmap_window);
425 head += event->header.size;
427 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) {
428 std::string comm, sym, level;
431 if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
433 sym = resolve_kernel_symbol(event->ip.ip);
434 } else if (event->header.misc & PERF_EVENT_MISC_USER) {
436 sym = resolve_user_symbol(event->ip.pid, event->ip.ip);
440 comm = resolve_comm(event->ip.pid);
442 snprintf(output, sizeof(output), "%16s %s %s",
443 comm.c_str(), level.c_str(), sym.c_str());
448 } else switch (event->header.type) {
449 case PERF_EVENT_MMAP:
450 maps[event->mmap.pid].insert(map(&event->mmap));
453 case PERF_EVENT_COMM:
454 comms[event->comm.pid] = std::string(event->comm.comm);
458 if (offset + head < stat.st_size)
463 std::map<std::string, int>::iterator hi = hist.begin();
465 while (hi != hist.end()) {
466 rev_hist.insert(std::pair<int, std::string>(hi->second, hi->first));
470 std::multimap<int, std::string>::const_iterator ri = rev_hist.begin();
472 while (ri != rev_hist.end()) {
473 printf(" %5.2f %s\n", (100.0 * ri->first)/total, ri->second.c_str());