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 11 typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...); 12 13 static 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) \ 83 static 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) \ 97 static 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) \ 111 static u64 he_get_##_field(struct hist_entry *he) \ 112 { \ 113 return he->stat._field; \ 114 } \ 115 \ 116 static 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) \ 124 static 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) \ 133 static u64 he_get_raw_##_field(struct hist_entry *he) \ 134 { \ 135 return he->stat._field; \ 136 } \ 137 \ 138 static 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 157 HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8) 158 HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8) 159 HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8) 160 HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8) 161 HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) 162 163 HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) 164 HPP_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 181 struct 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 191 LIST_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 207 void 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 228 void perf_hpp__column_register(struct perf_hpp_fmt *format) 229 { 230 list_add_tail(&format->list, &perf_hpp__list); 231 } 232 233 void 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 239 int 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 */ 261 unsigned 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