callchain.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873
  1. /*
  2. * Copyright (C) 2009-2011, Frederic Weisbecker <fweisbec@gmail.com>
  3. *
  4. * Handle the callchains from the stream in an ad-hoc radix tree and then
  5. * sort them in an rbtree.
  6. *
  7. * Using a radix for code path provides a fast retrieval and factorizes
  8. * memory use. Also that lets us use the paths in a hierarchical graph view.
  9. *
  10. */
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <stdbool.h>
  14. #include <errno.h>
  15. #include <math.h>
  16. #include "asm/bug.h"
  17. #include "hist.h"
  18. #include "util.h"
  19. #include "sort.h"
  20. #include "machine.h"
  21. #include "callchain.h"
  22. __thread struct callchain_cursor callchain_cursor;
  23. #ifdef HAVE_DWARF_UNWIND_SUPPORT
  24. static int get_stack_size(const char *str, unsigned long *_size)
  25. {
  26. char *endptr;
  27. unsigned long size;
  28. unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
  29. size = strtoul(str, &endptr, 0);
  30. do {
  31. if (*endptr)
  32. break;
  33. size = round_up(size, sizeof(u64));
  34. if (!size || size > max_size)
  35. break;
  36. *_size = size;
  37. return 0;
  38. } while (0);
  39. pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
  40. max_size, str);
  41. return -1;
  42. }
  43. #endif /* HAVE_DWARF_UNWIND_SUPPORT */
  44. int parse_callchain_record_opt(const char *arg)
  45. {
  46. char *tok, *name, *saveptr = NULL;
  47. char *buf;
  48. int ret = -1;
  49. /* We need buffer that we know we can write to. */
  50. buf = malloc(strlen(arg) + 1);
  51. if (!buf)
  52. return -ENOMEM;
  53. strcpy(buf, arg);
  54. tok = strtok_r((char *)buf, ",", &saveptr);
  55. name = tok ? : (char *)buf;
  56. do {
  57. /* Framepointer style */
  58. if (!strncmp(name, "fp", sizeof("fp"))) {
  59. if (!strtok_r(NULL, ",", &saveptr)) {
  60. callchain_param.record_mode = CALLCHAIN_FP;
  61. ret = 0;
  62. } else
  63. pr_err("callchain: No more arguments "
  64. "needed for --call-graph fp\n");
  65. break;
  66. #ifdef HAVE_DWARF_UNWIND_SUPPORT
  67. /* Dwarf style */
  68. } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
  69. const unsigned long default_stack_dump_size = 8192;
  70. ret = 0;
  71. callchain_param.record_mode = CALLCHAIN_DWARF;
  72. callchain_param.dump_size = default_stack_dump_size;
  73. tok = strtok_r(NULL, ",", &saveptr);
  74. if (tok) {
  75. unsigned long size = 0;
  76. ret = get_stack_size(tok, &size);
  77. callchain_param.dump_size = size;
  78. }
  79. #endif /* HAVE_DWARF_UNWIND_SUPPORT */
  80. } else {
  81. pr_err("callchain: Unknown --call-graph option "
  82. "value: %s\n", arg);
  83. break;
  84. }
  85. } while (0);
  86. free(buf);
  87. return ret;
  88. }
  89. static int parse_callchain_mode(const char *value)
  90. {
  91. if (!strncmp(value, "graph", strlen(value))) {
  92. callchain_param.mode = CHAIN_GRAPH_ABS;
  93. return 0;
  94. }
  95. if (!strncmp(value, "flat", strlen(value))) {
  96. callchain_param.mode = CHAIN_FLAT;
  97. return 0;
  98. }
  99. if (!strncmp(value, "fractal", strlen(value))) {
  100. callchain_param.mode = CHAIN_GRAPH_REL;
  101. return 0;
  102. }
  103. return -1;
  104. }
  105. static int parse_callchain_order(const char *value)
  106. {
  107. if (!strncmp(value, "caller", strlen(value))) {
  108. callchain_param.order = ORDER_CALLER;
  109. return 0;
  110. }
  111. if (!strncmp(value, "callee", strlen(value))) {
  112. callchain_param.order = ORDER_CALLEE;
  113. return 0;
  114. }
  115. return -1;
  116. }
  117. static int parse_callchain_sort_key(const char *value)
  118. {
  119. if (!strncmp(value, "function", strlen(value))) {
  120. callchain_param.key = CCKEY_FUNCTION;
  121. return 0;
  122. }
  123. if (!strncmp(value, "address", strlen(value))) {
  124. callchain_param.key = CCKEY_ADDRESS;
  125. return 0;
  126. }
  127. if (!strncmp(value, "branch", strlen(value))) {
  128. callchain_param.branch_callstack = 1;
  129. return 0;
  130. }
  131. return -1;
  132. }
  133. int
  134. parse_callchain_report_opt(const char *arg)
  135. {
  136. char *tok;
  137. char *endptr;
  138. bool minpcnt_set = false;
  139. symbol_conf.use_callchain = true;
  140. if (!arg)
  141. return 0;
  142. while ((tok = strtok((char *)arg, ",")) != NULL) {
  143. if (!strncmp(tok, "none", strlen(tok))) {
  144. callchain_param.mode = CHAIN_NONE;
  145. symbol_conf.use_callchain = false;
  146. return 0;
  147. }
  148. if (!parse_callchain_mode(tok) ||
  149. !parse_callchain_order(tok) ||
  150. !parse_callchain_sort_key(tok)) {
  151. /* parsing ok - move on to the next */
  152. } else if (!minpcnt_set) {
  153. /* try to get the min percent */
  154. callchain_param.min_percent = strtod(tok, &endptr);
  155. if (tok == endptr)
  156. return -1;
  157. minpcnt_set = true;
  158. } else {
  159. /* try print limit at last */
  160. callchain_param.print_limit = strtoul(tok, &endptr, 0);
  161. if (tok == endptr)
  162. return -1;
  163. }
  164. arg = NULL;
  165. }
  166. if (callchain_register_param(&callchain_param) < 0) {
  167. pr_err("Can't register callchain params\n");
  168. return -1;
  169. }
  170. return 0;
  171. }
  172. int perf_callchain_config(const char *var, const char *value)
  173. {
  174. char *endptr;
  175. if (prefixcmp(var, "call-graph."))
  176. return 0;
  177. var += sizeof("call-graph.") - 1;
  178. if (!strcmp(var, "record-mode"))
  179. return parse_callchain_record_opt(value);
  180. #ifdef HAVE_DWARF_UNWIND_SUPPORT
  181. if (!strcmp(var, "dump-size")) {
  182. unsigned long size = 0;
  183. int ret;
  184. ret = get_stack_size(value, &size);
  185. callchain_param.dump_size = size;
  186. return ret;
  187. }
  188. #endif
  189. if (!strcmp(var, "print-type"))
  190. return parse_callchain_mode(value);
  191. if (!strcmp(var, "order"))
  192. return parse_callchain_order(value);
  193. if (!strcmp(var, "sort-key"))
  194. return parse_callchain_sort_key(value);
  195. if (!strcmp(var, "threshold")) {
  196. callchain_param.min_percent = strtod(value, &endptr);
  197. if (value == endptr)
  198. return -1;
  199. }
  200. if (!strcmp(var, "print-limit")) {
  201. callchain_param.print_limit = strtod(value, &endptr);
  202. if (value == endptr)
  203. return -1;
  204. }
  205. return 0;
  206. }
  207. static void
  208. rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
  209. enum chain_mode mode)
  210. {
  211. struct rb_node **p = &root->rb_node;
  212. struct rb_node *parent = NULL;
  213. struct callchain_node *rnode;
  214. u64 chain_cumul = callchain_cumul_hits(chain);
  215. while (*p) {
  216. u64 rnode_cumul;
  217. parent = *p;
  218. rnode = rb_entry(parent, struct callchain_node, rb_node);
  219. rnode_cumul = callchain_cumul_hits(rnode);
  220. switch (mode) {
  221. case CHAIN_FLAT:
  222. if (rnode->hit < chain->hit)
  223. p = &(*p)->rb_left;
  224. else
  225. p = &(*p)->rb_right;
  226. break;
  227. case CHAIN_GRAPH_ABS: /* Falldown */
  228. case CHAIN_GRAPH_REL:
  229. if (rnode_cumul < chain_cumul)
  230. p = &(*p)->rb_left;
  231. else
  232. p = &(*p)->rb_right;
  233. break;
  234. case CHAIN_NONE:
  235. default:
  236. break;
  237. }
  238. }
  239. rb_link_node(&chain->rb_node, parent, p);
  240. rb_insert_color(&chain->rb_node, root);
  241. }
  242. static void
  243. __sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
  244. u64 min_hit)
  245. {
  246. struct rb_node *n;
  247. struct callchain_node *child;
  248. n = rb_first(&node->rb_root_in);
  249. while (n) {
  250. child = rb_entry(n, struct callchain_node, rb_node_in);
  251. n = rb_next(n);
  252. __sort_chain_flat(rb_root, child, min_hit);
  253. }
  254. if (node->hit && node->hit >= min_hit)
  255. rb_insert_callchain(rb_root, node, CHAIN_FLAT);
  256. }
  257. /*
  258. * Once we get every callchains from the stream, we can now
  259. * sort them by hit
  260. */
  261. static void
  262. sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
  263. u64 min_hit, struct callchain_param *param __maybe_unused)
  264. {
  265. __sort_chain_flat(rb_root, &root->node, min_hit);
  266. }
  267. static void __sort_chain_graph_abs(struct callchain_node *node,
  268. u64 min_hit)
  269. {
  270. struct rb_node *n;
  271. struct callchain_node *child;
  272. node->rb_root = RB_ROOT;
  273. n = rb_first(&node->rb_root_in);
  274. while (n) {
  275. child = rb_entry(n, struct callchain_node, rb_node_in);
  276. n = rb_next(n);
  277. __sort_chain_graph_abs(child, min_hit);
  278. if (callchain_cumul_hits(child) >= min_hit)
  279. rb_insert_callchain(&node->rb_root, child,
  280. CHAIN_GRAPH_ABS);
  281. }
  282. }
  283. static void
  284. sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
  285. u64 min_hit, struct callchain_param *param __maybe_unused)
  286. {
  287. __sort_chain_graph_abs(&chain_root->node, min_hit);
  288. rb_root->rb_node = chain_root->node.rb_root.rb_node;
  289. }
  290. static void __sort_chain_graph_rel(struct callchain_node *node,
  291. double min_percent)
  292. {
  293. struct rb_node *n;
  294. struct callchain_node *child;
  295. u64 min_hit;
  296. node->rb_root = RB_ROOT;
  297. min_hit = ceil(node->children_hit * min_percent);
  298. n = rb_first(&node->rb_root_in);
  299. while (n) {
  300. child = rb_entry(n, struct callchain_node, rb_node_in);
  301. n = rb_next(n);
  302. __sort_chain_graph_rel(child, min_percent);
  303. if (callchain_cumul_hits(child) >= min_hit)
  304. rb_insert_callchain(&node->rb_root, child,
  305. CHAIN_GRAPH_REL);
  306. }
  307. }
  308. static void
  309. sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
  310. u64 min_hit __maybe_unused, struct callchain_param *param)
  311. {
  312. __sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
  313. rb_root->rb_node = chain_root->node.rb_root.rb_node;
  314. }
  315. int callchain_register_param(struct callchain_param *param)
  316. {
  317. switch (param->mode) {
  318. case CHAIN_GRAPH_ABS:
  319. param->sort = sort_chain_graph_abs;
  320. break;
  321. case CHAIN_GRAPH_REL:
  322. param->sort = sort_chain_graph_rel;
  323. break;
  324. case CHAIN_FLAT:
  325. param->sort = sort_chain_flat;
  326. break;
  327. case CHAIN_NONE:
  328. default:
  329. return -1;
  330. }
  331. return 0;
  332. }
  333. /*
  334. * Create a child for a parent. If inherit_children, then the new child
  335. * will become the new parent of it's parent children
  336. */
  337. static struct callchain_node *
  338. create_child(struct callchain_node *parent, bool inherit_children)
  339. {
  340. struct callchain_node *new;
  341. new = zalloc(sizeof(*new));
  342. if (!new) {
  343. perror("not enough memory to create child for code path tree");
  344. return NULL;
  345. }
  346. new->parent = parent;
  347. INIT_LIST_HEAD(&new->val);
  348. if (inherit_children) {
  349. struct rb_node *n;
  350. struct callchain_node *child;
  351. new->rb_root_in = parent->rb_root_in;
  352. parent->rb_root_in = RB_ROOT;
  353. n = rb_first(&new->rb_root_in);
  354. while (n) {
  355. child = rb_entry(n, struct callchain_node, rb_node_in);
  356. child->parent = new;
  357. n = rb_next(n);
  358. }
  359. /* make it the first child */
  360. rb_link_node(&new->rb_node_in, NULL, &parent->rb_root_in.rb_node);
  361. rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
  362. }
  363. return new;
  364. }
  365. /*
  366. * Fill the node with callchain values
  367. */
  368. static void
  369. fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
  370. {
  371. struct callchain_cursor_node *cursor_node;
  372. node->val_nr = cursor->nr - cursor->pos;
  373. if (!node->val_nr)
  374. pr_warning("Warning: empty node in callchain tree\n");
  375. cursor_node = callchain_cursor_current(cursor);
  376. while (cursor_node) {
  377. struct callchain_list *call;
  378. call = zalloc(sizeof(*call));
  379. if (!call) {
  380. perror("not enough memory for the code path tree");
  381. return;
  382. }
  383. call->ip = cursor_node->ip;
  384. call->ms.sym = cursor_node->sym;
  385. call->ms.map = cursor_node->map;
  386. list_add_tail(&call->list, &node->val);
  387. callchain_cursor_advance(cursor);
  388. cursor_node = callchain_cursor_current(cursor);
  389. }
  390. }
  391. static struct callchain_node *
  392. add_child(struct callchain_node *parent,
  393. struct callchain_cursor *cursor,
  394. u64 period)
  395. {
  396. struct callchain_node *new;
  397. new = create_child(parent, false);
  398. fill_node(new, cursor);
  399. new->children_hit = 0;
  400. new->hit = period;
  401. return new;
  402. }
  403. static s64 match_chain(struct callchain_cursor_node *node,
  404. struct callchain_list *cnode)
  405. {
  406. struct symbol *sym = node->sym;
  407. if (cnode->ms.sym && sym &&
  408. callchain_param.key == CCKEY_FUNCTION)
  409. return cnode->ms.sym->start - sym->start;
  410. else
  411. return cnode->ip - node->ip;
  412. }
  413. /*
  414. * Split the parent in two parts (a new child is created) and
  415. * give a part of its callchain to the created child.
  416. * Then create another child to host the given callchain of new branch
  417. */
  418. static void
  419. split_add_child(struct callchain_node *parent,
  420. struct callchain_cursor *cursor,
  421. struct callchain_list *to_split,
  422. u64 idx_parents, u64 idx_local, u64 period)
  423. {
  424. struct callchain_node *new;
  425. struct list_head *old_tail;
  426. unsigned int idx_total = idx_parents + idx_local;
  427. /* split */
  428. new = create_child(parent, true);
  429. /* split the callchain and move a part to the new child */
  430. old_tail = parent->val.prev;
  431. list_del_range(&to_split->list, old_tail);
  432. new->val.next = &to_split->list;
  433. new->val.prev = old_tail;
  434. to_split->list.prev = &new->val;
  435. old_tail->next = &new->val;
  436. /* split the hits */
  437. new->hit = parent->hit;
  438. new->children_hit = parent->children_hit;
  439. parent->children_hit = callchain_cumul_hits(new);
  440. new->val_nr = parent->val_nr - idx_local;
  441. parent->val_nr = idx_local;
  442. /* create a new child for the new branch if any */
  443. if (idx_total < cursor->nr) {
  444. struct callchain_node *first;
  445. struct callchain_list *cnode;
  446. struct callchain_cursor_node *node;
  447. struct rb_node *p, **pp;
  448. parent->hit = 0;
  449. parent->children_hit += period;
  450. node = callchain_cursor_current(cursor);
  451. new = add_child(parent, cursor, period);
  452. /*
  453. * This is second child since we moved parent's children
  454. * to new (first) child above.
  455. */
  456. p = parent->rb_root_in.rb_node;
  457. first = rb_entry(p, struct callchain_node, rb_node_in);
  458. cnode = list_first_entry(&first->val, struct callchain_list,
  459. list);
  460. if (match_chain(node, cnode) < 0)
  461. pp = &p->rb_left;
  462. else
  463. pp = &p->rb_right;
  464. rb_link_node(&new->rb_node_in, p, pp);
  465. rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
  466. } else {
  467. parent->hit = period;
  468. }
  469. }
  470. static int
  471. append_chain(struct callchain_node *root,
  472. struct callchain_cursor *cursor,
  473. u64 period);
  474. static void
  475. append_chain_children(struct callchain_node *root,
  476. struct callchain_cursor *cursor,
  477. u64 period)
  478. {
  479. struct callchain_node *rnode;
  480. struct callchain_cursor_node *node;
  481. struct rb_node **p = &root->rb_root_in.rb_node;
  482. struct rb_node *parent = NULL;
  483. node = callchain_cursor_current(cursor);
  484. if (!node)
  485. return;
  486. /* lookup in childrens */
  487. while (*p) {
  488. s64 ret;
  489. parent = *p;
  490. rnode = rb_entry(parent, struct callchain_node, rb_node_in);
  491. /* If at least first entry matches, rely to children */
  492. ret = append_chain(rnode, cursor, period);
  493. if (ret == 0)
  494. goto inc_children_hit;
  495. if (ret < 0)
  496. p = &parent->rb_left;
  497. else
  498. p = &parent->rb_right;
  499. }
  500. /* nothing in children, add to the current node */
  501. rnode = add_child(root, cursor, period);
  502. rb_link_node(&rnode->rb_node_in, parent, p);
  503. rb_insert_color(&rnode->rb_node_in, &root->rb_root_in);
  504. inc_children_hit:
  505. root->children_hit += period;
  506. }
  507. static int
  508. append_chain(struct callchain_node *root,
  509. struct callchain_cursor *cursor,
  510. u64 period)
  511. {
  512. struct callchain_list *cnode;
  513. u64 start = cursor->pos;
  514. bool found = false;
  515. u64 matches;
  516. int cmp = 0;
  517. /*
  518. * Lookup in the current node
  519. * If we have a symbol, then compare the start to match
  520. * anywhere inside a function, unless function
  521. * mode is disabled.
  522. */
  523. list_for_each_entry(cnode, &root->val, list) {
  524. struct callchain_cursor_node *node;
  525. node = callchain_cursor_current(cursor);
  526. if (!node)
  527. break;
  528. cmp = match_chain(node, cnode);
  529. if (cmp)
  530. break;
  531. found = true;
  532. callchain_cursor_advance(cursor);
  533. }
  534. /* matches not, relay no the parent */
  535. if (!found) {
  536. WARN_ONCE(!cmp, "Chain comparison error\n");
  537. return cmp;
  538. }
  539. matches = cursor->pos - start;
  540. /* we match only a part of the node. Split it and add the new chain */
  541. if (matches < root->val_nr) {
  542. split_add_child(root, cursor, cnode, start, matches, period);
  543. return 0;
  544. }
  545. /* we match 100% of the path, increment the hit */
  546. if (matches == root->val_nr && cursor->pos == cursor->nr) {
  547. root->hit += period;
  548. return 0;
  549. }
  550. /* We match the node and still have a part remaining */
  551. append_chain_children(root, cursor, period);
  552. return 0;
  553. }
  554. int callchain_append(struct callchain_root *root,
  555. struct callchain_cursor *cursor,
  556. u64 period)
  557. {
  558. if (!cursor->nr)
  559. return 0;
  560. callchain_cursor_commit(cursor);
  561. append_chain_children(&root->node, cursor, period);
  562. if (cursor->nr > root->max_depth)
  563. root->max_depth = cursor->nr;
  564. return 0;
  565. }
  566. static int
  567. merge_chain_branch(struct callchain_cursor *cursor,
  568. struct callchain_node *dst, struct callchain_node *src)
  569. {
  570. struct callchain_cursor_node **old_last = cursor->last;
  571. struct callchain_node *child;
  572. struct callchain_list *list, *next_list;
  573. struct rb_node *n;
  574. int old_pos = cursor->nr;
  575. int err = 0;
  576. list_for_each_entry_safe(list, next_list, &src->val, list) {
  577. callchain_cursor_append(cursor, list->ip,
  578. list->ms.map, list->ms.sym);
  579. list_del(&list->list);
  580. free(list);
  581. }
  582. if (src->hit) {
  583. callchain_cursor_commit(cursor);
  584. append_chain_children(dst, cursor, src->hit);
  585. }
  586. n = rb_first(&src->rb_root_in);
  587. while (n) {
  588. child = container_of(n, struct callchain_node, rb_node_in);
  589. n = rb_next(n);
  590. rb_erase(&child->rb_node_in, &src->rb_root_in);
  591. err = merge_chain_branch(cursor, dst, child);
  592. if (err)
  593. break;
  594. free(child);
  595. }
  596. cursor->nr = old_pos;
  597. cursor->last = old_last;
  598. return err;
  599. }
  600. int callchain_merge(struct callchain_cursor *cursor,
  601. struct callchain_root *dst, struct callchain_root *src)
  602. {
  603. return merge_chain_branch(cursor, &dst->node, &src->node);
  604. }
  605. int callchain_cursor_append(struct callchain_cursor *cursor,
  606. u64 ip, struct map *map, struct symbol *sym)
  607. {
  608. struct callchain_cursor_node *node = *cursor->last;
  609. if (!node) {
  610. node = calloc(1, sizeof(*node));
  611. if (!node)
  612. return -ENOMEM;
  613. *cursor->last = node;
  614. }
  615. node->ip = ip;
  616. node->map = map;
  617. node->sym = sym;
  618. cursor->nr++;
  619. cursor->last = &node->next;
  620. return 0;
  621. }
  622. int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent,
  623. struct perf_evsel *evsel, struct addr_location *al,
  624. int max_stack)
  625. {
  626. if (sample->callchain == NULL)
  627. return 0;
  628. if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
  629. sort__has_parent) {
  630. return thread__resolve_callchain(al->thread, evsel, sample,
  631. parent, al, max_stack);
  632. }
  633. return 0;
  634. }
  635. int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
  636. {
  637. if (!symbol_conf.use_callchain || sample->callchain == NULL)
  638. return 0;
  639. return callchain_append(he->callchain, &callchain_cursor, sample->period);
  640. }
  641. int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
  642. bool hide_unresolved)
  643. {
  644. al->map = node->map;
  645. al->sym = node->sym;
  646. if (node->map)
  647. al->addr = node->map->map_ip(node->map, node->ip);
  648. else
  649. al->addr = node->ip;
  650. if (al->sym == NULL) {
  651. if (hide_unresolved)
  652. return 0;
  653. if (al->map == NULL)
  654. goto out;
  655. }
  656. if (al->map->groups == &al->machine->kmaps) {
  657. if (machine__is_host(al->machine)) {
  658. al->cpumode = PERF_RECORD_MISC_KERNEL;
  659. al->level = 'k';
  660. } else {
  661. al->cpumode = PERF_RECORD_MISC_GUEST_KERNEL;
  662. al->level = 'g';
  663. }
  664. } else {
  665. if (machine__is_host(al->machine)) {
  666. al->cpumode = PERF_RECORD_MISC_USER;
  667. al->level = '.';
  668. } else if (perf_guest) {
  669. al->cpumode = PERF_RECORD_MISC_GUEST_USER;
  670. al->level = 'u';
  671. } else {
  672. al->cpumode = PERF_RECORD_MISC_HYPERVISOR;
  673. al->level = 'H';
  674. }
  675. }
  676. out:
  677. return 1;
  678. }
  679. char *callchain_list__sym_name(struct callchain_list *cl,
  680. char *bf, size_t bfsize, bool show_dso)
  681. {
  682. int printed;
  683. if (cl->ms.sym) {
  684. if (callchain_param.key == CCKEY_ADDRESS &&
  685. cl->ms.map && !cl->srcline)
  686. cl->srcline = get_srcline(cl->ms.map->dso,
  687. map__rip_2objdump(cl->ms.map,
  688. cl->ip),
  689. cl->ms.sym, false);
  690. if (cl->srcline)
  691. printed = scnprintf(bf, bfsize, "%s %s",
  692. cl->ms.sym->name, cl->srcline);
  693. else
  694. printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
  695. } else
  696. printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
  697. if (show_dso)
  698. scnprintf(bf + printed, bfsize - printed, " %s",
  699. cl->ms.map ?
  700. cl->ms.map->dso->short_name :
  701. "unknown");
  702. return bf;
  703. }
  704. static void free_callchain_node(struct callchain_node *node)
  705. {
  706. struct callchain_list *list, *tmp;
  707. struct callchain_node *child;
  708. struct rb_node *n;
  709. list_for_each_entry_safe(list, tmp, &node->val, list) {
  710. list_del(&list->list);
  711. free(list);
  712. }
  713. n = rb_first(&node->rb_root_in);
  714. while (n) {
  715. child = container_of(n, struct callchain_node, rb_node_in);
  716. n = rb_next(n);
  717. rb_erase(&child->rb_node_in, &node->rb_root_in);
  718. free_callchain_node(child);
  719. free(child);
  720. }
  721. }
  722. void free_callchain(struct callchain_root *root)
  723. {
  724. if (!symbol_conf.use_callchain)
  725. return;
  726. free_callchain_node(&root->node);
  727. }