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 = hist_entry__next_pair(he); 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 if (hist_entry__has_pairs(he)) 183 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); 184 else 185 return scnprintf(hpp->buf, hpp->size, " "); 186 } 187 188 static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he) 189 { 190 double percent = baseline_percent(he); 191 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; 192 193 if (hist_entry__has_pairs(he) || symbol_conf.field_sep) 194 return scnprintf(hpp->buf, hpp->size, fmt, percent); 195 else 196 return scnprintf(hpp->buf, hpp->size, " "); 197 } 198 199 static int hpp__header_samples(struct perf_hpp *hpp) 200 { 201 const char *fmt = symbol_conf.field_sep ? "%s" : "%11s"; 202 203 return scnprintf(hpp->buf, hpp->size, fmt, "Samples"); 204 } 205 206 static int hpp__width_samples(struct perf_hpp *hpp __maybe_unused) 207 { 208 return 11; 209 } 210 211 static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he) 212 { 213 const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64; 214 215 return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events); 216 } 217 218 static int hpp__header_period(struct perf_hpp *hpp) 219 { 220 const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; 221 222 return scnprintf(hpp->buf, hpp->size, fmt, "Period"); 223 } 224 225 static int hpp__width_period(struct perf_hpp *hpp __maybe_unused) 226 { 227 return 12; 228 } 229 230 static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he) 231 { 232 const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64; 233 234 return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period); 235 } 236 237 static int hpp__header_period_baseline(struct perf_hpp *hpp) 238 { 239 const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; 240 241 return scnprintf(hpp->buf, hpp->size, fmt, "Period Base"); 242 } 243 244 static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused) 245 { 246 return 12; 247 } 248 249 static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *he) 250 { 251 struct hist_entry *pair = hist_entry__next_pair(he); 252 u64 period = pair ? pair->stat.period : 0; 253 const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64; 254 255 return scnprintf(hpp->buf, hpp->size, fmt, period); 256 } 257 static int hpp__header_delta(struct perf_hpp *hpp) 258 { 259 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; 260 261 return scnprintf(hpp->buf, hpp->size, fmt, "Delta"); 262 } 263 264 static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused) 265 { 266 return 7; 267 } 268 269 static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) 270 { 271 const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; 272 char buf[32] = " "; 273 double diff; 274 275 if (he->diff.computed) 276 diff = he->diff.period_ratio_delta; 277 else 278 diff = perf_diff__compute_delta(he); 279 280 if (fabs(diff) >= 0.01) 281 scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); 282 283 return scnprintf(hpp->buf, hpp->size, fmt, buf); 284 } 285 286 static int hpp__header_ratio(struct perf_hpp *hpp) 287 { 288 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; 289 290 return scnprintf(hpp->buf, hpp->size, fmt, "Ratio"); 291 } 292 293 static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused) 294 { 295 return 14; 296 } 297 298 static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) 299 { 300 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; 301 char buf[32] = " "; 302 double ratio; 303 304 if (he->diff.computed) 305 ratio = he->diff.period_ratio; 306 else 307 ratio = perf_diff__compute_ratio(he); 308 309 if (ratio > 0.0) 310 scnprintf(buf, sizeof(buf), "%+14.6F", ratio); 311 312 return scnprintf(hpp->buf, hpp->size, fmt, buf); 313 } 314 315 static int hpp__header_wdiff(struct perf_hpp *hpp) 316 { 317 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; 318 319 return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff"); 320 } 321 322 static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused) 323 { 324 return 14; 325 } 326 327 static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) 328 { 329 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; 330 char buf[32] = " "; 331 s64 wdiff; 332 333 if (he->diff.computed) 334 wdiff = he->diff.wdiff; 335 else 336 wdiff = perf_diff__compute_wdiff(he); 337 338 if (wdiff != 0) 339 scnprintf(buf, sizeof(buf), "%14ld", wdiff); 340 341 return scnprintf(hpp->buf, hpp->size, fmt, buf); 342 } 343 344 static int hpp__header_displ(struct perf_hpp *hpp) 345 { 346 return scnprintf(hpp->buf, hpp->size, "Displ."); 347 } 348 349 static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused) 350 { 351 return 6; 352 } 353 354 static int hpp__entry_displ(struct perf_hpp *hpp, 355 struct hist_entry *he) 356 { 357 struct hist_entry *pair = hist_entry__next_pair(he); 358 long displacement = pair ? pair->position - he->position : 0; 359 const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s"; 360 char buf[32] = " "; 361 362 if (displacement) 363 scnprintf(buf, sizeof(buf), "%+4ld", displacement); 364 365 return scnprintf(hpp->buf, hpp->size, fmt, buf); 366 } 367 368 static int hpp__header_formula(struct perf_hpp *hpp) 369 { 370 const char *fmt = symbol_conf.field_sep ? "%s" : "%70s"; 371 372 return scnprintf(hpp->buf, hpp->size, fmt, "Formula"); 373 } 374 375 static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused) 376 { 377 return 70; 378 } 379 380 static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) 381 { 382 const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s"; 383 char buf[96] = " "; 384 385 perf_diff__formula(buf, sizeof(buf), he); 386 return scnprintf(hpp->buf, hpp->size, fmt, buf); 387 } 388 389 #define HPP__COLOR_PRINT_FNS(_name) \ 390 .header = hpp__header_ ## _name, \ 391 .width = hpp__width_ ## _name, \ 392 .color = hpp__color_ ## _name, \ 393 .entry = hpp__entry_ ## _name 394 395 #define HPP__PRINT_FNS(_name) \ 396 .header = hpp__header_ ## _name, \ 397 .width = hpp__width_ ## _name, \ 398 .entry = hpp__entry_ ## _name 399 400 struct perf_hpp_fmt perf_hpp__format[] = { 401 { .cond = false, HPP__COLOR_PRINT_FNS(baseline) }, 402 { .cond = true, HPP__COLOR_PRINT_FNS(overhead) }, 403 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) }, 404 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) }, 405 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_sys) }, 406 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) }, 407 { .cond = false, HPP__PRINT_FNS(samples) }, 408 { .cond = false, HPP__PRINT_FNS(period) }, 409 { .cond = false, HPP__PRINT_FNS(period_baseline) }, 410 { .cond = false, HPP__PRINT_FNS(delta) }, 411 { .cond = false, HPP__PRINT_FNS(ratio) }, 412 { .cond = false, HPP__PRINT_FNS(wdiff) }, 413 { .cond = false, HPP__PRINT_FNS(displ) }, 414 { .cond = false, HPP__PRINT_FNS(formula) } 415 }; 416 417 #undef HPP__COLOR_PRINT_FNS 418 #undef HPP__PRINT_FNS 419 420 void perf_hpp__init(void) 421 { 422 if (symbol_conf.show_cpu_utilization) { 423 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true; 424 perf_hpp__format[PERF_HPP__OVERHEAD_US].cond = true; 425 426 if (perf_guest) { 427 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].cond = true; 428 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].cond = true; 429 } 430 } 431 432 if (symbol_conf.show_nr_samples) 433 perf_hpp__format[PERF_HPP__SAMPLES].cond = true; 434 435 if (symbol_conf.show_total_period) 436 perf_hpp__format[PERF_HPP__PERIOD].cond = true; 437 } 438 439 void perf_hpp__column_enable(unsigned col, bool enable) 440 { 441 BUG_ON(col >= PERF_HPP__MAX_INDEX); 442 perf_hpp__format[col].cond = enable; 443 } 444 445 static inline void advance_hpp(struct perf_hpp *hpp, int inc) 446 { 447 hpp->buf += inc; 448 hpp->size -= inc; 449 } 450 451 int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, 452 bool color) 453 { 454 const char *sep = symbol_conf.field_sep; 455 char *start = hpp->buf; 456 int i, ret; 457 bool first = true; 458 459 if (symbol_conf.exclude_other && !he->parent) 460 return 0; 461 462 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { 463 if (!perf_hpp__format[i].cond) 464 continue; 465 466 if (!sep || !first) { 467 ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); 468 advance_hpp(hpp, ret); 469 first = false; 470 } 471 472 if (color && perf_hpp__format[i].color) 473 ret = perf_hpp__format[i].color(hpp, he); 474 else 475 ret = perf_hpp__format[i].entry(hpp, he); 476 477 advance_hpp(hpp, ret); 478 } 479 480 return hpp->buf - start; 481 } 482 483 int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, 484 struct hists *hists) 485 { 486 const char *sep = symbol_conf.field_sep; 487 struct sort_entry *se; 488 int ret = 0; 489 490 list_for_each_entry(se, &hist_entry__sort_list, list) { 491 if (se->elide) 492 continue; 493 494 ret += scnprintf(s + ret, size - ret, "%s", sep ?: " "); 495 ret += se->se_snprintf(he, s + ret, size - ret, 496 hists__col_len(hists, se->se_width_idx)); 497 } 498 499 return ret; 500 } 501 502 /* 503 * See hists__fprintf to match the column widths 504 */ 505 unsigned int hists__sort_list_width(struct hists *hists) 506 { 507 struct sort_entry *se; 508 int i, ret = 0; 509 510 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { 511 if (!perf_hpp__format[i].cond) 512 continue; 513 if (i) 514 ret += 2; 515 516 ret += perf_hpp__format[i].width(NULL); 517 } 518 519 list_for_each_entry(se, &hist_entry__sort_list, list) 520 if (!se->elide) 521 ret += 2 + hists__col_len(hists, se->se_width_idx); 522 523 if (verbose) /* Addr + origin */ 524 ret += 3 + BITS_PER_LONG / 4; 525 526 return ret; 527 } 528