1 #include <math.h> 2 3 #include "../util/hist.h" 4 #include "../util/util.h" 5 #include "../util/sort.h" 6 7 8 /* hist period print (hpp) functions */ 9 static int hpp__header_overhead(struct perf_hpp *hpp) 10 { 11 return scnprintf(hpp->buf, hpp->size, "Overhead"); 12 } 13 14 static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused) 15 { 16 return 8; 17 } 18 19 static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he) 20 { 21 struct hists *hists = he->hists; 22 double percent = 100.0 * he->stat.period / hists->stats.total_period; 23 24 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); 25 } 26 27 static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he) 28 { 29 struct hists *hists = he->hists; 30 double percent = 100.0 * he->stat.period / hists->stats.total_period; 31 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; 32 33 return scnprintf(hpp->buf, hpp->size, fmt, percent); 34 } 35 36 static int hpp__header_overhead_sys(struct perf_hpp *hpp) 37 { 38 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; 39 40 return scnprintf(hpp->buf, hpp->size, fmt, "sys"); 41 } 42 43 static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused) 44 { 45 return 7; 46 } 47 48 static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) 49 { 50 struct hists *hists = he->hists; 51 double percent = 100.0 * he->stat.period_sys / hists->stats.total_period; 52 53 return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); 54 } 55 56 static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) 57 { 58 struct hists *hists = he->hists; 59 double percent = 100.0 * he->stat.period_sys / hists->stats.total_period; 60 const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; 61 62 return scnprintf(hpp->buf, hpp->size, fmt, percent); 63 } 64 65 static int hpp__header_overhead_us(struct perf_hpp *hpp) 66 { 67 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; 68 69 return scnprintf(hpp->buf, hpp->size, fmt, "user"); 70 } 71 72 static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused) 73 { 74 return 7; 75 } 76 77 static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) 78 { 79 struct hists *hists = he->hists; 80 double percent = 100.0 * he->stat.period_us / hists->stats.total_period; 81 82 return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); 83 } 84 85 static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) 86 { 87 struct hists *hists = he->hists; 88 double percent = 100.0 * he->stat.period_us / hists->stats.total_period; 89 const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; 90 91 return scnprintf(hpp->buf, hpp->size, fmt, percent); 92 } 93 94 static int hpp__header_overhead_guest_sys(struct perf_hpp *hpp) 95 { 96 return scnprintf(hpp->buf, hpp->size, "guest sys"); 97 } 98 99 static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused) 100 { 101 return 9; 102 } 103 104 static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp, 105 struct hist_entry *he) 106 { 107 struct hists *hists = he->hists; 108 double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period; 109 110 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); 111 } 112 113 static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp, 114 struct hist_entry *he) 115 { 116 struct hists *hists = he->hists; 117 double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period; 118 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; 119 120 return scnprintf(hpp->buf, hpp->size, fmt, percent); 121 } 122 123 static int hpp__header_overhead_guest_us(struct perf_hpp *hpp) 124 { 125 return scnprintf(hpp->buf, hpp->size, "guest usr"); 126 } 127 128 static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused) 129 { 130 return 9; 131 } 132 133 static int hpp__color_overhead_guest_us(struct perf_hpp *hpp, 134 struct hist_entry *he) 135 { 136 struct hists *hists = he->hists; 137 double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period; 138 139 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); 140 } 141 142 static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp, 143 struct hist_entry *he) 144 { 145 struct hists *hists = he->hists; 146 double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period; 147 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; 148 149 return scnprintf(hpp->buf, hpp->size, fmt, percent); 150 } 151 152 static int hpp__header_baseline(struct perf_hpp *hpp) 153 { 154 return scnprintf(hpp->buf, hpp->size, "Baseline"); 155 } 156 157 static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused) 158 { 159 return 8; 160 } 161 162 static double baseline_percent(struct hist_entry *he) 163 { 164 struct hist_entry *pair = he->pair; 165 struct hists *pair_hists = pair ? pair->hists : NULL; 166 double percent = 0.0; 167 168 if (pair) { 169 u64 total_period = pair_hists->stats.total_period; 170 u64 base_period = pair->stat.period; 171 172 percent = 100.0 * base_period / total_period; 173 } 174 175 return percent; 176 } 177 178 static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he) 179 { 180 double percent = baseline_percent(he); 181 182 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); 183 } 184 185 static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he) 186 { 187 double percent = baseline_percent(he); 188 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; 189 190 return scnprintf(hpp->buf, hpp->size, fmt, percent); 191 } 192 193 static int hpp__header_samples(struct perf_hpp *hpp) 194 { 195 const char *fmt = symbol_conf.field_sep ? "%s" : "%11s"; 196 197 return scnprintf(hpp->buf, hpp->size, fmt, "Samples"); 198 } 199 200 static int hpp__width_samples(struct perf_hpp *hpp __maybe_unused) 201 { 202 return 11; 203 } 204 205 static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he) 206 { 207 const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64; 208 209 return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events); 210 } 211 212 static int hpp__header_period(struct perf_hpp *hpp) 213 { 214 const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; 215 216 return scnprintf(hpp->buf, hpp->size, fmt, "Period"); 217 } 218 219 static int hpp__width_period(struct perf_hpp *hpp __maybe_unused) 220 { 221 return 12; 222 } 223 224 static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he) 225 { 226 const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64; 227 228 return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period); 229 } 230 231 static int hpp__header_delta(struct perf_hpp *hpp) 232 { 233 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; 234 235 return scnprintf(hpp->buf, hpp->size, fmt, "Delta"); 236 } 237 238 static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused) 239 { 240 return 7; 241 } 242 243 static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) 244 { 245 struct hist_entry *pair = he->pair; 246 struct hists *pair_hists = pair ? pair->hists : NULL; 247 struct hists *hists = he->hists; 248 u64 old_total, new_total; 249 double old_percent = 0, new_percent = 0; 250 double diff; 251 const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; 252 char buf[32] = " "; 253 254 old_total = pair_hists ? pair_hists->stats.total_period : 0; 255 if (old_total > 0 && pair) 256 old_percent = 100.0 * pair->stat.period / old_total; 257 258 new_total = hists->stats.total_period; 259 if (new_total > 0) 260 new_percent = 100.0 * he->stat.period / new_total; 261 262 diff = new_percent - old_percent; 263 if (fabs(diff) >= 0.01) 264 scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); 265 266 return scnprintf(hpp->buf, hpp->size, fmt, buf); 267 } 268 269 static int hpp__header_displ(struct perf_hpp *hpp) 270 { 271 return scnprintf(hpp->buf, hpp->size, "Displ."); 272 } 273 274 static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused) 275 { 276 return 6; 277 } 278 279 static int hpp__entry_displ(struct perf_hpp *hpp, 280 struct hist_entry *he) 281 { 282 struct hist_entry *pair = he->pair; 283 long displacement = pair ? pair->position - he->position : 0; 284 const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s"; 285 char buf[32] = " "; 286 287 if (displacement) 288 scnprintf(buf, sizeof(buf), "%+4ld", displacement); 289 290 return scnprintf(hpp->buf, hpp->size, fmt, buf); 291 } 292 293 #define HPP__COLOR_PRINT_FNS(_name) \ 294 .header = hpp__header_ ## _name, \ 295 .width = hpp__width_ ## _name, \ 296 .color = hpp__color_ ## _name, \ 297 .entry = hpp__entry_ ## _name 298 299 #define HPP__PRINT_FNS(_name) \ 300 .header = hpp__header_ ## _name, \ 301 .width = hpp__width_ ## _name, \ 302 .entry = hpp__entry_ ## _name 303 304 struct perf_hpp_fmt perf_hpp__format[] = { 305 { .cond = false, HPP__COLOR_PRINT_FNS(baseline) }, 306 { .cond = true, HPP__COLOR_PRINT_FNS(overhead) }, 307 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) }, 308 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) }, 309 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_sys) }, 310 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) }, 311 { .cond = false, HPP__PRINT_FNS(samples) }, 312 { .cond = false, HPP__PRINT_FNS(period) }, 313 { .cond = false, HPP__PRINT_FNS(delta) }, 314 { .cond = false, HPP__PRINT_FNS(displ) } 315 }; 316 317 #undef HPP__COLOR_PRINT_FNS 318 #undef HPP__PRINT_FNS 319 320 void perf_hpp__init(void) 321 { 322 if (symbol_conf.show_cpu_utilization) { 323 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true; 324 perf_hpp__format[PERF_HPP__OVERHEAD_US].cond = true; 325 326 if (perf_guest) { 327 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].cond = true; 328 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].cond = true; 329 } 330 } 331 332 if (symbol_conf.show_nr_samples) 333 perf_hpp__format[PERF_HPP__SAMPLES].cond = true; 334 335 if (symbol_conf.show_total_period) 336 perf_hpp__format[PERF_HPP__PERIOD].cond = true; 337 } 338 339 void perf_hpp__column_enable(unsigned col, bool enable) 340 { 341 BUG_ON(col >= PERF_HPP__MAX_INDEX); 342 perf_hpp__format[col].cond = enable; 343 } 344 345 static inline void advance_hpp(struct perf_hpp *hpp, int inc) 346 { 347 hpp->buf += inc; 348 hpp->size -= inc; 349 } 350 351 int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, 352 bool color) 353 { 354 const char *sep = symbol_conf.field_sep; 355 char *start = hpp->buf; 356 int i, ret; 357 bool first = true; 358 359 if (symbol_conf.exclude_other && !he->parent) 360 return 0; 361 362 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { 363 if (!perf_hpp__format[i].cond) 364 continue; 365 366 if (!sep || !first) { 367 ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); 368 advance_hpp(hpp, ret); 369 first = false; 370 } 371 372 if (color && perf_hpp__format[i].color) 373 ret = perf_hpp__format[i].color(hpp, he); 374 else 375 ret = perf_hpp__format[i].entry(hpp, he); 376 377 advance_hpp(hpp, ret); 378 } 379 380 return hpp->buf - start; 381 } 382 383 int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, 384 struct hists *hists) 385 { 386 const char *sep = symbol_conf.field_sep; 387 struct sort_entry *se; 388 int ret = 0; 389 390 list_for_each_entry(se, &hist_entry__sort_list, list) { 391 if (se->elide) 392 continue; 393 394 ret += scnprintf(s + ret, size - ret, "%s", sep ?: " "); 395 ret += se->se_snprintf(he, s + ret, size - ret, 396 hists__col_len(hists, se->se_width_idx)); 397 } 398 399 return ret; 400 } 401 402 /* 403 * See hists__fprintf to match the column widths 404 */ 405 unsigned int hists__sort_list_width(struct hists *hists) 406 { 407 struct sort_entry *se; 408 int i, ret = 0; 409 410 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { 411 if (!perf_hpp__format[i].cond) 412 continue; 413 if (i) 414 ret += 2; 415 416 ret += perf_hpp__format[i].width(NULL); 417 } 418 419 list_for_each_entry(se, &hist_entry__sort_list, list) 420 if (!se->elide) 421 ret += 2 + hists__col_len(hists, se->se_width_idx); 422 423 if (verbose) /* Addr + origin */ 424 ret += 3 + BITS_PER_LONG / 4; 425 426 return ret; 427 } 428