hist.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. #include <math.h>
  2. #include "../util/hist.h"
  3. #include "../util/util.h"
  4. #include "../util/sort.h"
  5. #include "../util/evsel.h"
  6. /* hist period print (hpp) functions */
  7. typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...);
  8. static int __hpp__percent_fmt(struct perf_hpp *hpp, struct hist_entry *he,
  9. u64 (*get_field)(struct hist_entry *),
  10. const char *fmt, hpp_snprint_fn print_fn)
  11. {
  12. int ret;
  13. double percent = 0.0;
  14. struct hists *hists = he->hists;
  15. if (hists->stats.total_period)
  16. percent = 100.0 * get_field(he) / hists->stats.total_period;
  17. ret = print_fn(hpp->buf, hpp->size, fmt, percent);
  18. return ret;
  19. }
  20. static int __hpp__raw_fmt(struct perf_hpp *hpp, struct hist_entry *he,
  21. u64 (*get_field)(struct hist_entry *),
  22. const char *fmt, hpp_snprint_fn print_fn)
  23. {
  24. int ret;
  25. ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he));
  26. return ret;
  27. }
  28. #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
  29. static int hpp__header_##_type(struct perf_hpp *hpp) \
  30. { \
  31. int len = _min_width; \
  32. \
  33. return scnprintf(hpp->buf, hpp->size, "%*s", len, _str); \
  34. }
  35. #define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \
  36. static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused) \
  37. { \
  38. int len = _min_width; \
  39. \
  40. return len; \
  41. }
  42. #define __HPP_COLOR_PERCENT_FN(_type, _field) \
  43. static u64 he_get_##_field(struct hist_entry *he) \
  44. { \
  45. return he->stat._field; \
  46. } \
  47. \
  48. static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
  49. { \
  50. return __hpp__percent_fmt(hpp, he, he_get_##_field, " %6.2f%%", \
  51. (hpp_snprint_fn)percent_color_snprintf); \
  52. }
  53. #define __HPP_ENTRY_PERCENT_FN(_type, _field) \
  54. static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
  55. { \
  56. const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \
  57. return __hpp__percent_fmt(hpp, he, he_get_##_field, fmt, \
  58. scnprintf); \
  59. }
  60. #define __HPP_ENTRY_RAW_FN(_type, _field) \
  61. static u64 he_get_raw_##_field(struct hist_entry *he) \
  62. { \
  63. return he->stat._field; \
  64. } \
  65. \
  66. static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
  67. { \
  68. const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \
  69. return __hpp__raw_fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf); \
  70. }
  71. #define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \
  72. __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
  73. __HPP_WIDTH_FN(_type, _min_width, _unit_width) \
  74. __HPP_COLOR_PERCENT_FN(_type, _field) \
  75. __HPP_ENTRY_PERCENT_FN(_type, _field)
  76. #define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \
  77. __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
  78. __HPP_WIDTH_FN(_type, _min_width, _unit_width) \
  79. __HPP_ENTRY_RAW_FN(_type, _field)
  80. HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8)
  81. HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8)
  82. HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8)
  83. HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8)
  84. HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
  85. HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
  86. HPP_RAW_FNS(period, "Period", period, 12, 12)
  87. static int hpp__header_baseline(struct perf_hpp *hpp)
  88. {
  89. return scnprintf(hpp->buf, hpp->size, "Baseline");
  90. }
  91. static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused)
  92. {
  93. return 8;
  94. }
  95. static double baseline_percent(struct hist_entry *he)
  96. {
  97. struct hist_entry *pair = hist_entry__next_pair(he);
  98. struct hists *pair_hists = pair ? pair->hists : NULL;
  99. double percent = 0.0;
  100. if (pair) {
  101. u64 total_period = pair_hists->stats.total_period;
  102. u64 base_period = pair->stat.period;
  103. percent = 100.0 * base_period / total_period;
  104. }
  105. return percent;
  106. }
  107. static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
  108. {
  109. double percent = baseline_percent(he);
  110. if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
  111. return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
  112. else
  113. return scnprintf(hpp->buf, hpp->size, " ");
  114. }
  115. static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
  116. {
  117. double percent = baseline_percent(he);
  118. const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
  119. if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
  120. return scnprintf(hpp->buf, hpp->size, fmt, percent);
  121. else
  122. return scnprintf(hpp->buf, hpp->size, " ");
  123. }
  124. static int hpp__header_period_baseline(struct perf_hpp *hpp)
  125. {
  126. const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
  127. return scnprintf(hpp->buf, hpp->size, fmt, "Period Base");
  128. }
  129. static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused)
  130. {
  131. return 12;
  132. }
  133. static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *he)
  134. {
  135. struct hist_entry *pair = hist_entry__next_pair(he);
  136. u64 period = pair ? pair->stat.period : 0;
  137. const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
  138. return scnprintf(hpp->buf, hpp->size, fmt, period);
  139. }
  140. static int hpp__header_delta(struct perf_hpp *hpp)
  141. {
  142. const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
  143. return scnprintf(hpp->buf, hpp->size, fmt, "Delta");
  144. }
  145. static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
  146. {
  147. return 7;
  148. }
  149. static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
  150. {
  151. struct hist_entry *pair = hist_entry__next_pair(he);
  152. const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
  153. char buf[32] = " ";
  154. double diff = 0.0;
  155. if (pair) {
  156. if (he->diff.computed)
  157. diff = he->diff.period_ratio_delta;
  158. else
  159. diff = perf_diff__compute_delta(he, pair);
  160. } else
  161. diff = perf_diff__period_percent(he, he->stat.period);
  162. if (fabs(diff) >= 0.01)
  163. scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
  164. return scnprintf(hpp->buf, hpp->size, fmt, buf);
  165. }
  166. static int hpp__header_ratio(struct perf_hpp *hpp)
  167. {
  168. const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
  169. return scnprintf(hpp->buf, hpp->size, fmt, "Ratio");
  170. }
  171. static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused)
  172. {
  173. return 14;
  174. }
  175. static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he)
  176. {
  177. struct hist_entry *pair = hist_entry__next_pair(he);
  178. const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
  179. char buf[32] = " ";
  180. double ratio = 0.0;
  181. if (pair) {
  182. if (he->diff.computed)
  183. ratio = he->diff.period_ratio;
  184. else
  185. ratio = perf_diff__compute_ratio(he, pair);
  186. }
  187. if (ratio > 0.0)
  188. scnprintf(buf, sizeof(buf), "%+14.6F", ratio);
  189. return scnprintf(hpp->buf, hpp->size, fmt, buf);
  190. }
  191. static int hpp__header_wdiff(struct perf_hpp *hpp)
  192. {
  193. const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
  194. return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff");
  195. }
  196. static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
  197. {
  198. return 14;
  199. }
  200. static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
  201. {
  202. struct hist_entry *pair = hist_entry__next_pair(he);
  203. const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
  204. char buf[32] = " ";
  205. s64 wdiff = 0;
  206. if (pair) {
  207. if (he->diff.computed)
  208. wdiff = he->diff.wdiff;
  209. else
  210. wdiff = perf_diff__compute_wdiff(he, pair);
  211. }
  212. if (wdiff != 0)
  213. scnprintf(buf, sizeof(buf), "%14ld", wdiff);
  214. return scnprintf(hpp->buf, hpp->size, fmt, buf);
  215. }
  216. static int hpp__header_formula(struct perf_hpp *hpp)
  217. {
  218. const char *fmt = symbol_conf.field_sep ? "%s" : "%70s";
  219. return scnprintf(hpp->buf, hpp->size, fmt, "Formula");
  220. }
  221. static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused)
  222. {
  223. return 70;
  224. }
  225. static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
  226. {
  227. struct hist_entry *pair = hist_entry__next_pair(he);
  228. const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s";
  229. char buf[96] = " ";
  230. if (pair)
  231. perf_diff__formula(he, pair, buf, sizeof(buf));
  232. return scnprintf(hpp->buf, hpp->size, fmt, buf);
  233. }
  234. #define HPP__COLOR_PRINT_FNS(_name) \
  235. { \
  236. .header = hpp__header_ ## _name, \
  237. .width = hpp__width_ ## _name, \
  238. .color = hpp__color_ ## _name, \
  239. .entry = hpp__entry_ ## _name \
  240. }
  241. #define HPP__PRINT_FNS(_name) \
  242. { \
  243. .header = hpp__header_ ## _name, \
  244. .width = hpp__width_ ## _name, \
  245. .entry = hpp__entry_ ## _name \
  246. }
  247. struct perf_hpp_fmt perf_hpp__format[] = {
  248. HPP__COLOR_PRINT_FNS(baseline),
  249. HPP__COLOR_PRINT_FNS(overhead),
  250. HPP__COLOR_PRINT_FNS(overhead_sys),
  251. HPP__COLOR_PRINT_FNS(overhead_us),
  252. HPP__COLOR_PRINT_FNS(overhead_guest_sys),
  253. HPP__COLOR_PRINT_FNS(overhead_guest_us),
  254. HPP__PRINT_FNS(samples),
  255. HPP__PRINT_FNS(period),
  256. HPP__PRINT_FNS(period_baseline),
  257. HPP__PRINT_FNS(delta),
  258. HPP__PRINT_FNS(ratio),
  259. HPP__PRINT_FNS(wdiff),
  260. HPP__PRINT_FNS(formula)
  261. };
  262. LIST_HEAD(perf_hpp__list);
  263. #undef HPP__COLOR_PRINT_FNS
  264. #undef HPP__PRINT_FNS
  265. #undef HPP_PERCENT_FNS
  266. #undef HPP_RAW_FNS
  267. #undef __HPP_HEADER_FN
  268. #undef __HPP_WIDTH_FN
  269. #undef __HPP_COLOR_PERCENT_FN
  270. #undef __HPP_ENTRY_PERCENT_FN
  271. #undef __HPP_ENTRY_RAW_FN
  272. void perf_hpp__init(void)
  273. {
  274. if (symbol_conf.show_cpu_utilization) {
  275. perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS);
  276. perf_hpp__column_enable(PERF_HPP__OVERHEAD_US);
  277. if (perf_guest) {
  278. perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_SYS);
  279. perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_US);
  280. }
  281. }
  282. if (symbol_conf.show_nr_samples)
  283. perf_hpp__column_enable(PERF_HPP__SAMPLES);
  284. if (symbol_conf.show_total_period)
  285. perf_hpp__column_enable(PERF_HPP__PERIOD);
  286. }
  287. void perf_hpp__column_register(struct perf_hpp_fmt *format)
  288. {
  289. list_add_tail(&format->list, &perf_hpp__list);
  290. }
  291. void perf_hpp__column_enable(unsigned col)
  292. {
  293. BUG_ON(col >= PERF_HPP__MAX_INDEX);
  294. perf_hpp__column_register(&perf_hpp__format[col]);
  295. }
  296. static inline void advance_hpp(struct perf_hpp *hpp, int inc)
  297. {
  298. hpp->buf += inc;
  299. hpp->size -= inc;
  300. }
  301. int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
  302. bool color)
  303. {
  304. const char *sep = symbol_conf.field_sep;
  305. struct perf_hpp_fmt *fmt;
  306. char *start = hpp->buf;
  307. int ret;
  308. bool first = true;
  309. if (symbol_conf.exclude_other && !he->parent)
  310. return 0;
  311. perf_hpp__for_each_format(fmt) {
  312. /*
  313. * If there's no field_sep, we still need
  314. * to display initial ' '.
  315. */
  316. if (!sep || !first) {
  317. ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
  318. advance_hpp(hpp, ret);
  319. } else
  320. first = false;
  321. if (color && fmt->color)
  322. ret = fmt->color(hpp, he);
  323. else
  324. ret = fmt->entry(hpp, he);
  325. advance_hpp(hpp, ret);
  326. }
  327. return hpp->buf - start;
  328. }
  329. int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
  330. struct hists *hists)
  331. {
  332. const char *sep = symbol_conf.field_sep;
  333. struct sort_entry *se;
  334. int ret = 0;
  335. list_for_each_entry(se, &hist_entry__sort_list, list) {
  336. if (se->elide)
  337. continue;
  338. ret += scnprintf(s + ret, size - ret, "%s", sep ?: " ");
  339. ret += se->se_snprintf(he, s + ret, size - ret,
  340. hists__col_len(hists, se->se_width_idx));
  341. }
  342. return ret;
  343. }
  344. /*
  345. * See hists__fprintf to match the column widths
  346. */
  347. unsigned int hists__sort_list_width(struct hists *hists)
  348. {
  349. struct perf_hpp_fmt *fmt;
  350. struct sort_entry *se;
  351. int i = 0, ret = 0;
  352. perf_hpp__for_each_format(fmt) {
  353. if (i)
  354. ret += 2;
  355. ret += fmt->width(NULL);
  356. }
  357. list_for_each_entry(se, &hist_entry__sort_list, list)
  358. if (!se->elide)
  359. ret += 2 + hists__col_len(hists, se->se_width_idx);
  360. if (verbose) /* Addr + origin */
  361. ret += 3 + BITS_PER_LONG / 4;
  362. return ret;
  363. }