1#include <math.h> 2#include <linux/compiler.h> 3 4#include "../util/hist.h" 5#include "../util/util.h" 6#include "../util/sort.h" 7#include "../util/evsel.h" 8 9/* hist period print (hpp) functions */ 10 11typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...); 12 13static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, 14 u64 (*get_field)(struct hist_entry *), 15 const char *fmt, hpp_snprint_fn print_fn, 16 bool fmt_percent) 17{ 18 int ret; 19 struct hists *hists = he->hists; 20 struct perf_evsel *evsel = hists_to_evsel(hists); 21 22 if (fmt_percent) { 23 double percent = 0.0; 24 25 if (hists->stats.total_period) 26 percent = 100.0 * get_field(he) / 27 hists->stats.total_period; 28 29 ret = print_fn(hpp->buf, hpp->size, fmt, percent); 30 } else 31 ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he)); 32 33 if (perf_evsel__is_group_event(evsel)) { 34 int prev_idx, idx_delta; 35 struct hist_entry *pair; 36 int nr_members = evsel->nr_members; 37 38 prev_idx = perf_evsel__group_idx(evsel); 39 40 list_for_each_entry(pair, &he->pairs.head, pairs.node) { 41 u64 period = get_field(pair); 42 u64 total = pair->hists->stats.total_period; 43 44 if (!total) 45 continue; 46 47 evsel = hists_to_evsel(pair->hists); 48 idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1; 49 50 while (idx_delta--) { 51 /* 52 * zero-fill group members in the middle which 53 * have no sample 54 */ 55 ret += print_fn(hpp->buf + ret, hpp->size - ret, 56 fmt, 0); 57 } 58 59 if (fmt_percent) 60 ret += print_fn(hpp->buf + ret, hpp->size - ret, 61 fmt, 100.0 * period / total); 62 else 63 ret += print_fn(hpp->buf + ret, hpp->size - ret, 64 fmt, period); 65 66 prev_idx = perf_evsel__group_idx(evsel); 67 } 68 69 idx_delta = nr_members - prev_idx - 1; 70 71 while (idx_delta--) { 72 /* 73 * zero-fill group members at last which have no sample 74 */ 75 ret += print_fn(hpp->buf + ret, hpp->size - ret, 76 fmt, 0); 77 } 78 } 79 return ret; 80} 81 82#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ 83static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 84 struct perf_hpp *hpp) \ 85{ \ 86 int len = _min_width; \ 87 \ 88 if (symbol_conf.event_group) { \ 89 struct perf_evsel *evsel = hpp->ptr; \ 90 \ 91 len = max(len, evsel->nr_members * _unit_width); \ 92 } \ 93 return scnprintf(hpp->buf, hpp->size, "%*s", len, _str); \ 94} 95 96#define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ 97static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 98 struct perf_hpp *hpp __maybe_unused) \ 99{ \ 100 int len = _min_width; \ 101 \ 102 if (symbol_conf.event_group) { \ 103 struct perf_evsel *evsel = hpp->ptr; \ 104 \ 105 len = max(len, evsel->nr_members * _unit_width); \ 106 } \ 107 return len; \ 108} 109 110#define __HPP_COLOR_PERCENT_FN(_type, _field) \ 111static u64 he_get_##_field(struct hist_entry *he) \ 112{ \ 113 return he->stat._field; \ 114} \ 115 \ 116static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 117 struct perf_hpp *hpp, struct hist_entry *he) \ 118{ \ 119 return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ 120 percent_color_snprintf, true); \ 121} 122 123#define __HPP_ENTRY_PERCENT_FN(_type, _field) \ 124static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ 125 struct perf_hpp *hpp, struct hist_entry *he) \ 126{ \ 127 const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ 128 return __hpp__fmt(hpp, he, he_get_##_field, fmt, \ 129 scnprintf, true); \ 130} 131 132#define __HPP_ENTRY_RAW_FN(_type, _field) \ 133static u64 he_get_raw_##_field(struct hist_entry *he) \ 134{ \ 135 return he->stat._field; \ 136} \ 137 \ 138static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ 139 struct perf_hpp *hpp, struct hist_entry *he) \ 140{ \ 141 const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ 142 return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \ 143} 144 145#define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \ 146__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ 147__HPP_WIDTH_FN(_type, _min_width, _unit_width) \ 148__HPP_COLOR_PERCENT_FN(_type, _field) \ 149__HPP_ENTRY_PERCENT_FN(_type, _field) 150 151#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \ 152__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ 153__HPP_WIDTH_FN(_type, _min_width, _unit_width) \ 154__HPP_ENTRY_RAW_FN(_type, _field) 155 156 157HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8) 158HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8) 159HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8) 160HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8) 161HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) 162 163HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) 164HPP_RAW_FNS(period, "Period", period, 12, 12) 165 166#define HPP__COLOR_PRINT_FNS(_name) \ 167 { \ 168 .header = hpp__header_ ## _name, \ 169 .width = hpp__width_ ## _name, \ 170 .color = hpp__color_ ## _name, \ 171 .entry = hpp__entry_ ## _name \ 172 } 173 174#define HPP__PRINT_FNS(_name) \ 175 { \ 176 .header = hpp__header_ ## _name, \ 177 .width = hpp__width_ ## _name, \ 178 .entry = hpp__entry_ ## _name \ 179 } 180 181struct perf_hpp_fmt perf_hpp__format[] = { 182 HPP__COLOR_PRINT_FNS(overhead), 183 HPP__COLOR_PRINT_FNS(overhead_sys), 184 HPP__COLOR_PRINT_FNS(overhead_us), 185 HPP__COLOR_PRINT_FNS(overhead_guest_sys), 186 HPP__COLOR_PRINT_FNS(overhead_guest_us), 187 HPP__PRINT_FNS(samples), 188 HPP__PRINT_FNS(period) 189}; 190 191LIST_HEAD(perf_hpp__list); 192 193 194#undef HPP__COLOR_PRINT_FNS 195#undef HPP__PRINT_FNS 196 197#undef HPP_PERCENT_FNS 198#undef HPP_RAW_FNS 199 200#undef __HPP_HEADER_FN 201#undef __HPP_WIDTH_FN 202#undef __HPP_COLOR_PERCENT_FN 203#undef __HPP_ENTRY_PERCENT_FN 204#undef __HPP_ENTRY_RAW_FN 205 206 207void perf_hpp__init(void) 208{ 209 perf_hpp__column_enable(PERF_HPP__OVERHEAD); 210 211 if (symbol_conf.show_cpu_utilization) { 212 perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS); 213 perf_hpp__column_enable(PERF_HPP__OVERHEAD_US); 214 215 if (perf_guest) { 216 perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_SYS); 217 perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_US); 218 } 219 } 220 221 if (symbol_conf.show_nr_samples) 222 perf_hpp__column_enable(PERF_HPP__SAMPLES); 223 224 if (symbol_conf.show_total_period) 225 perf_hpp__column_enable(PERF_HPP__PERIOD); 226} 227 228void perf_hpp__column_register(struct perf_hpp_fmt *format) 229{ 230 list_add_tail(&format->list, &perf_hpp__list); 231} 232 233void perf_hpp__column_enable(unsigned col) 234{ 235 BUG_ON(col >= PERF_HPP__MAX_INDEX); 236 perf_hpp__column_register(&perf_hpp__format[col]); 237} 238 239int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, 240 struct hists *hists) 241{ 242 const char *sep = symbol_conf.field_sep; 243 struct sort_entry *se; 244 int ret = 0; 245 246 list_for_each_entry(se, &hist_entry__sort_list, list) { 247 if (se->elide) 248 continue; 249 250 ret += scnprintf(s + ret, size - ret, "%s", sep ?: " "); 251 ret += se->se_snprintf(he, s + ret, size - ret, 252 hists__col_len(hists, se->se_width_idx)); 253 } 254 255 return ret; 256} 257 258/* 259 * See hists__fprintf to match the column widths 260 */ 261unsigned int hists__sort_list_width(struct hists *hists) 262{ 263 struct perf_hpp_fmt *fmt; 264 struct sort_entry *se; 265 int i = 0, ret = 0; 266 struct perf_hpp dummy_hpp = { 267 .ptr = hists_to_evsel(hists), 268 }; 269 270 perf_hpp__for_each_format(fmt) { 271 if (i) 272 ret += 2; 273 274 ret += fmt->width(fmt, &dummy_hpp); 275 } 276 277 list_for_each_entry(se, &hist_entry__sort_list, list) 278 if (!se->elide) 279 ret += 2 + hists__col_len(hists, se->se_width_idx); 280 281 if (verbose) /* Addr + origin */ 282 ret += 3 + BITS_PER_LONG / 4; 283 284 return ret; 285} 286