hist.c 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <errno.h>
  3. #include <inttypes.h>
  4. #include <math.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <linux/compiler.h>
  8. #include "../util/callchain.h"
  9. #include "../util/debug.h"
  10. #include "../util/hist.h"
  11. #include "../util/sort.h"
  12. #include "../util/evsel.h"
  13. #include "../util/evlist.h"
  14. #include "../util/mem-events.h"
  15. #include "../util/string2.h"
  16. #include "../util/thread.h"
  17. #include "../util/util.h"
  18. /* hist period print (hpp) functions */
  19. #define hpp__call_print_fn(hpp, fn, fmt, ...) \
  20. ({ \
  21. int __ret = fn(hpp, fmt, ##__VA_ARGS__); \
  22. advance_hpp(hpp, __ret); \
  23. __ret; \
  24. })
  25. static int __hpp__fmt_print(struct perf_hpp *hpp, struct hists *hists, u64 val,
  26. int nr_samples, const char *fmt, int len,
  27. hpp_snprint_fn print_fn, enum perf_hpp_fmt_type fmtype)
  28. {
  29. if (fmtype == PERF_HPP_FMT_TYPE__PERCENT || fmtype == PERF_HPP_FMT_TYPE__LATENCY) {
  30. double percent = 0.0;
  31. u64 total = fmtype == PERF_HPP_FMT_TYPE__PERCENT ? hists__total_period(hists) :
  32. hists__total_latency(hists);
  33. if (total)
  34. percent = 100.0 * val / total;
  35. return hpp__call_print_fn(hpp, print_fn, fmt, len, percent);
  36. }
  37. if (fmtype == PERF_HPP_FMT_TYPE__AVERAGE) {
  38. double avg = nr_samples ? (1.0 * val / nr_samples) : 0;
  39. return hpp__call_print_fn(hpp, print_fn, fmt, len, avg);
  40. }
  41. return hpp__call_print_fn(hpp, print_fn, fmt, len, val);
  42. }
  43. struct hpp_fmt_value {
  44. struct hists *hists;
  45. u64 val;
  46. int samples;
  47. };
  48. static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
  49. hpp_field_fn get_field, const char *fmt, int len,
  50. hpp_snprint_fn print_fn, enum perf_hpp_fmt_type fmtype)
  51. {
  52. int ret = 0;
  53. struct hists *hists = he->hists;
  54. struct evsel *evsel = hists_to_evsel(hists);
  55. struct evsel *pos;
  56. char *buf = hpp->buf;
  57. size_t size = hpp->size;
  58. int i = 0, nr_members = 1;
  59. struct hpp_fmt_value *values;
  60. if (evsel__is_group_event(evsel))
  61. nr_members = evsel->core.nr_members;
  62. values = calloc(nr_members, sizeof(*values));
  63. if (values == NULL)
  64. return 0;
  65. values[0].hists = evsel__hists(evsel);
  66. values[0].val = get_field(he);
  67. values[0].samples = he->stat.nr_events;
  68. if (evsel__is_group_event(evsel)) {
  69. struct hist_entry *pair;
  70. for_each_group_member(pos, evsel)
  71. values[++i].hists = evsel__hists(pos);
  72. list_for_each_entry(pair, &he->pairs.head, pairs.node) {
  73. for (i = 0; i < nr_members; i++) {
  74. if (values[i].hists != pair->hists)
  75. continue;
  76. values[i].val = get_field(pair);
  77. values[i].samples = pair->stat.nr_events;
  78. break;
  79. }
  80. }
  81. }
  82. for (i = 0; i < nr_members; i++) {
  83. if (symbol_conf.skip_empty &&
  84. values[i].hists->stats.nr_samples == 0)
  85. continue;
  86. ret += __hpp__fmt_print(hpp, values[i].hists, values[i].val,
  87. values[i].samples, fmt, len,
  88. print_fn, fmtype);
  89. }
  90. free(values);
  91. /*
  92. * Restore original buf and size as it's where caller expects
  93. * the result will be saved.
  94. */
  95. hpp->buf = buf;
  96. hpp->size = size;
  97. return ret;
  98. }
  99. int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
  100. struct hist_entry *he, hpp_field_fn get_field,
  101. const char *fmtstr, hpp_snprint_fn print_fn,
  102. enum perf_hpp_fmt_type fmtype)
  103. {
  104. int len = max(fmt->user_len ?: fmt->len, (int)strlen(fmt->name));
  105. if (symbol_conf.field_sep) {
  106. return __hpp__fmt(hpp, he, get_field, fmtstr, 1,
  107. print_fn, fmtype);
  108. }
  109. if (fmtype == PERF_HPP_FMT_TYPE__PERCENT || fmtype == PERF_HPP_FMT_TYPE__LATENCY)
  110. len -= 2; /* 2 for a space and a % sign */
  111. else
  112. len -= 1;
  113. return __hpp__fmt(hpp, he, get_field, fmtstr, len, print_fn, fmtype);
  114. }
  115. int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
  116. struct hist_entry *he, hpp_field_fn get_field,
  117. const char *fmtstr, hpp_snprint_fn print_fn,
  118. enum perf_hpp_fmt_type fmtype)
  119. {
  120. if (!symbol_conf.cumulate_callchain) {
  121. int len = fmt->user_len ?: fmt->len;
  122. return snprintf(hpp->buf, hpp->size, " %*s", len - 1, "N/A");
  123. }
  124. return hpp__fmt(fmt, hpp, he, get_field, fmtstr, print_fn, fmtype);
  125. }
  126. int hpp__fmt_mem_stat(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp,
  127. struct hist_entry *he, enum mem_stat_type mst,
  128. const char *fmtstr, hpp_snprint_fn print_fn)
  129. {
  130. struct hists *hists = he->hists;
  131. int mem_stat_idx = -1;
  132. char *buf = hpp->buf;
  133. size_t size = hpp->size;
  134. u64 total = 0;
  135. int ret = 0;
  136. for (int i = 0; i < hists->nr_mem_stats; i++) {
  137. if (hists->mem_stat_types[i] == mst) {
  138. mem_stat_idx = i;
  139. break;
  140. }
  141. }
  142. assert(mem_stat_idx != -1);
  143. for (int i = 0; i < MEM_STAT_LEN; i++)
  144. total += hists->mem_stat_total[mem_stat_idx].entries[i];
  145. assert(total != 0);
  146. for (int i = 0; i < MEM_STAT_LEN; i++) {
  147. u64 val = he->mem_stat[mem_stat_idx].entries[i];
  148. if (hists->mem_stat_total[mem_stat_idx].entries[i] == 0)
  149. continue;
  150. ret += hpp__call_print_fn(hpp, print_fn, fmtstr, 100.0 * val / total);
  151. }
  152. /*
  153. * Restore original buf and size as it's where caller expects
  154. * the result will be saved.
  155. */
  156. hpp->buf = buf;
  157. hpp->size = size;
  158. return ret;
  159. }
  160. static int field_cmp(u64 field_a, u64 field_b)
  161. {
  162. if (field_a > field_b)
  163. return 1;
  164. if (field_a < field_b)
  165. return -1;
  166. return 0;
  167. }
  168. static int hist_entry__new_pair(struct hist_entry *a, struct hist_entry *b,
  169. hpp_field_fn get_field, int nr_members,
  170. u64 **fields_a, u64 **fields_b)
  171. {
  172. u64 *fa = calloc(nr_members, sizeof(*fa)),
  173. *fb = calloc(nr_members, sizeof(*fb));
  174. struct hist_entry *pair;
  175. if (!fa || !fb)
  176. goto out_free;
  177. list_for_each_entry(pair, &a->pairs.head, pairs.node) {
  178. struct evsel *evsel = hists_to_evsel(pair->hists);
  179. fa[evsel__group_idx(evsel)] = get_field(pair);
  180. }
  181. list_for_each_entry(pair, &b->pairs.head, pairs.node) {
  182. struct evsel *evsel = hists_to_evsel(pair->hists);
  183. fb[evsel__group_idx(evsel)] = get_field(pair);
  184. }
  185. *fields_a = fa;
  186. *fields_b = fb;
  187. return 0;
  188. out_free:
  189. free(fa);
  190. free(fb);
  191. *fields_a = *fields_b = NULL;
  192. return -1;
  193. }
  194. static int __hpp__group_sort_idx(struct hist_entry *a, struct hist_entry *b,
  195. hpp_field_fn get_field, int idx)
  196. {
  197. struct evsel *evsel = hists_to_evsel(a->hists);
  198. u64 *fields_a, *fields_b;
  199. int cmp, nr_members, ret, i;
  200. cmp = field_cmp(get_field(a), get_field(b));
  201. if (!evsel__is_group_event(evsel))
  202. return cmp;
  203. nr_members = evsel->core.nr_members;
  204. if (idx < 1 || idx >= nr_members)
  205. return cmp;
  206. ret = hist_entry__new_pair(a, b, get_field, nr_members, &fields_a, &fields_b);
  207. if (ret) {
  208. ret = cmp;
  209. goto out;
  210. }
  211. ret = field_cmp(fields_a[idx], fields_b[idx]);
  212. if (ret)
  213. goto out;
  214. for (i = 1; i < nr_members; i++) {
  215. if (i != idx) {
  216. ret = field_cmp(fields_a[i], fields_b[i]);
  217. if (ret)
  218. goto out;
  219. }
  220. }
  221. out:
  222. free(fields_a);
  223. free(fields_b);
  224. return ret;
  225. }
  226. static int __hpp__sort(struct hist_entry *a, struct hist_entry *b,
  227. hpp_field_fn get_field)
  228. {
  229. s64 ret;
  230. int i, nr_members;
  231. struct evsel *evsel;
  232. u64 *fields_a, *fields_b;
  233. if (symbol_conf.group_sort_idx && symbol_conf.event_group) {
  234. return __hpp__group_sort_idx(a, b, get_field,
  235. symbol_conf.group_sort_idx);
  236. }
  237. ret = field_cmp(get_field(a), get_field(b));
  238. if (ret || !symbol_conf.event_group)
  239. return ret;
  240. evsel = hists_to_evsel(a->hists);
  241. if (!evsel__is_group_event(evsel))
  242. return ret;
  243. nr_members = evsel->core.nr_members;
  244. i = hist_entry__new_pair(a, b, get_field, nr_members, &fields_a, &fields_b);
  245. if (i)
  246. goto out;
  247. for (i = 1; i < nr_members; i++) {
  248. ret = field_cmp(fields_a[i], fields_b[i]);
  249. if (ret)
  250. break;
  251. }
  252. out:
  253. free(fields_a);
  254. free(fields_b);
  255. return ret;
  256. }
  257. static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b,
  258. hpp_field_fn get_field)
  259. {
  260. s64 ret = 0;
  261. if (symbol_conf.cumulate_callchain) {
  262. /*
  263. * Put caller above callee when they have equal period.
  264. */
  265. ret = field_cmp(get_field(a), get_field(b));
  266. if (ret)
  267. return ret;
  268. if ((a->thread == NULL ? NULL : RC_CHK_ACCESS(a->thread)) !=
  269. (b->thread == NULL ? NULL : RC_CHK_ACCESS(b->thread)) ||
  270. !hist_entry__has_callchains(a) || !symbol_conf.use_callchain)
  271. return 0;
  272. ret = b->callchain->max_depth - a->callchain->max_depth;
  273. if (callchain_param.order == ORDER_CALLER)
  274. ret = -ret;
  275. }
  276. return ret;
  277. }
  278. static bool perf_hpp__is_mem_stat_entry(struct perf_hpp_fmt *fmt);
  279. static enum mem_stat_type hpp__mem_stat_type(struct perf_hpp_fmt *fmt)
  280. {
  281. if (!perf_hpp__is_mem_stat_entry(fmt))
  282. return -1;
  283. switch (fmt->idx) {
  284. case PERF_HPP__MEM_STAT_OP:
  285. return PERF_MEM_STAT_OP;
  286. case PERF_HPP__MEM_STAT_CACHE:
  287. return PERF_MEM_STAT_CACHE;
  288. case PERF_HPP__MEM_STAT_MEMORY:
  289. return PERF_MEM_STAT_MEMORY;
  290. case PERF_HPP__MEM_STAT_SNOOP:
  291. return PERF_MEM_STAT_SNOOP;
  292. case PERF_HPP__MEM_STAT_DTLB:
  293. return PERF_MEM_STAT_DTLB;
  294. default:
  295. break;
  296. }
  297. pr_debug("Should not reach here\n");
  298. return -1;
  299. }
  300. static int64_t hpp__sort_mem_stat(struct perf_hpp_fmt *fmt __maybe_unused,
  301. struct hist_entry *a, struct hist_entry *b)
  302. {
  303. return a->stat.period - b->stat.period;
  304. }
  305. static int hpp__width_fn(struct perf_hpp_fmt *fmt,
  306. struct perf_hpp *hpp __maybe_unused,
  307. struct hists *hists)
  308. {
  309. int len = fmt->user_len ?: fmt->len;
  310. struct evsel *evsel = hists_to_evsel(hists);
  311. if (symbol_conf.event_group) {
  312. int nr = 0;
  313. struct evsel *pos;
  314. for_each_group_evsel(pos, evsel) {
  315. if (!symbol_conf.skip_empty ||
  316. evsel__hists(pos)->stats.nr_samples)
  317. nr++;
  318. }
  319. len = max(len, nr * fmt->len);
  320. }
  321. if (len < (int)strlen(fmt->name))
  322. len = strlen(fmt->name);
  323. return len;
  324. }
  325. static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
  326. struct hists *hists, int line,
  327. int *span __maybe_unused)
  328. {
  329. int len = hpp__width_fn(fmt, hpp, hists);
  330. const char *hdr = "";
  331. if (line == hists->hpp_list->nr_header_lines - 1)
  332. hdr = fmt->name;
  333. return scnprintf(hpp->buf, hpp->size, "%*s", len, hdr);
  334. }
  335. static int hpp__header_mem_stat_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
  336. struct hists *hists, int line,
  337. int *span __maybe_unused)
  338. {
  339. char *buf = hpp->buf;
  340. int ret = 0;
  341. int len;
  342. enum mem_stat_type mst = hpp__mem_stat_type(fmt);
  343. int mem_stat_idx = -1;
  344. for (int i = 0; i < hists->nr_mem_stats; i++) {
  345. if (hists->mem_stat_types[i] == mst) {
  346. mem_stat_idx = i;
  347. break;
  348. }
  349. }
  350. assert(mem_stat_idx != -1);
  351. if (line == 0) {
  352. int left, right;
  353. len = 0;
  354. /* update fmt->len for acutally used columns only */
  355. for (int i = 0; i < MEM_STAT_LEN; i++) {
  356. if (hists->mem_stat_total[mem_stat_idx].entries[i])
  357. len += MEM_STAT_PRINT_LEN;
  358. }
  359. fmt->len = len;
  360. /* print header directly if single column only */
  361. if (len == MEM_STAT_PRINT_LEN)
  362. return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name);
  363. left = (len - strlen(fmt->name)) / 2 - 1;
  364. right = len - left - strlen(fmt->name) - 2;
  365. if (left < 0)
  366. left = 0;
  367. if (right < 0)
  368. right = 0;
  369. return scnprintf(hpp->buf, hpp->size, "%.*s %s %.*s",
  370. left, graph_dotted_line, fmt->name, right, graph_dotted_line);
  371. }
  372. len = hpp->size;
  373. for (int i = 0; i < MEM_STAT_LEN; i++) {
  374. int printed;
  375. if (hists->mem_stat_total[mem_stat_idx].entries[i] == 0)
  376. continue;
  377. printed = scnprintf(buf, len, "%*s", MEM_STAT_PRINT_LEN,
  378. mem_stat_name(mst, i));
  379. ret += printed;
  380. buf += printed;
  381. len -= printed;
  382. }
  383. return ret;
  384. }
  385. int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)
  386. {
  387. va_list args;
  388. ssize_t ssize = hpp->size;
  389. double percent;
  390. int ret, len;
  391. va_start(args, fmt);
  392. len = va_arg(args, int);
  393. percent = va_arg(args, double);
  394. ret = percent_color_len_snprintf(hpp->buf, hpp->size, fmt, len, percent);
  395. va_end(args);
  396. return (ret >= ssize) ? (ssize - 1) : ret;
  397. }
  398. static int hpp_entry_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)
  399. {
  400. va_list args;
  401. ssize_t ssize = hpp->size;
  402. int ret;
  403. va_start(args, fmt);
  404. ret = vsnprintf(hpp->buf, hpp->size, fmt, args);
  405. va_end(args);
  406. return (ret >= ssize) ? (ssize - 1) : ret;
  407. }
  408. #define __HPP_COLOR_PERCENT_FN(_type, _field, _fmttype) \
  409. static u64 he_get_##_field(struct hist_entry *he) \
  410. { \
  411. return he->stat._field; \
  412. } \
  413. \
  414. static int hpp__color_##_type(struct perf_hpp_fmt *fmt, \
  415. struct perf_hpp *hpp, struct hist_entry *he) \
  416. { \
  417. return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \
  418. hpp_color_scnprintf, _fmttype); \
  419. }
  420. #define __HPP_ENTRY_PERCENT_FN(_type, _field, _fmttype) \
  421. static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \
  422. struct perf_hpp *hpp, struct hist_entry *he) \
  423. { \
  424. return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \
  425. hpp_entry_scnprintf, _fmttype); \
  426. }
  427. #define __HPP_SORT_FN(_type, _field) \
  428. static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
  429. struct hist_entry *a, struct hist_entry *b) \
  430. { \
  431. return __hpp__sort(a, b, he_get_##_field); \
  432. }
  433. #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field, _fmttype) \
  434. static u64 he_get_acc_##_field(struct hist_entry *he) \
  435. { \
  436. return he->stat_acc->_field; \
  437. } \
  438. \
  439. static int hpp__color_##_type(struct perf_hpp_fmt *fmt, \
  440. struct perf_hpp *hpp, struct hist_entry *he) \
  441. { \
  442. return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \
  443. hpp_color_scnprintf, _fmttype); \
  444. }
  445. #define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field, _fmttype) \
  446. static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \
  447. struct perf_hpp *hpp, struct hist_entry *he) \
  448. { \
  449. return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \
  450. hpp_entry_scnprintf, _fmttype); \
  451. }
  452. #define __HPP_SORT_ACC_FN(_type, _field) \
  453. static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
  454. struct hist_entry *a, struct hist_entry *b) \
  455. { \
  456. return __hpp__sort_acc(a, b, he_get_acc_##_field); \
  457. }
  458. #define __HPP_ENTRY_RAW_FN(_type, _field) \
  459. static u64 he_get_raw_##_field(struct hist_entry *he) \
  460. { \
  461. return he->stat._field; \
  462. } \
  463. \
  464. static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \
  465. struct perf_hpp *hpp, struct hist_entry *he) \
  466. { \
  467. return hpp__fmt(fmt, hpp, he, he_get_raw_##_field, " %*"PRIu64, \
  468. hpp_entry_scnprintf, PERF_HPP_FMT_TYPE__RAW); \
  469. }
  470. #define __HPP_SORT_RAW_FN(_type, _field) \
  471. static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
  472. struct hist_entry *a, struct hist_entry *b) \
  473. { \
  474. return __hpp__sort(a, b, he_get_raw_##_field); \
  475. }
  476. #define __HPP_ENTRY_AVERAGE_FN(_type, _field) \
  477. static u64 he_get_##_field(struct hist_entry *he) \
  478. { \
  479. return he->stat._field; \
  480. } \
  481. \
  482. static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \
  483. struct perf_hpp *hpp, struct hist_entry *he) \
  484. { \
  485. return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.1f", \
  486. hpp_entry_scnprintf, PERF_HPP_FMT_TYPE__AVERAGE); \
  487. }
  488. #define __HPP_SORT_AVERAGE_FN(_type, _field) \
  489. static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
  490. struct hist_entry *a, struct hist_entry *b) \
  491. { \
  492. return __hpp__sort(a, b, he_get_##_field); \
  493. }
  494. #define __HPP_COLOR_MEM_STAT_FN(_name, _type) \
  495. static int hpp__color_mem_stat_##_name(struct perf_hpp_fmt *fmt, \
  496. struct perf_hpp *hpp, \
  497. struct hist_entry *he) \
  498. { \
  499. return hpp__fmt_mem_stat(fmt, hpp, he, PERF_MEM_STAT_##_type, \
  500. " %5.1f%%", hpp_color_scnprintf); \
  501. }
  502. #define __HPP_ENTRY_MEM_STAT_FN(_name, _type) \
  503. static int hpp__entry_mem_stat_##_name(struct perf_hpp_fmt *fmt, \
  504. struct perf_hpp *hpp, \
  505. struct hist_entry *he) \
  506. { \
  507. return hpp__fmt_mem_stat(fmt, hpp, he, PERF_MEM_STAT_##_type, \
  508. " %5.1f%%", hpp_entry_scnprintf); \
  509. }
  510. #define HPP_PERCENT_FNS(_type, _field, _fmttype) \
  511. __HPP_COLOR_PERCENT_FN(_type, _field, _fmttype) \
  512. __HPP_ENTRY_PERCENT_FN(_type, _field, _fmttype) \
  513. __HPP_SORT_FN(_type, _field)
  514. #define HPP_PERCENT_ACC_FNS(_type, _field, _fmttype) \
  515. __HPP_COLOR_ACC_PERCENT_FN(_type, _field, _fmttype) \
  516. __HPP_ENTRY_ACC_PERCENT_FN(_type, _field, _fmttype) \
  517. __HPP_SORT_ACC_FN(_type, _field)
  518. #define HPP_RAW_FNS(_type, _field) \
  519. __HPP_ENTRY_RAW_FN(_type, _field) \
  520. __HPP_SORT_RAW_FN(_type, _field)
  521. #define HPP_AVERAGE_FNS(_type, _field) \
  522. __HPP_ENTRY_AVERAGE_FN(_type, _field) \
  523. __HPP_SORT_AVERAGE_FN(_type, _field)
  524. #define HPP_MEM_STAT_FNS(_name, _type) \
  525. __HPP_COLOR_MEM_STAT_FN(_name, _type) \
  526. __HPP_ENTRY_MEM_STAT_FN(_name, _type)
  527. HPP_PERCENT_FNS(overhead, period, PERF_HPP_FMT_TYPE__PERCENT)
  528. HPP_PERCENT_FNS(latency, latency, PERF_HPP_FMT_TYPE__LATENCY)
  529. HPP_PERCENT_FNS(overhead_sys, period_sys, PERF_HPP_FMT_TYPE__PERCENT)
  530. HPP_PERCENT_FNS(overhead_us, period_us, PERF_HPP_FMT_TYPE__PERCENT)
  531. HPP_PERCENT_FNS(overhead_guest_sys, period_guest_sys, PERF_HPP_FMT_TYPE__PERCENT)
  532. HPP_PERCENT_FNS(overhead_guest_us, period_guest_us, PERF_HPP_FMT_TYPE__PERCENT)
  533. HPP_PERCENT_ACC_FNS(overhead_acc, period, PERF_HPP_FMT_TYPE__PERCENT)
  534. HPP_PERCENT_ACC_FNS(latency_acc, latency, PERF_HPP_FMT_TYPE__LATENCY)
  535. HPP_RAW_FNS(samples, nr_events)
  536. HPP_RAW_FNS(period, period)
  537. HPP_AVERAGE_FNS(weight1, weight1)
  538. HPP_AVERAGE_FNS(weight2, weight2)
  539. HPP_AVERAGE_FNS(weight3, weight3)
  540. HPP_MEM_STAT_FNS(op, OP)
  541. HPP_MEM_STAT_FNS(cache, CACHE)
  542. HPP_MEM_STAT_FNS(memory, MEMORY)
  543. HPP_MEM_STAT_FNS(snoop, SNOOP)
  544. HPP_MEM_STAT_FNS(dtlb, DTLB)
  545. static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
  546. struct hist_entry *a __maybe_unused,
  547. struct hist_entry *b __maybe_unused)
  548. {
  549. return 0;
  550. }
  551. static bool perf_hpp__is_mem_stat_entry(struct perf_hpp_fmt *fmt)
  552. {
  553. return fmt->sort == hpp__sort_mem_stat;
  554. }
  555. static bool perf_hpp__is_hpp_entry(struct perf_hpp_fmt *a)
  556. {
  557. return a->header == hpp__header_fn;
  558. }
  559. static bool hpp__equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
  560. {
  561. if (!perf_hpp__is_hpp_entry(a) || !perf_hpp__is_hpp_entry(b))
  562. return false;
  563. return a->idx == b->idx;
  564. }
  565. static bool hpp__equal_mem_stat(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
  566. {
  567. if (!perf_hpp__is_mem_stat_entry(a) || !perf_hpp__is_mem_stat_entry(b))
  568. return false;
  569. return a->entry == b->entry;
  570. }
  571. #define HPP__COLOR_PRINT_FNS(_name, _fn, _idx) \
  572. { \
  573. .name = _name, \
  574. .header = hpp__header_fn, \
  575. .width = hpp__width_fn, \
  576. .color = hpp__color_ ## _fn, \
  577. .entry = hpp__entry_ ## _fn, \
  578. .cmp = hpp__nop_cmp, \
  579. .collapse = hpp__nop_cmp, \
  580. .sort = hpp__sort_ ## _fn, \
  581. .idx = PERF_HPP__ ## _idx, \
  582. .equal = hpp__equal, \
  583. }
  584. #define HPP__COLOR_ACC_PRINT_FNS(_name, _fn, _idx) \
  585. { \
  586. .name = _name, \
  587. .header = hpp__header_fn, \
  588. .width = hpp__width_fn, \
  589. .color = hpp__color_ ## _fn, \
  590. .entry = hpp__entry_ ## _fn, \
  591. .cmp = hpp__nop_cmp, \
  592. .collapse = hpp__nop_cmp, \
  593. .sort = hpp__sort_ ## _fn, \
  594. .idx = PERF_HPP__ ## _idx, \
  595. .equal = hpp__equal, \
  596. }
  597. #define HPP__PRINT_FNS(_name, _fn, _idx) \
  598. { \
  599. .name = _name, \
  600. .header = hpp__header_fn, \
  601. .width = hpp__width_fn, \
  602. .entry = hpp__entry_ ## _fn, \
  603. .cmp = hpp__nop_cmp, \
  604. .collapse = hpp__nop_cmp, \
  605. .sort = hpp__sort_ ## _fn, \
  606. .idx = PERF_HPP__ ## _idx, \
  607. .equal = hpp__equal, \
  608. }
  609. #define HPP__MEM_STAT_PRINT_FNS(_name, _fn, _type) \
  610. { \
  611. .name = _name, \
  612. .header = hpp__header_mem_stat_fn, \
  613. .width = hpp__width_fn, \
  614. .color = hpp__color_mem_stat_ ## _fn, \
  615. .entry = hpp__entry_mem_stat_ ## _fn, \
  616. .cmp = hpp__nop_cmp, \
  617. .collapse = hpp__nop_cmp, \
  618. .sort = hpp__sort_mem_stat, \
  619. .idx = PERF_HPP__MEM_STAT_ ## _type, \
  620. .equal = hpp__equal_mem_stat, \
  621. }
  622. struct perf_hpp_fmt perf_hpp__format[] = {
  623. HPP__COLOR_PRINT_FNS("Overhead", overhead, OVERHEAD),
  624. HPP__COLOR_PRINT_FNS("Latency", latency, LATENCY),
  625. HPP__COLOR_PRINT_FNS("sys", overhead_sys, OVERHEAD_SYS),
  626. HPP__COLOR_PRINT_FNS("usr", overhead_us, OVERHEAD_US),
  627. HPP__COLOR_PRINT_FNS("guest sys", overhead_guest_sys, OVERHEAD_GUEST_SYS),
  628. HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us, OVERHEAD_GUEST_US),
  629. HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc, OVERHEAD_ACC),
  630. HPP__COLOR_ACC_PRINT_FNS("Latency", latency_acc, LATENCY_ACC),
  631. HPP__PRINT_FNS("Samples", samples, SAMPLES),
  632. HPP__PRINT_FNS("Period", period, PERIOD),
  633. HPP__PRINT_FNS("Weight1", weight1, WEIGHT1),
  634. HPP__PRINT_FNS("Weight2", weight2, WEIGHT2),
  635. HPP__PRINT_FNS("Weight3", weight3, WEIGHT3),
  636. HPP__MEM_STAT_PRINT_FNS("Mem Op", op, OP),
  637. HPP__MEM_STAT_PRINT_FNS("Cache", cache, CACHE),
  638. HPP__MEM_STAT_PRINT_FNS("Memory", memory, MEMORY),
  639. HPP__MEM_STAT_PRINT_FNS("Snoop", snoop, SNOOP),
  640. HPP__MEM_STAT_PRINT_FNS("D-TLB", dtlb, DTLB),
  641. };
  642. struct perf_hpp_list perf_hpp_list = {
  643. .fields = LIST_HEAD_INIT(perf_hpp_list.fields),
  644. .sorts = LIST_HEAD_INIT(perf_hpp_list.sorts),
  645. .nr_header_lines = 1,
  646. };
  647. #undef HPP__COLOR_PRINT_FNS
  648. #undef HPP__COLOR_ACC_PRINT_FNS
  649. #undef HPP__PRINT_FNS
  650. #undef HPP__MEM_STAT_PRINT_FNS
  651. #undef HPP_PERCENT_FNS
  652. #undef HPP_PERCENT_ACC_FNS
  653. #undef HPP_RAW_FNS
  654. #undef HPP_AVERAGE_FNS
  655. #undef HPP_MEM_STAT_FNS
  656. #undef __HPP_HEADER_FN
  657. #undef __HPP_WIDTH_FN
  658. #undef __HPP_COLOR_PERCENT_FN
  659. #undef __HPP_ENTRY_PERCENT_FN
  660. #undef __HPP_COLOR_ACC_PERCENT_FN
  661. #undef __HPP_ENTRY_ACC_PERCENT_FN
  662. #undef __HPP_ENTRY_RAW_FN
  663. #undef __HPP_ENTRY_AVERAGE_FN
  664. #undef __HPP_COLOR_MEM_STAT_FN
  665. #undef __HPP_ENTRY_MEM_STAT_FN
  666. #undef __HPP_SORT_FN
  667. #undef __HPP_SORT_ACC_FN
  668. #undef __HPP_SORT_RAW_FN
  669. #undef __HPP_SORT_AVERAGE_FN
  670. static void fmt_free(struct perf_hpp_fmt *fmt)
  671. {
  672. /*
  673. * At this point fmt should be completely
  674. * unhooked, if not it's a bug.
  675. */
  676. BUG_ON(!list_empty(&fmt->list));
  677. BUG_ON(!list_empty(&fmt->sort_list));
  678. if (fmt->free)
  679. fmt->free(fmt);
  680. }
  681. static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
  682. {
  683. return a->equal && a->equal(a, b);
  684. }
  685. void perf_hpp__init(void)
  686. {
  687. int i;
  688. for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
  689. struct perf_hpp_fmt *fmt = &perf_hpp__format[i];
  690. INIT_LIST_HEAD(&fmt->list);
  691. /* sort_list may be linked by setup_sorting() */
  692. if (fmt->sort_list.next == NULL)
  693. INIT_LIST_HEAD(&fmt->sort_list);
  694. }
  695. /*
  696. * If user specified field order, no need to setup default fields.
  697. */
  698. if (is_strict_order(field_order))
  699. return;
  700. /*
  701. * Overhead and latency columns are added in setup_overhead(),
  702. * so they are added implicitly here only if they were added
  703. * by setup_overhead() before (have was_taken flag set).
  704. * This is required because setup_overhead() has more complex
  705. * logic, in particular it does not add "overhead" if user
  706. * specified "latency" in sort order, and vise versa.
  707. */
  708. if (symbol_conf.cumulate_callchain) {
  709. /*
  710. * Addition of fields is idempotent, so we add latency
  711. * column twice to get desired order with simpler logic.
  712. */
  713. if (symbol_conf.prefer_latency)
  714. hpp_dimension__add_output(PERF_HPP__LATENCY_ACC, true);
  715. hpp_dimension__add_output(PERF_HPP__OVERHEAD_ACC, true);
  716. if (symbol_conf.enable_latency)
  717. hpp_dimension__add_output(PERF_HPP__LATENCY_ACC, true);
  718. perf_hpp__format[PERF_HPP__OVERHEAD].name = "Self";
  719. }
  720. if (symbol_conf.prefer_latency)
  721. hpp_dimension__add_output(PERF_HPP__LATENCY, true);
  722. hpp_dimension__add_output(PERF_HPP__OVERHEAD, true);
  723. if (symbol_conf.enable_latency)
  724. hpp_dimension__add_output(PERF_HPP__LATENCY, true);
  725. if (symbol_conf.show_cpu_utilization) {
  726. hpp_dimension__add_output(PERF_HPP__OVERHEAD_SYS, false);
  727. hpp_dimension__add_output(PERF_HPP__OVERHEAD_US, false);
  728. if (perf_guest) {
  729. hpp_dimension__add_output(PERF_HPP__OVERHEAD_GUEST_SYS, false);
  730. hpp_dimension__add_output(PERF_HPP__OVERHEAD_GUEST_US, false);
  731. }
  732. }
  733. if (symbol_conf.show_nr_samples)
  734. hpp_dimension__add_output(PERF_HPP__SAMPLES, false);
  735. if (symbol_conf.show_total_period)
  736. hpp_dimension__add_output(PERF_HPP__PERIOD, false);
  737. }
  738. void perf_hpp_list__column_register(struct perf_hpp_list *list,
  739. struct perf_hpp_fmt *format)
  740. {
  741. list_add_tail(&format->list, &list->fields);
  742. }
  743. void perf_hpp_list__register_sort_field(struct perf_hpp_list *list,
  744. struct perf_hpp_fmt *format)
  745. {
  746. list_add_tail(&format->sort_list, &list->sorts);
  747. }
  748. void perf_hpp_list__prepend_sort_field(struct perf_hpp_list *list,
  749. struct perf_hpp_fmt *format)
  750. {
  751. list_add(&format->sort_list, &list->sorts);
  752. }
  753. static void perf_hpp__column_unregister(struct perf_hpp_fmt *format)
  754. {
  755. list_del_init(&format->list);
  756. list_del_init(&format->sort_list);
  757. fmt_free(format);
  758. }
  759. void perf_hpp__cancel_cumulate(struct evlist *evlist)
  760. {
  761. struct perf_hpp_fmt *fmt, *acc, *ovh, *acc_lat, *tmp;
  762. struct evsel *evsel;
  763. if (is_strict_order(field_order))
  764. return;
  765. ovh = &perf_hpp__format[PERF_HPP__OVERHEAD];
  766. acc = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC];
  767. acc_lat = &perf_hpp__format[PERF_HPP__LATENCY_ACC];
  768. perf_hpp_list__for_each_format_safe(&perf_hpp_list, fmt, tmp) {
  769. if (fmt_equal(acc, fmt) || fmt_equal(acc_lat, fmt)) {
  770. perf_hpp__column_unregister(fmt);
  771. continue;
  772. }
  773. if (fmt_equal(ovh, fmt))
  774. fmt->name = "Overhead";
  775. }
  776. evlist__for_each_entry(evlist, evsel) {
  777. struct hists *hists = evsel__hists(evsel);
  778. struct perf_hpp_list_node *node;
  779. list_for_each_entry(node, &hists->hpp_formats, list) {
  780. perf_hpp_list__for_each_format_safe(&node->hpp, fmt, tmp) {
  781. if (fmt_equal(acc, fmt) || fmt_equal(acc_lat, fmt)) {
  782. perf_hpp__column_unregister(fmt);
  783. continue;
  784. }
  785. if (fmt_equal(ovh, fmt))
  786. fmt->name = "Overhead";
  787. }
  788. }
  789. }
  790. }
  791. void perf_hpp__cancel_latency(struct evlist *evlist)
  792. {
  793. struct perf_hpp_fmt *fmt, *lat, *acc, *tmp;
  794. struct evsel *evsel;
  795. if (is_strict_order(field_order))
  796. return;
  797. if (sort_order && strstr(sort_order, "latency"))
  798. return;
  799. lat = &perf_hpp__format[PERF_HPP__LATENCY];
  800. acc = &perf_hpp__format[PERF_HPP__LATENCY_ACC];
  801. perf_hpp_list__for_each_format_safe(&perf_hpp_list, fmt, tmp) {
  802. if (fmt_equal(lat, fmt) || fmt_equal(acc, fmt))
  803. perf_hpp__column_unregister(fmt);
  804. }
  805. evlist__for_each_entry(evlist, evsel) {
  806. struct hists *hists = evsel__hists(evsel);
  807. struct perf_hpp_list_node *node;
  808. list_for_each_entry(node, &hists->hpp_formats, list) {
  809. perf_hpp_list__for_each_format_safe(&node->hpp, fmt, tmp) {
  810. if (fmt_equal(lat, fmt) || fmt_equal(acc, fmt))
  811. perf_hpp__column_unregister(fmt);
  812. }
  813. }
  814. }
  815. }
  816. void perf_hpp__setup_output_field(struct perf_hpp_list *list)
  817. {
  818. struct perf_hpp_fmt *fmt;
  819. /* append sort keys to output field */
  820. perf_hpp_list__for_each_sort_list(list, fmt) {
  821. struct perf_hpp_fmt *pos;
  822. /* skip sort-only fields ("sort_compute" in perf diff) */
  823. if (!fmt->entry && !fmt->color)
  824. continue;
  825. perf_hpp_list__for_each_format(list, pos) {
  826. if (fmt_equal(fmt, pos))
  827. goto next;
  828. }
  829. perf_hpp__column_register(fmt);
  830. next:
  831. continue;
  832. }
  833. }
  834. void perf_hpp__append_sort_keys(struct perf_hpp_list *list)
  835. {
  836. struct perf_hpp_fmt *fmt;
  837. /* append output fields to sort keys */
  838. perf_hpp_list__for_each_format(list, fmt) {
  839. struct perf_hpp_fmt *pos;
  840. perf_hpp_list__for_each_sort_list(list, pos) {
  841. if (fmt_equal(fmt, pos))
  842. goto next;
  843. }
  844. perf_hpp__register_sort_field(fmt);
  845. next:
  846. continue;
  847. }
  848. }
  849. void perf_hpp__reset_output_field(struct perf_hpp_list *list)
  850. {
  851. struct perf_hpp_fmt *fmt, *tmp;
  852. /* reset output fields */
  853. perf_hpp_list__for_each_format_safe(list, fmt, tmp)
  854. perf_hpp__column_unregister(fmt);
  855. /* reset sort keys */
  856. perf_hpp_list__for_each_sort_list_safe(list, fmt, tmp)
  857. perf_hpp__column_unregister(fmt);
  858. }
  859. /*
  860. * See hists__fprintf to match the column widths
  861. */
  862. unsigned int hists__sort_list_width(struct hists *hists)
  863. {
  864. struct perf_hpp_fmt *fmt;
  865. int ret = 0;
  866. bool first = true;
  867. struct perf_hpp dummy_hpp;
  868. hists__for_each_format(hists, fmt) {
  869. if (perf_hpp__should_skip(fmt, hists))
  870. continue;
  871. if (first)
  872. first = false;
  873. else
  874. ret += 2;
  875. ret += fmt->width(fmt, &dummy_hpp, hists);
  876. }
  877. if (verbose > 0 && hists__has(hists, sym)) /* Addr + origin */
  878. ret += 3 + BITS_PER_LONG / 4;
  879. return ret;
  880. }
  881. unsigned int hists__overhead_width(struct hists *hists)
  882. {
  883. struct perf_hpp_fmt *fmt;
  884. int ret = 0;
  885. bool first = true;
  886. struct perf_hpp dummy_hpp;
  887. hists__for_each_format(hists, fmt) {
  888. if (perf_hpp__is_sort_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
  889. break;
  890. if (first)
  891. first = false;
  892. else
  893. ret += 2;
  894. ret += fmt->width(fmt, &dummy_hpp, hists);
  895. }
  896. return ret;
  897. }
  898. void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
  899. {
  900. if (perf_hpp__is_sort_entry(fmt))
  901. return perf_hpp__reset_sort_width(fmt, hists);
  902. if (perf_hpp__is_dynamic_entry(fmt))
  903. return;
  904. BUG_ON(fmt->idx >= PERF_HPP__MAX_INDEX);
  905. switch (fmt->idx) {
  906. case PERF_HPP__OVERHEAD:
  907. case PERF_HPP__LATENCY:
  908. case PERF_HPP__OVERHEAD_SYS:
  909. case PERF_HPP__OVERHEAD_US:
  910. case PERF_HPP__OVERHEAD_ACC:
  911. fmt->len = 8;
  912. break;
  913. case PERF_HPP__OVERHEAD_GUEST_SYS:
  914. case PERF_HPP__OVERHEAD_GUEST_US:
  915. fmt->len = 9;
  916. break;
  917. case PERF_HPP__SAMPLES:
  918. case PERF_HPP__PERIOD:
  919. fmt->len = 12;
  920. break;
  921. case PERF_HPP__WEIGHT1:
  922. case PERF_HPP__WEIGHT2:
  923. case PERF_HPP__WEIGHT3:
  924. fmt->len = 8;
  925. break;
  926. case PERF_HPP__MEM_STAT_OP:
  927. case PERF_HPP__MEM_STAT_CACHE:
  928. case PERF_HPP__MEM_STAT_MEMORY:
  929. case PERF_HPP__MEM_STAT_SNOOP:
  930. case PERF_HPP__MEM_STAT_DTLB:
  931. fmt->len = MEM_STAT_LEN * MEM_STAT_PRINT_LEN;
  932. break;
  933. default:
  934. break;
  935. }
  936. }
  937. void hists__reset_column_width(struct hists *hists)
  938. {
  939. struct perf_hpp_fmt *fmt;
  940. struct perf_hpp_list_node *node;
  941. hists__for_each_format(hists, fmt)
  942. perf_hpp__reset_width(fmt, hists);
  943. /* hierarchy entries have their own hpp list */
  944. list_for_each_entry(node, &hists->hpp_formats, list) {
  945. perf_hpp_list__for_each_format(&node->hpp, fmt)
  946. perf_hpp__reset_width(fmt, hists);
  947. }
  948. }
  949. void perf_hpp__set_user_width(const char *width_list_str)
  950. {
  951. struct perf_hpp_fmt *fmt;
  952. const char *ptr = width_list_str;
  953. perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
  954. char *p;
  955. int len = strtol(ptr, &p, 10);
  956. fmt->user_len = len;
  957. if (*p == ',')
  958. ptr = p + 1;
  959. else
  960. break;
  961. }
  962. }
  963. static int add_hierarchy_fmt(struct hists *hists, struct perf_hpp_fmt *fmt)
  964. {
  965. struct perf_hpp_list_node *node = NULL;
  966. struct perf_hpp_fmt *fmt_copy;
  967. bool found = false;
  968. bool skip = perf_hpp__should_skip(fmt, hists);
  969. list_for_each_entry(node, &hists->hpp_formats, list) {
  970. if (node->level == fmt->level) {
  971. found = true;
  972. break;
  973. }
  974. }
  975. if (!found) {
  976. node = malloc(sizeof(*node));
  977. if (node == NULL)
  978. return -1;
  979. node->skip = skip;
  980. node->level = fmt->level;
  981. perf_hpp_list__init(&node->hpp);
  982. hists->nr_hpp_node++;
  983. list_add_tail(&node->list, &hists->hpp_formats);
  984. }
  985. fmt_copy = perf_hpp_fmt__dup(fmt);
  986. if (fmt_copy == NULL)
  987. return -1;
  988. if (!skip)
  989. node->skip = false;
  990. list_add_tail(&fmt_copy->list, &node->hpp.fields);
  991. list_add_tail(&fmt_copy->sort_list, &node->hpp.sorts);
  992. return 0;
  993. }
  994. int perf_hpp__setup_hists_formats(struct perf_hpp_list *list,
  995. struct evlist *evlist)
  996. {
  997. struct evsel *evsel;
  998. struct perf_hpp_fmt *fmt;
  999. struct hists *hists;
  1000. int ret;
  1001. if (!symbol_conf.report_hierarchy)
  1002. return 0;
  1003. evlist__for_each_entry(evlist, evsel) {
  1004. hists = evsel__hists(evsel);
  1005. perf_hpp_list__for_each_sort_list(list, fmt) {
  1006. if (perf_hpp__is_dynamic_entry(fmt) &&
  1007. !perf_hpp__defined_dynamic_entry(fmt, hists))
  1008. continue;
  1009. ret = add_hierarchy_fmt(hists, fmt);
  1010. if (ret < 0)
  1011. return ret;
  1012. }
  1013. }
  1014. return 0;
  1015. }
  1016. int perf_hpp__alloc_mem_stats(struct perf_hpp_list *list, struct evlist *evlist)
  1017. {
  1018. struct perf_hpp_fmt *fmt;
  1019. struct evsel *evsel;
  1020. enum mem_stat_type mst[16];
  1021. unsigned nr_mem_stats = 0;
  1022. perf_hpp_list__for_each_format(list, fmt) {
  1023. if (!perf_hpp__is_mem_stat_entry(fmt))
  1024. continue;
  1025. assert(nr_mem_stats < ARRAY_SIZE(mst));
  1026. mst[nr_mem_stats++] = hpp__mem_stat_type(fmt);
  1027. }
  1028. if (nr_mem_stats == 0)
  1029. return 0;
  1030. list->nr_header_lines = 2;
  1031. evlist__for_each_entry(evlist, evsel) {
  1032. struct hists *hists = evsel__hists(evsel);
  1033. hists->mem_stat_types = calloc(nr_mem_stats,
  1034. sizeof(*hists->mem_stat_types));
  1035. if (hists->mem_stat_types == NULL)
  1036. return -ENOMEM;
  1037. hists->mem_stat_total = calloc(nr_mem_stats,
  1038. sizeof(*hists->mem_stat_total));
  1039. if (hists->mem_stat_total == NULL)
  1040. return -ENOMEM;
  1041. memcpy(hists->mem_stat_types, mst, nr_mem_stats * sizeof(*mst));
  1042. hists->nr_mem_stats = nr_mem_stats;
  1043. }
  1044. return 0;
  1045. }