hist.c 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093
  1. #include "util.h"
  2. #include "build-id.h"
  3. #include "hist.h"
  4. #include "session.h"
  5. #include "sort.h"
  6. #include <math.h>
  7. enum hist_filter {
  8. HIST_FILTER__DSO,
  9. HIST_FILTER__THREAD,
  10. HIST_FILTER__PARENT,
  11. };
  12. struct callchain_param callchain_param = {
  13. .mode = CHAIN_GRAPH_REL,
  14. .min_percent = 0.5
  15. };
  16. static void hist_entry__add_cpumode_period(struct hist_entry *self,
  17. unsigned int cpumode, u64 period)
  18. {
  19. switch (cpumode) {
  20. case PERF_RECORD_MISC_KERNEL:
  21. self->period_sys += period;
  22. break;
  23. case PERF_RECORD_MISC_USER:
  24. self->period_us += period;
  25. break;
  26. case PERF_RECORD_MISC_GUEST_KERNEL:
  27. self->period_guest_sys += period;
  28. break;
  29. case PERF_RECORD_MISC_GUEST_USER:
  30. self->period_guest_us += period;
  31. break;
  32. default:
  33. break;
  34. }
  35. }
  36. /*
  37. * histogram, sorted on item, collects periods
  38. */
  39. static struct hist_entry *hist_entry__new(struct hist_entry *template)
  40. {
  41. size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_node) : 0;
  42. struct hist_entry *self = malloc(sizeof(*self) + callchain_size);
  43. if (self != NULL) {
  44. *self = *template;
  45. self->nr_events = 1;
  46. if (symbol_conf.use_callchain)
  47. callchain_init(self->callchain);
  48. }
  49. return self;
  50. }
  51. static void hists__inc_nr_entries(struct hists *self, struct hist_entry *entry)
  52. {
  53. if (entry->filtered)
  54. return;
  55. if (entry->ms.sym && self->max_sym_namelen < entry->ms.sym->namelen)
  56. self->max_sym_namelen = entry->ms.sym->namelen;
  57. ++self->nr_entries;
  58. }
  59. static u8 symbol__parent_filter(const struct symbol *parent)
  60. {
  61. if (symbol_conf.exclude_other && parent == NULL)
  62. return 1 << HIST_FILTER__PARENT;
  63. return 0;
  64. }
  65. struct hist_entry *__hists__add_entry(struct hists *self,
  66. struct addr_location *al,
  67. struct symbol *sym_parent, u64 period)
  68. {
  69. struct rb_node **p = &self->entries.rb_node;
  70. struct rb_node *parent = NULL;
  71. struct hist_entry *he;
  72. struct hist_entry entry = {
  73. .thread = al->thread,
  74. .ms = {
  75. .map = al->map,
  76. .sym = al->sym,
  77. },
  78. .cpu = al->cpu,
  79. .ip = al->addr,
  80. .level = al->level,
  81. .period = period,
  82. .parent = sym_parent,
  83. .filtered = symbol__parent_filter(sym_parent),
  84. };
  85. int cmp;
  86. while (*p != NULL) {
  87. parent = *p;
  88. he = rb_entry(parent, struct hist_entry, rb_node);
  89. cmp = hist_entry__cmp(&entry, he);
  90. if (!cmp) {
  91. he->period += period;
  92. ++he->nr_events;
  93. goto out;
  94. }
  95. if (cmp < 0)
  96. p = &(*p)->rb_left;
  97. else
  98. p = &(*p)->rb_right;
  99. }
  100. he = hist_entry__new(&entry);
  101. if (!he)
  102. return NULL;
  103. rb_link_node(&he->rb_node, parent, p);
  104. rb_insert_color(&he->rb_node, &self->entries);
  105. hists__inc_nr_entries(self, he);
  106. out:
  107. hist_entry__add_cpumode_period(he, al->cpumode, period);
  108. return he;
  109. }
  110. int64_t
  111. hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
  112. {
  113. struct sort_entry *se;
  114. int64_t cmp = 0;
  115. list_for_each_entry(se, &hist_entry__sort_list, list) {
  116. cmp = se->se_cmp(left, right);
  117. if (cmp)
  118. break;
  119. }
  120. return cmp;
  121. }
  122. int64_t
  123. hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
  124. {
  125. struct sort_entry *se;
  126. int64_t cmp = 0;
  127. list_for_each_entry(se, &hist_entry__sort_list, list) {
  128. int64_t (*f)(struct hist_entry *, struct hist_entry *);
  129. f = se->se_collapse ?: se->se_cmp;
  130. cmp = f(left, right);
  131. if (cmp)
  132. break;
  133. }
  134. return cmp;
  135. }
  136. void hist_entry__free(struct hist_entry *he)
  137. {
  138. free(he);
  139. }
  140. /*
  141. * collapse the histogram
  142. */
  143. static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
  144. {
  145. struct rb_node **p = &root->rb_node;
  146. struct rb_node *parent = NULL;
  147. struct hist_entry *iter;
  148. int64_t cmp;
  149. while (*p != NULL) {
  150. parent = *p;
  151. iter = rb_entry(parent, struct hist_entry, rb_node);
  152. cmp = hist_entry__collapse(iter, he);
  153. if (!cmp) {
  154. iter->period += he->period;
  155. hist_entry__free(he);
  156. return false;
  157. }
  158. if (cmp < 0)
  159. p = &(*p)->rb_left;
  160. else
  161. p = &(*p)->rb_right;
  162. }
  163. rb_link_node(&he->rb_node, parent, p);
  164. rb_insert_color(&he->rb_node, root);
  165. return true;
  166. }
  167. void hists__collapse_resort(struct hists *self)
  168. {
  169. struct rb_root tmp;
  170. struct rb_node *next;
  171. struct hist_entry *n;
  172. if (!sort__need_collapse)
  173. return;
  174. tmp = RB_ROOT;
  175. next = rb_first(&self->entries);
  176. self->nr_entries = 0;
  177. self->max_sym_namelen = 0;
  178. while (next) {
  179. n = rb_entry(next, struct hist_entry, rb_node);
  180. next = rb_next(&n->rb_node);
  181. rb_erase(&n->rb_node, &self->entries);
  182. if (collapse__insert_entry(&tmp, n))
  183. hists__inc_nr_entries(self, n);
  184. }
  185. self->entries = tmp;
  186. }
  187. /*
  188. * reverse the map, sort on period.
  189. */
  190. static void __hists__insert_output_entry(struct rb_root *entries,
  191. struct hist_entry *he,
  192. u64 min_callchain_hits)
  193. {
  194. struct rb_node **p = &entries->rb_node;
  195. struct rb_node *parent = NULL;
  196. struct hist_entry *iter;
  197. if (symbol_conf.use_callchain)
  198. callchain_param.sort(&he->sorted_chain, he->callchain,
  199. min_callchain_hits, &callchain_param);
  200. while (*p != NULL) {
  201. parent = *p;
  202. iter = rb_entry(parent, struct hist_entry, rb_node);
  203. if (he->period > iter->period)
  204. p = &(*p)->rb_left;
  205. else
  206. p = &(*p)->rb_right;
  207. }
  208. rb_link_node(&he->rb_node, parent, p);
  209. rb_insert_color(&he->rb_node, entries);
  210. }
  211. void hists__output_resort(struct hists *self)
  212. {
  213. struct rb_root tmp;
  214. struct rb_node *next;
  215. struct hist_entry *n;
  216. u64 min_callchain_hits;
  217. min_callchain_hits = self->stats.total_period * (callchain_param.min_percent / 100);
  218. tmp = RB_ROOT;
  219. next = rb_first(&self->entries);
  220. self->nr_entries = 0;
  221. self->max_sym_namelen = 0;
  222. while (next) {
  223. n = rb_entry(next, struct hist_entry, rb_node);
  224. next = rb_next(&n->rb_node);
  225. rb_erase(&n->rb_node, &self->entries);
  226. __hists__insert_output_entry(&tmp, n, min_callchain_hits);
  227. hists__inc_nr_entries(self, n);
  228. }
  229. self->entries = tmp;
  230. }
  231. static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
  232. {
  233. int i;
  234. int ret = fprintf(fp, " ");
  235. for (i = 0; i < left_margin; i++)
  236. ret += fprintf(fp, " ");
  237. return ret;
  238. }
  239. static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
  240. int left_margin)
  241. {
  242. int i;
  243. size_t ret = callchain__fprintf_left_margin(fp, left_margin);
  244. for (i = 0; i < depth; i++)
  245. if (depth_mask & (1 << i))
  246. ret += fprintf(fp, "| ");
  247. else
  248. ret += fprintf(fp, " ");
  249. ret += fprintf(fp, "\n");
  250. return ret;
  251. }
  252. static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
  253. int depth, int depth_mask, int period,
  254. u64 total_samples, int hits,
  255. int left_margin)
  256. {
  257. int i;
  258. size_t ret = 0;
  259. ret += callchain__fprintf_left_margin(fp, left_margin);
  260. for (i = 0; i < depth; i++) {
  261. if (depth_mask & (1 << i))
  262. ret += fprintf(fp, "|");
  263. else
  264. ret += fprintf(fp, " ");
  265. if (!period && i == depth - 1) {
  266. double percent;
  267. percent = hits * 100.0 / total_samples;
  268. ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
  269. } else
  270. ret += fprintf(fp, "%s", " ");
  271. }
  272. if (chain->ms.sym)
  273. ret += fprintf(fp, "%s\n", chain->ms.sym->name);
  274. else
  275. ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
  276. return ret;
  277. }
  278. static struct symbol *rem_sq_bracket;
  279. static struct callchain_list rem_hits;
  280. static void init_rem_hits(void)
  281. {
  282. rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
  283. if (!rem_sq_bracket) {
  284. fprintf(stderr, "Not enough memory to display remaining hits\n");
  285. return;
  286. }
  287. strcpy(rem_sq_bracket->name, "[...]");
  288. rem_hits.ms.sym = rem_sq_bracket;
  289. }
  290. static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
  291. u64 total_samples, int depth,
  292. int depth_mask, int left_margin)
  293. {
  294. struct rb_node *node, *next;
  295. struct callchain_node *child;
  296. struct callchain_list *chain;
  297. int new_depth_mask = depth_mask;
  298. u64 new_total;
  299. u64 remaining;
  300. size_t ret = 0;
  301. int i;
  302. uint entries_printed = 0;
  303. if (callchain_param.mode == CHAIN_GRAPH_REL)
  304. new_total = self->children_hit;
  305. else
  306. new_total = total_samples;
  307. remaining = new_total;
  308. node = rb_first(&self->rb_root);
  309. while (node) {
  310. u64 cumul;
  311. child = rb_entry(node, struct callchain_node, rb_node);
  312. cumul = cumul_hits(child);
  313. remaining -= cumul;
  314. /*
  315. * The depth mask manages the output of pipes that show
  316. * the depth. We don't want to keep the pipes of the current
  317. * level for the last child of this depth.
  318. * Except if we have remaining filtered hits. They will
  319. * supersede the last child
  320. */
  321. next = rb_next(node);
  322. if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
  323. new_depth_mask &= ~(1 << (depth - 1));
  324. /*
  325. * But we keep the older depth mask for the line separator
  326. * to keep the level link until we reach the last child
  327. */
  328. ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
  329. left_margin);
  330. i = 0;
  331. list_for_each_entry(chain, &child->val, list) {
  332. ret += ipchain__fprintf_graph(fp, chain, depth,
  333. new_depth_mask, i++,
  334. new_total,
  335. cumul,
  336. left_margin);
  337. }
  338. ret += __callchain__fprintf_graph(fp, child, new_total,
  339. depth + 1,
  340. new_depth_mask | (1 << depth),
  341. left_margin);
  342. node = next;
  343. if (++entries_printed == callchain_param.print_limit)
  344. break;
  345. }
  346. if (callchain_param.mode == CHAIN_GRAPH_REL &&
  347. remaining && remaining != new_total) {
  348. if (!rem_sq_bracket)
  349. return ret;
  350. new_depth_mask &= ~(1 << (depth - 1));
  351. ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
  352. new_depth_mask, 0, new_total,
  353. remaining, left_margin);
  354. }
  355. return ret;
  356. }
  357. static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
  358. u64 total_samples, int left_margin)
  359. {
  360. struct callchain_list *chain;
  361. bool printed = false;
  362. int i = 0;
  363. int ret = 0;
  364. u32 entries_printed = 0;
  365. list_for_each_entry(chain, &self->val, list) {
  366. if (!i++ && sort__first_dimension == SORT_SYM)
  367. continue;
  368. if (!printed) {
  369. ret += callchain__fprintf_left_margin(fp, left_margin);
  370. ret += fprintf(fp, "|\n");
  371. ret += callchain__fprintf_left_margin(fp, left_margin);
  372. ret += fprintf(fp, "---");
  373. left_margin += 3;
  374. printed = true;
  375. } else
  376. ret += callchain__fprintf_left_margin(fp, left_margin);
  377. if (chain->ms.sym)
  378. ret += fprintf(fp, " %s\n", chain->ms.sym->name);
  379. else
  380. ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
  381. if (++entries_printed == callchain_param.print_limit)
  382. break;
  383. }
  384. ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
  385. return ret;
  386. }
  387. static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
  388. u64 total_samples)
  389. {
  390. struct callchain_list *chain;
  391. size_t ret = 0;
  392. if (!self)
  393. return 0;
  394. ret += callchain__fprintf_flat(fp, self->parent, total_samples);
  395. list_for_each_entry(chain, &self->val, list) {
  396. if (chain->ip >= PERF_CONTEXT_MAX)
  397. continue;
  398. if (chain->ms.sym)
  399. ret += fprintf(fp, " %s\n", chain->ms.sym->name);
  400. else
  401. ret += fprintf(fp, " %p\n",
  402. (void *)(long)chain->ip);
  403. }
  404. return ret;
  405. }
  406. static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
  407. u64 total_samples, int left_margin)
  408. {
  409. struct rb_node *rb_node;
  410. struct callchain_node *chain;
  411. size_t ret = 0;
  412. u32 entries_printed = 0;
  413. rb_node = rb_first(&self->sorted_chain);
  414. while (rb_node) {
  415. double percent;
  416. chain = rb_entry(rb_node, struct callchain_node, rb_node);
  417. percent = chain->hit * 100.0 / total_samples;
  418. switch (callchain_param.mode) {
  419. case CHAIN_FLAT:
  420. ret += percent_color_fprintf(fp, " %6.2f%%\n",
  421. percent);
  422. ret += callchain__fprintf_flat(fp, chain, total_samples);
  423. break;
  424. case CHAIN_GRAPH_ABS: /* Falldown */
  425. case CHAIN_GRAPH_REL:
  426. ret += callchain__fprintf_graph(fp, chain, total_samples,
  427. left_margin);
  428. case CHAIN_NONE:
  429. default:
  430. break;
  431. }
  432. ret += fprintf(fp, "\n");
  433. if (++entries_printed == callchain_param.print_limit)
  434. break;
  435. rb_node = rb_next(rb_node);
  436. }
  437. return ret;
  438. }
  439. int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
  440. struct hists *pair_hists, bool show_displacement,
  441. long displacement, bool color, u64 session_total)
  442. {
  443. struct sort_entry *se;
  444. u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
  445. const char *sep = symbol_conf.field_sep;
  446. int ret;
  447. if (symbol_conf.exclude_other && !self->parent)
  448. return 0;
  449. if (pair_hists) {
  450. period = self->pair ? self->pair->period : 0;
  451. total = pair_hists->stats.total_period;
  452. period_sys = self->pair ? self->pair->period_sys : 0;
  453. period_us = self->pair ? self->pair->period_us : 0;
  454. period_guest_sys = self->pair ? self->pair->period_guest_sys : 0;
  455. period_guest_us = self->pair ? self->pair->period_guest_us : 0;
  456. } else {
  457. period = self->period;
  458. total = session_total;
  459. period_sys = self->period_sys;
  460. period_us = self->period_us;
  461. period_guest_sys = self->period_guest_sys;
  462. period_guest_us = self->period_guest_us;
  463. }
  464. if (total) {
  465. if (color)
  466. ret = percent_color_snprintf(s, size,
  467. sep ? "%.2f" : " %6.2f%%",
  468. (period * 100.0) / total);
  469. else
  470. ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%",
  471. (period * 100.0) / total);
  472. if (symbol_conf.show_cpu_utilization) {
  473. ret += percent_color_snprintf(s + ret, size - ret,
  474. sep ? "%.2f" : " %6.2f%%",
  475. (period_sys * 100.0) / total);
  476. ret += percent_color_snprintf(s + ret, size - ret,
  477. sep ? "%.2f" : " %6.2f%%",
  478. (period_us * 100.0) / total);
  479. if (perf_guest) {
  480. ret += percent_color_snprintf(s + ret,
  481. size - ret,
  482. sep ? "%.2f" : " %6.2f%%",
  483. (period_guest_sys * 100.0) /
  484. total);
  485. ret += percent_color_snprintf(s + ret,
  486. size - ret,
  487. sep ? "%.2f" : " %6.2f%%",
  488. (period_guest_us * 100.0) /
  489. total);
  490. }
  491. }
  492. } else
  493. ret = snprintf(s, size, sep ? "%lld" : "%12lld ", period);
  494. if (symbol_conf.show_nr_samples) {
  495. if (sep)
  496. ret += snprintf(s + ret, size - ret, "%c%lld", *sep, period);
  497. else
  498. ret += snprintf(s + ret, size - ret, "%11lld", period);
  499. }
  500. if (pair_hists) {
  501. char bf[32];
  502. double old_percent = 0, new_percent = 0, diff;
  503. if (total > 0)
  504. old_percent = (period * 100.0) / total;
  505. if (session_total > 0)
  506. new_percent = (self->period * 100.0) / session_total;
  507. diff = new_percent - old_percent;
  508. if (fabs(diff) >= 0.01)
  509. snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
  510. else
  511. snprintf(bf, sizeof(bf), " ");
  512. if (sep)
  513. ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
  514. else
  515. ret += snprintf(s + ret, size - ret, "%11.11s", bf);
  516. if (show_displacement) {
  517. if (displacement)
  518. snprintf(bf, sizeof(bf), "%+4ld", displacement);
  519. else
  520. snprintf(bf, sizeof(bf), " ");
  521. if (sep)
  522. ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
  523. else
  524. ret += snprintf(s + ret, size - ret, "%6.6s", bf);
  525. }
  526. }
  527. list_for_each_entry(se, &hist_entry__sort_list, list) {
  528. if (se->elide)
  529. continue;
  530. ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
  531. ret += se->se_snprintf(self, s + ret, size - ret,
  532. se->se_width ? *se->se_width : 0);
  533. }
  534. return ret;
  535. }
  536. int hist_entry__fprintf(struct hist_entry *self, struct hists *pair_hists,
  537. bool show_displacement, long displacement, FILE *fp,
  538. u64 session_total)
  539. {
  540. char bf[512];
  541. hist_entry__snprintf(self, bf, sizeof(bf), pair_hists,
  542. show_displacement, displacement,
  543. true, session_total);
  544. return fprintf(fp, "%s\n", bf);
  545. }
  546. static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp,
  547. u64 session_total)
  548. {
  549. int left_margin = 0;
  550. if (sort__first_dimension == SORT_COMM) {
  551. struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
  552. typeof(*se), list);
  553. left_margin = se->se_width ? *se->se_width : 0;
  554. left_margin -= thread__comm_len(self->thread);
  555. }
  556. return hist_entry_callchain__fprintf(fp, self, session_total,
  557. left_margin);
  558. }
  559. size_t hists__fprintf(struct hists *self, struct hists *pair,
  560. bool show_displacement, FILE *fp)
  561. {
  562. struct sort_entry *se;
  563. struct rb_node *nd;
  564. size_t ret = 0;
  565. unsigned long position = 1;
  566. long displacement = 0;
  567. unsigned int width;
  568. const char *sep = symbol_conf.field_sep;
  569. const char *col_width = symbol_conf.col_width_list_str;
  570. init_rem_hits();
  571. fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
  572. if (symbol_conf.show_nr_samples) {
  573. if (sep)
  574. fprintf(fp, "%cSamples", *sep);
  575. else
  576. fputs(" Samples ", fp);
  577. }
  578. if (symbol_conf.show_cpu_utilization) {
  579. if (sep) {
  580. ret += fprintf(fp, "%csys", *sep);
  581. ret += fprintf(fp, "%cus", *sep);
  582. if (perf_guest) {
  583. ret += fprintf(fp, "%cguest sys", *sep);
  584. ret += fprintf(fp, "%cguest us", *sep);
  585. }
  586. } else {
  587. ret += fprintf(fp, " sys ");
  588. ret += fprintf(fp, " us ");
  589. if (perf_guest) {
  590. ret += fprintf(fp, " guest sys ");
  591. ret += fprintf(fp, " guest us ");
  592. }
  593. }
  594. }
  595. if (pair) {
  596. if (sep)
  597. ret += fprintf(fp, "%cDelta", *sep);
  598. else
  599. ret += fprintf(fp, " Delta ");
  600. if (show_displacement) {
  601. if (sep)
  602. ret += fprintf(fp, "%cDisplacement", *sep);
  603. else
  604. ret += fprintf(fp, " Displ");
  605. }
  606. }
  607. list_for_each_entry(se, &hist_entry__sort_list, list) {
  608. if (se->elide)
  609. continue;
  610. if (sep) {
  611. fprintf(fp, "%c%s", *sep, se->se_header);
  612. continue;
  613. }
  614. width = strlen(se->se_header);
  615. if (se->se_width) {
  616. if (symbol_conf.col_width_list_str) {
  617. if (col_width) {
  618. *se->se_width = atoi(col_width);
  619. col_width = strchr(col_width, ',');
  620. if (col_width)
  621. ++col_width;
  622. }
  623. }
  624. width = *se->se_width = max(*se->se_width, width);
  625. }
  626. fprintf(fp, " %*s", width, se->se_header);
  627. }
  628. fprintf(fp, "\n");
  629. if (sep)
  630. goto print_entries;
  631. fprintf(fp, "# ........");
  632. if (symbol_conf.show_nr_samples)
  633. fprintf(fp, " ..........");
  634. if (pair) {
  635. fprintf(fp, " ..........");
  636. if (show_displacement)
  637. fprintf(fp, " .....");
  638. }
  639. list_for_each_entry(se, &hist_entry__sort_list, list) {
  640. unsigned int i;
  641. if (se->elide)
  642. continue;
  643. fprintf(fp, " ");
  644. if (se->se_width)
  645. width = *se->se_width;
  646. else
  647. width = strlen(se->se_header);
  648. for (i = 0; i < width; i++)
  649. fprintf(fp, ".");
  650. }
  651. fprintf(fp, "\n#\n");
  652. print_entries:
  653. for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
  654. struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
  655. if (show_displacement) {
  656. if (h->pair != NULL)
  657. displacement = ((long)h->pair->position -
  658. (long)position);
  659. else
  660. displacement = 0;
  661. ++position;
  662. }
  663. ret += hist_entry__fprintf(h, pair, show_displacement,
  664. displacement, fp, self->stats.total_period);
  665. if (symbol_conf.use_callchain)
  666. ret += hist_entry__fprintf_callchain(h, fp, self->stats.total_period);
  667. if (h->ms.map == NULL && verbose > 1) {
  668. __map_groups__fprintf_maps(&h->thread->mg,
  669. MAP__FUNCTION, verbose, fp);
  670. fprintf(fp, "%.10s end\n", graph_dotted_line);
  671. }
  672. }
  673. free(rem_sq_bracket);
  674. return ret;
  675. }
  676. static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h,
  677. enum hist_filter filter)
  678. {
  679. h->filtered &= ~(1 << filter);
  680. if (h->filtered)
  681. return;
  682. ++self->nr_entries;
  683. self->stats.total_period += h->period;
  684. self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
  685. if (h->ms.sym && self->max_sym_namelen < h->ms.sym->namelen)
  686. self->max_sym_namelen = h->ms.sym->namelen;
  687. }
  688. void hists__filter_by_dso(struct hists *self, const struct dso *dso)
  689. {
  690. struct rb_node *nd;
  691. self->nr_entries = self->stats.total_period = 0;
  692. self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
  693. self->max_sym_namelen = 0;
  694. for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
  695. struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
  696. if (symbol_conf.exclude_other && !h->parent)
  697. continue;
  698. if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) {
  699. h->filtered |= (1 << HIST_FILTER__DSO);
  700. continue;
  701. }
  702. hists__remove_entry_filter(self, h, HIST_FILTER__DSO);
  703. }
  704. }
  705. void hists__filter_by_thread(struct hists *self, const struct thread *thread)
  706. {
  707. struct rb_node *nd;
  708. self->nr_entries = self->stats.total_period = 0;
  709. self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
  710. self->max_sym_namelen = 0;
  711. for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
  712. struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
  713. if (thread != NULL && h->thread != thread) {
  714. h->filtered |= (1 << HIST_FILTER__THREAD);
  715. continue;
  716. }
  717. hists__remove_entry_filter(self, h, HIST_FILTER__THREAD);
  718. }
  719. }
  720. static int symbol__alloc_hist(struct symbol *self)
  721. {
  722. struct sym_priv *priv = symbol__priv(self);
  723. const int size = (sizeof(*priv->hist) +
  724. (self->end - self->start) * sizeof(u64));
  725. priv->hist = zalloc(size);
  726. return priv->hist == NULL ? -1 : 0;
  727. }
  728. int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
  729. {
  730. unsigned int sym_size, offset;
  731. struct symbol *sym = self->ms.sym;
  732. struct sym_priv *priv;
  733. struct sym_hist *h;
  734. if (!sym || !self->ms.map)
  735. return 0;
  736. priv = symbol__priv(sym);
  737. if (priv->hist == NULL && symbol__alloc_hist(sym) < 0)
  738. return -ENOMEM;
  739. sym_size = sym->end - sym->start;
  740. offset = ip - sym->start;
  741. pr_debug3("%s: ip=%#Lx\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
  742. if (offset >= sym_size)
  743. return 0;
  744. h = priv->hist;
  745. h->sum++;
  746. h->ip[offset]++;
  747. pr_debug3("%#Lx %s: period++ [ip: %#Lx, %#Lx] => %Ld\n", self->ms.sym->start,
  748. self->ms.sym->name, ip, ip - self->ms.sym->start, h->ip[offset]);
  749. return 0;
  750. }
  751. static struct objdump_line *objdump_line__new(s64 offset, char *line)
  752. {
  753. struct objdump_line *self = malloc(sizeof(*self));
  754. if (self != NULL) {
  755. self->offset = offset;
  756. self->line = line;
  757. }
  758. return self;
  759. }
  760. void objdump_line__free(struct objdump_line *self)
  761. {
  762. free(self->line);
  763. free(self);
  764. }
  765. static void objdump__add_line(struct list_head *head, struct objdump_line *line)
  766. {
  767. list_add_tail(&line->node, head);
  768. }
  769. struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
  770. struct objdump_line *pos)
  771. {
  772. list_for_each_entry_continue(pos, head, node)
  773. if (pos->offset >= 0)
  774. return pos;
  775. return NULL;
  776. }
  777. static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
  778. struct list_head *head)
  779. {
  780. struct symbol *sym = self->ms.sym;
  781. struct objdump_line *objdump_line;
  782. char *line = NULL, *tmp, *tmp2, *c;
  783. size_t line_len;
  784. s64 line_ip, offset = -1;
  785. if (getline(&line, &line_len, file) < 0)
  786. return -1;
  787. if (!line)
  788. return -1;
  789. while (line_len != 0 && isspace(line[line_len - 1]))
  790. line[--line_len] = '\0';
  791. c = strchr(line, '\n');
  792. if (c)
  793. *c = 0;
  794. line_ip = -1;
  795. /*
  796. * Strip leading spaces:
  797. */
  798. tmp = line;
  799. while (*tmp) {
  800. if (*tmp != ' ')
  801. break;
  802. tmp++;
  803. }
  804. if (*tmp) {
  805. /*
  806. * Parse hexa addresses followed by ':'
  807. */
  808. line_ip = strtoull(tmp, &tmp2, 16);
  809. if (*tmp2 != ':' || tmp == tmp2)
  810. line_ip = -1;
  811. }
  812. if (line_ip != -1) {
  813. u64 start = map__rip_2objdump(self->ms.map, sym->start);
  814. offset = line_ip - start;
  815. }
  816. objdump_line = objdump_line__new(offset, line);
  817. if (objdump_line == NULL) {
  818. free(line);
  819. return -1;
  820. }
  821. objdump__add_line(head, objdump_line);
  822. return 0;
  823. }
  824. int hist_entry__annotate(struct hist_entry *self, struct list_head *head)
  825. {
  826. struct symbol *sym = self->ms.sym;
  827. struct map *map = self->ms.map;
  828. struct dso *dso = map->dso;
  829. char *filename = dso__build_id_filename(dso, NULL, 0);
  830. bool free_filename = true;
  831. char command[PATH_MAX * 2];
  832. FILE *file;
  833. int err = 0;
  834. u64 len;
  835. if (filename == NULL) {
  836. if (dso->has_build_id) {
  837. pr_err("Can't annotate %s: not enough memory\n",
  838. sym->name);
  839. return -ENOMEM;
  840. }
  841. goto fallback;
  842. } else if (readlink(filename, command, sizeof(command)) < 0 ||
  843. strstr(command, "[kernel.kallsyms]") ||
  844. access(filename, R_OK)) {
  845. free(filename);
  846. fallback:
  847. /*
  848. * If we don't have build-ids or the build-id file isn't in the
  849. * cache, or is just a kallsyms file, well, lets hope that this
  850. * DSO is the same as when 'perf record' ran.
  851. */
  852. filename = dso->long_name;
  853. free_filename = false;
  854. }
  855. if (dso->origin == DSO__ORIG_KERNEL) {
  856. if (dso->annotate_warned)
  857. goto out_free_filename;
  858. err = -ENOENT;
  859. dso->annotate_warned = 1;
  860. pr_err("Can't annotate %s: No vmlinux file was found in the "
  861. "path\n", sym->name);
  862. goto out_free_filename;
  863. }
  864. pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
  865. filename, sym->name, map->unmap_ip(map, sym->start),
  866. map->unmap_ip(map, sym->end));
  867. len = sym->end - sym->start;
  868. pr_debug("annotating [%p] %30s : [%p] %30s\n",
  869. dso, dso->long_name, sym, sym->name);
  870. snprintf(command, sizeof(command),
  871. "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
  872. map__rip_2objdump(map, sym->start),
  873. map__rip_2objdump(map, sym->end),
  874. filename, filename);
  875. pr_debug("Executing: %s\n", command);
  876. file = popen(command, "r");
  877. if (!file)
  878. goto out_free_filename;
  879. while (!feof(file))
  880. if (hist_entry__parse_objdump_line(self, file, head) < 0)
  881. break;
  882. pclose(file);
  883. out_free_filename:
  884. if (free_filename)
  885. free(filename);
  886. return err;
  887. }
  888. void hists__inc_nr_events(struct hists *self, u32 type)
  889. {
  890. ++self->stats.nr_events[0];
  891. ++self->stats.nr_events[type];
  892. }
  893. size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
  894. {
  895. int i;
  896. size_t ret = 0;
  897. for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
  898. if (!event__name[i])
  899. continue;
  900. ret += fprintf(fp, "%10s events: %10d\n",
  901. event__name[i], self->stats.nr_events[i]);
  902. }
  903. return ret;
  904. }