session.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. #define _FILE_OFFSET_BITS 64
  2. #include <linux/kernel.h>
  3. #include <byteswap.h>
  4. #include <unistd.h>
  5. #include <sys/types.h>
  6. #include "session.h"
  7. #include "sort.h"
  8. #include "util.h"
  9. static int perf_session__open(struct perf_session *self, bool force)
  10. {
  11. struct stat input_stat;
  12. self->fd = open(self->filename, O_RDONLY);
  13. if (self->fd < 0) {
  14. pr_err("failed to open file: %s", self->filename);
  15. if (!strcmp(self->filename, "perf.data"))
  16. pr_err(" (try 'perf record' first)");
  17. pr_err("\n");
  18. return -errno;
  19. }
  20. if (fstat(self->fd, &input_stat) < 0)
  21. goto out_close;
  22. if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
  23. pr_err("file %s not owned by current user or root\n",
  24. self->filename);
  25. goto out_close;
  26. }
  27. if (!input_stat.st_size) {
  28. pr_info("zero-sized file (%s), nothing to do!\n",
  29. self->filename);
  30. goto out_close;
  31. }
  32. if (perf_header__read(&self->header, self->fd) < 0) {
  33. pr_err("incompatible file format");
  34. goto out_close;
  35. }
  36. self->size = input_stat.st_size;
  37. return 0;
  38. out_close:
  39. close(self->fd);
  40. self->fd = -1;
  41. return -1;
  42. }
  43. static inline int perf_session__create_kernel_maps(struct perf_session *self)
  44. {
  45. return map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps);
  46. }
  47. struct perf_session *perf_session__new(const char *filename, int mode, bool force)
  48. {
  49. size_t len = filename ? strlen(filename) + 1 : 0;
  50. struct perf_session *self = zalloc(sizeof(*self) + len);
  51. if (self == NULL)
  52. goto out;
  53. if (perf_header__init(&self->header) < 0)
  54. goto out_free;
  55. memcpy(self->filename, filename, len);
  56. self->threads = RB_ROOT;
  57. self->stats_by_id = RB_ROOT;
  58. self->last_match = NULL;
  59. self->mmap_window = 32;
  60. self->cwd = NULL;
  61. self->cwdlen = 0;
  62. self->unknown_events = 0;
  63. map_groups__init(&self->kmaps);
  64. if (mode == O_RDONLY) {
  65. if (perf_session__open(self, force) < 0)
  66. goto out_delete;
  67. } else if (mode == O_WRONLY) {
  68. /*
  69. * In O_RDONLY mode this will be performed when reading the
  70. * kernel MMAP event, in event__process_mmap().
  71. */
  72. if (perf_session__create_kernel_maps(self) < 0)
  73. goto out_delete;
  74. }
  75. self->sample_type = perf_header__sample_type(&self->header);
  76. out:
  77. return self;
  78. out_free:
  79. free(self);
  80. return NULL;
  81. out_delete:
  82. perf_session__delete(self);
  83. return NULL;
  84. }
  85. void perf_session__delete(struct perf_session *self)
  86. {
  87. perf_header__exit(&self->header);
  88. close(self->fd);
  89. free(self->cwd);
  90. free(self);
  91. }
  92. static bool symbol__match_parent_regex(struct symbol *sym)
  93. {
  94. if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
  95. return 1;
  96. return 0;
  97. }
  98. struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
  99. struct thread *thread,
  100. struct ip_callchain *chain,
  101. struct symbol **parent)
  102. {
  103. u8 cpumode = PERF_RECORD_MISC_USER;
  104. struct map_symbol *syms = NULL;
  105. unsigned int i;
  106. if (symbol_conf.use_callchain) {
  107. syms = calloc(chain->nr, sizeof(*syms));
  108. if (!syms) {
  109. fprintf(stderr, "Can't allocate memory for symbols\n");
  110. exit(-1);
  111. }
  112. }
  113. for (i = 0; i < chain->nr; i++) {
  114. u64 ip = chain->ips[i];
  115. struct addr_location al;
  116. if (ip >= PERF_CONTEXT_MAX) {
  117. switch (ip) {
  118. case PERF_CONTEXT_HV:
  119. cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
  120. case PERF_CONTEXT_KERNEL:
  121. cpumode = PERF_RECORD_MISC_KERNEL; break;
  122. case PERF_CONTEXT_USER:
  123. cpumode = PERF_RECORD_MISC_USER; break;
  124. default:
  125. break;
  126. }
  127. continue;
  128. }
  129. thread__find_addr_location(thread, self, cpumode,
  130. MAP__FUNCTION, ip, &al, NULL);
  131. if (al.sym != NULL) {
  132. if (sort__has_parent && !*parent &&
  133. symbol__match_parent_regex(al.sym))
  134. *parent = al.sym;
  135. if (!symbol_conf.use_callchain)
  136. break;
  137. syms[i].map = al.map;
  138. syms[i].sym = al.sym;
  139. }
  140. }
  141. return syms;
  142. }
  143. static int process_event_stub(event_t *event __used,
  144. struct perf_session *session __used)
  145. {
  146. dump_printf(": unhandled!\n");
  147. return 0;
  148. }
  149. static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
  150. {
  151. if (handler->sample == NULL)
  152. handler->sample = process_event_stub;
  153. if (handler->mmap == NULL)
  154. handler->mmap = process_event_stub;
  155. if (handler->comm == NULL)
  156. handler->comm = process_event_stub;
  157. if (handler->fork == NULL)
  158. handler->fork = process_event_stub;
  159. if (handler->exit == NULL)
  160. handler->exit = process_event_stub;
  161. if (handler->lost == NULL)
  162. handler->lost = process_event_stub;
  163. if (handler->read == NULL)
  164. handler->read = process_event_stub;
  165. if (handler->throttle == NULL)
  166. handler->throttle = process_event_stub;
  167. if (handler->unthrottle == NULL)
  168. handler->unthrottle = process_event_stub;
  169. }
  170. static const char *event__name[] = {
  171. [0] = "TOTAL",
  172. [PERF_RECORD_MMAP] = "MMAP",
  173. [PERF_RECORD_LOST] = "LOST",
  174. [PERF_RECORD_COMM] = "COMM",
  175. [PERF_RECORD_EXIT] = "EXIT",
  176. [PERF_RECORD_THROTTLE] = "THROTTLE",
  177. [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
  178. [PERF_RECORD_FORK] = "FORK",
  179. [PERF_RECORD_READ] = "READ",
  180. [PERF_RECORD_SAMPLE] = "SAMPLE",
  181. };
  182. unsigned long event__total[PERF_RECORD_MAX];
  183. void event__print_totals(void)
  184. {
  185. int i;
  186. for (i = 0; i < PERF_RECORD_MAX; ++i)
  187. pr_info("%10s events: %10ld\n",
  188. event__name[i], event__total[i]);
  189. }
  190. void mem_bswap_64(void *src, int byte_size)
  191. {
  192. u64 *m = src;
  193. while (byte_size > 0) {
  194. *m = bswap_64(*m);
  195. byte_size -= sizeof(u64);
  196. ++m;
  197. }
  198. }
  199. static void event__all64_swap(event_t *self)
  200. {
  201. struct perf_event_header *hdr = &self->header;
  202. mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr));
  203. }
  204. static void event__comm_swap(event_t *self)
  205. {
  206. self->comm.pid = bswap_32(self->comm.pid);
  207. self->comm.tid = bswap_32(self->comm.tid);
  208. }
  209. static void event__mmap_swap(event_t *self)
  210. {
  211. self->mmap.pid = bswap_32(self->mmap.pid);
  212. self->mmap.tid = bswap_32(self->mmap.tid);
  213. self->mmap.start = bswap_64(self->mmap.start);
  214. self->mmap.len = bswap_64(self->mmap.len);
  215. self->mmap.pgoff = bswap_64(self->mmap.pgoff);
  216. }
  217. static void event__task_swap(event_t *self)
  218. {
  219. self->fork.pid = bswap_32(self->fork.pid);
  220. self->fork.tid = bswap_32(self->fork.tid);
  221. self->fork.ppid = bswap_32(self->fork.ppid);
  222. self->fork.ptid = bswap_32(self->fork.ptid);
  223. self->fork.time = bswap_64(self->fork.time);
  224. }
  225. static void event__read_swap(event_t *self)
  226. {
  227. self->read.pid = bswap_32(self->read.pid);
  228. self->read.tid = bswap_32(self->read.tid);
  229. self->read.value = bswap_64(self->read.value);
  230. self->read.time_enabled = bswap_64(self->read.time_enabled);
  231. self->read.time_running = bswap_64(self->read.time_running);
  232. self->read.id = bswap_64(self->read.id);
  233. }
  234. typedef void (*event__swap_op)(event_t *self);
  235. static event__swap_op event__swap_ops[] = {
  236. [PERF_RECORD_MMAP] = event__mmap_swap,
  237. [PERF_RECORD_COMM] = event__comm_swap,
  238. [PERF_RECORD_FORK] = event__task_swap,
  239. [PERF_RECORD_EXIT] = event__task_swap,
  240. [PERF_RECORD_LOST] = event__all64_swap,
  241. [PERF_RECORD_READ] = event__read_swap,
  242. [PERF_RECORD_SAMPLE] = event__all64_swap,
  243. [PERF_RECORD_MAX] = NULL,
  244. };
  245. static int perf_session__process_event(struct perf_session *self,
  246. event_t *event,
  247. struct perf_event_ops *ops,
  248. u64 offset, u64 head)
  249. {
  250. trace_event(event);
  251. if (event->header.type < PERF_RECORD_MAX) {
  252. dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
  253. offset + head, event->header.size,
  254. event__name[event->header.type]);
  255. ++event__total[0];
  256. ++event__total[event->header.type];
  257. }
  258. if (self->header.needs_swap && event__swap_ops[event->header.type])
  259. event__swap_ops[event->header.type](event);
  260. switch (event->header.type) {
  261. case PERF_RECORD_SAMPLE:
  262. return ops->sample(event, self);
  263. case PERF_RECORD_MMAP:
  264. return ops->mmap(event, self);
  265. case PERF_RECORD_COMM:
  266. return ops->comm(event, self);
  267. case PERF_RECORD_FORK:
  268. return ops->fork(event, self);
  269. case PERF_RECORD_EXIT:
  270. return ops->exit(event, self);
  271. case PERF_RECORD_LOST:
  272. return ops->lost(event, self);
  273. case PERF_RECORD_READ:
  274. return ops->read(event, self);
  275. case PERF_RECORD_THROTTLE:
  276. return ops->throttle(event, self);
  277. case PERF_RECORD_UNTHROTTLE:
  278. return ops->unthrottle(event, self);
  279. default:
  280. self->unknown_events++;
  281. return -1;
  282. }
  283. }
  284. void perf_event_header__bswap(struct perf_event_header *self)
  285. {
  286. self->type = bswap_32(self->type);
  287. self->misc = bswap_16(self->misc);
  288. self->size = bswap_16(self->size);
  289. }
  290. int perf_header__read_build_ids(struct perf_header *self,
  291. int input, u64 offset, u64 size)
  292. {
  293. struct build_id_event bev;
  294. char filename[PATH_MAX];
  295. u64 limit = offset + size;
  296. int err = -1;
  297. while (offset < limit) {
  298. struct dso *dso;
  299. ssize_t len;
  300. struct list_head *head = &dsos__user;
  301. if (read(input, &bev, sizeof(bev)) != sizeof(bev))
  302. goto out;
  303. if (self->needs_swap)
  304. perf_event_header__bswap(&bev.header);
  305. len = bev.header.size - sizeof(bev);
  306. if (read(input, filename, len) != len)
  307. goto out;
  308. if (bev.header.misc & PERF_RECORD_MISC_KERNEL)
  309. head = &dsos__kernel;
  310. dso = __dsos__findnew(head, filename);
  311. if (dso != NULL) {
  312. dso__set_build_id(dso, &bev.build_id);
  313. if (head == &dsos__kernel && filename[0] == '[')
  314. dso->kernel = 1;
  315. }
  316. offset += bev.header.size;
  317. }
  318. err = 0;
  319. out:
  320. return err;
  321. }
  322. static struct thread *perf_session__register_idle_thread(struct perf_session *self)
  323. {
  324. struct thread *thread = perf_session__findnew(self, 0);
  325. if (thread == NULL || thread__set_comm(thread, "swapper")) {
  326. pr_err("problem inserting idle task.\n");
  327. thread = NULL;
  328. }
  329. return thread;
  330. }
  331. int __perf_session__process_events(struct perf_session *self,
  332. u64 data_offset, u64 data_size,
  333. u64 file_size, struct perf_event_ops *ops)
  334. {
  335. int err, mmap_prot, mmap_flags;
  336. u64 head, shift;
  337. u64 offset = 0;
  338. size_t page_size;
  339. event_t *event;
  340. uint32_t size;
  341. char *buf;
  342. perf_event_ops__fill_defaults(ops);
  343. page_size = sysconf(_SC_PAGESIZE);
  344. head = data_offset;
  345. shift = page_size * (head / page_size);
  346. offset += shift;
  347. head -= shift;
  348. mmap_prot = PROT_READ;
  349. mmap_flags = MAP_SHARED;
  350. if (self->header.needs_swap) {
  351. mmap_prot |= PROT_WRITE;
  352. mmap_flags = MAP_PRIVATE;
  353. }
  354. remap:
  355. buf = mmap(NULL, page_size * self->mmap_window, mmap_prot,
  356. mmap_flags, self->fd, offset);
  357. if (buf == MAP_FAILED) {
  358. pr_err("failed to mmap file\n");
  359. err = -errno;
  360. goto out_err;
  361. }
  362. more:
  363. event = (event_t *)(buf + head);
  364. if (self->header.needs_swap)
  365. perf_event_header__bswap(&event->header);
  366. size = event->header.size;
  367. if (size == 0)
  368. size = 8;
  369. if (head + event->header.size >= page_size * self->mmap_window) {
  370. int munmap_ret;
  371. shift = page_size * (head / page_size);
  372. munmap_ret = munmap(buf, page_size * self->mmap_window);
  373. assert(munmap_ret == 0);
  374. offset += shift;
  375. head -= shift;
  376. goto remap;
  377. }
  378. size = event->header.size;
  379. dump_printf("\n%#Lx [%#x]: event: %d\n",
  380. offset + head, event->header.size, event->header.type);
  381. if (size == 0 ||
  382. perf_session__process_event(self, event, ops, offset, head) < 0) {
  383. dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
  384. offset + head, event->header.size,
  385. event->header.type);
  386. /*
  387. * assume we lost track of the stream, check alignment, and
  388. * increment a single u64 in the hope to catch on again 'soon'.
  389. */
  390. if (unlikely(head & 7))
  391. head &= ~7ULL;
  392. size = 8;
  393. }
  394. head += size;
  395. if (offset + head >= data_offset + data_size)
  396. goto done;
  397. if (offset + head < file_size)
  398. goto more;
  399. done:
  400. err = 0;
  401. out_err:
  402. return err;
  403. }
  404. int perf_session__process_events(struct perf_session *self,
  405. struct perf_event_ops *ops)
  406. {
  407. int err;
  408. if (perf_session__register_idle_thread(self) == NULL)
  409. return -ENOMEM;
  410. if (!symbol_conf.full_paths) {
  411. char bf[PATH_MAX];
  412. if (getcwd(bf, sizeof(bf)) == NULL) {
  413. err = -errno;
  414. out_getcwd_err:
  415. pr_err("failed to get the current directory\n");
  416. goto out_err;
  417. }
  418. self->cwd = strdup(bf);
  419. if (self->cwd == NULL) {
  420. err = -ENOMEM;
  421. goto out_getcwd_err;
  422. }
  423. self->cwdlen = strlen(self->cwd);
  424. }
  425. err = __perf_session__process_events(self, self->header.data_offset,
  426. self->header.data_size,
  427. self->size, ops);
  428. out_err:
  429. return err;
  430. }
  431. bool perf_session__has_traces(struct perf_session *self, const char *msg)
  432. {
  433. if (!(self->sample_type & PERF_SAMPLE_RAW)) {
  434. pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
  435. return false;
  436. }
  437. return true;
  438. }
  439. int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
  440. const char *symbol_name,
  441. u64 addr)
  442. {
  443. char *bracket;
  444. enum map_type i;
  445. self->ref_reloc_sym.name = strdup(symbol_name);
  446. if (self->ref_reloc_sym.name == NULL)
  447. return -ENOMEM;
  448. bracket = strchr(self->ref_reloc_sym.name, ']');
  449. if (bracket)
  450. *bracket = '\0';
  451. self->ref_reloc_sym.addr = addr;
  452. for (i = 0; i < MAP__NR_TYPES; ++i) {
  453. struct kmap *kmap = map__kmap(self->vmlinux_maps[i]);
  454. kmap->ref_reloc_sym = &self->ref_reloc_sym;
  455. }
  456. return 0;
  457. }
  458. static u64 map__reloc_map_ip(struct map *map, u64 ip)
  459. {
  460. return ip + (s64)map->pgoff;
  461. }
  462. static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
  463. {
  464. return ip - (s64)map->pgoff;
  465. }
  466. void map__reloc_vmlinux(struct map *self)
  467. {
  468. struct kmap *kmap = map__kmap(self);
  469. s64 reloc;
  470. if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
  471. return;
  472. reloc = (kmap->ref_reloc_sym->unrelocated_addr -
  473. kmap->ref_reloc_sym->addr);
  474. if (!reloc)
  475. return;
  476. self->map_ip = map__reloc_map_ip;
  477. self->unmap_ip = map__reloc_unmap_ip;
  478. self->pgoff = reloc;
  479. }