1 // SPDX-License-Identifier: GPL-2.0 2 #include <inttypes.h> 3 #include <math.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <linux/compiler.h> 7 8 #include "../util/callchain.h" 9 #include "../util/debug.h" 10 #include "../util/hist.h" 11 #include "../util/sort.h" 12 #include "../util/evsel.h" 13 #include "../util/evlist.h" 14 #include "../util/mem-events.h" 15 #include "../util/string2.h" 16 #include "../util/thread.h" 17 #include "../util/util.h" 18 19 /* hist period print (hpp) functions */ 20 21 #define hpp__call_print_fn(hpp, fn, fmt, ...) \ 22 ({ \ 23 int __ret = fn(hpp, fmt, ##__VA_ARGS__); \ 24 advance_hpp(hpp, __ret); \ 25 __ret; \ 26 }) 27 28 static int __hpp__fmt_print(struct perf_hpp *hpp, struct hists *hists, u64 val, 29 int nr_samples, const char *fmt, int len, 30 hpp_snprint_fn print_fn, enum perf_hpp_fmt_type fmtype) 31 { 32 if (fmtype == PERF_HPP_FMT_TYPE__PERCENT || fmtype == PERF_HPP_FMT_TYPE__LATENCY) { 33 double percent = 0.0; 34 u64 total = fmtype == PERF_HPP_FMT_TYPE__PERCENT ? hists__total_period(hists) : 35 hists__total_latency(hists); 36 37 if (total) 38 percent = 100.0 * val / total; 39 40 return hpp__call_print_fn(hpp, print_fn, fmt, len, percent); 41 } 42 43 if (fmtype == PERF_HPP_FMT_TYPE__AVERAGE) { 44 double avg = nr_samples ? (1.0 * val / nr_samples) : 0; 45 46 return hpp__call_print_fn(hpp, print_fn, fmt, len, avg); 47 } 48 49 return hpp__call_print_fn(hpp, print_fn, fmt, len, val); 50 } 51 52 struct hpp_fmt_value { 53 struct hists *hists; 54 u64 val; 55 int samples; 56 }; 57 58 static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, 59 hpp_field_fn get_field, const char *fmt, int len, 60 hpp_snprint_fn print_fn, enum perf_hpp_fmt_type fmtype) 61 { 62 int ret = 0; 63 struct hists *hists = he->hists; 64 struct evsel *evsel = hists_to_evsel(hists); 65 struct evsel *pos; 66 char *buf = hpp->buf; 67 size_t size = hpp->size; 68 int i = 0, nr_members = 1; 69 struct hpp_fmt_value *values; 70 71 if (evsel__is_group_event(evsel)) 72 nr_members = evsel->core.nr_members; 73 74 values = calloc(nr_members, sizeof(*values)); 75 if (values == NULL) 76 return 0; 77 78 values[0].hists = evsel__hists(evsel); 79 values[0].val = get_field(he); 80 values[0].samples = he->stat.nr_events; 81 82 if (evsel__is_group_event(evsel)) { 83 struct hist_entry *pair; 84 85 for_each_group_member(pos, evsel) 86 values[++i].hists = evsel__hists(pos); 87 88 list_for_each_entry(pair, &he->pairs.head, pairs.node) { 89 for (i = 0; i < nr_members; i++) { 90 if (values[i].hists != pair->hists) 91 continue; 92 93 values[i].val = get_field(pair); 94 values[i].samples = pair->stat.nr_events; 95 break; 96 } 97 } 98 } 99 100 for (i = 0; i < nr_members; i++) { 101 if (symbol_conf.skip_empty && 102 values[i].hists->stats.nr_samples == 0) 103 continue; 104 105 ret += __hpp__fmt_print(hpp, values[i].hists, values[i].val, 106 values[i].samples, fmt, len, 107 print_fn, fmtype); 108 } 109 110 free(values); 111 112 /* 113 * Restore original buf and size as it's where caller expects 114 * the result will be saved. 115 */ 116 hpp->buf = buf; 117 hpp->size = size; 118 119 return ret; 120 } 121 122 int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 123 struct hist_entry *he, hpp_field_fn get_field, 124 const char *fmtstr, hpp_snprint_fn print_fn, 125 enum perf_hpp_fmt_type fmtype) 126 { 127 int len = max(fmt->user_len ?: fmt->len, (int)strlen(fmt->name)); 128 129 if (symbol_conf.field_sep) { 130 return __hpp__fmt(hpp, he, get_field, fmtstr, 1, 131 print_fn, fmtype); 132 } 133 134 if (fmtype == PERF_HPP_FMT_TYPE__PERCENT || fmtype == PERF_HPP_FMT_TYPE__LATENCY) 135 len -= 2; /* 2 for a space and a % sign */ 136 else 137 len -= 1; 138 139 return __hpp__fmt(hpp, he, get_field, fmtstr, len, print_fn, fmtype); 140 } 141 142 int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 143 struct hist_entry *he, hpp_field_fn get_field, 144 const char *fmtstr, hpp_snprint_fn print_fn, 145 enum perf_hpp_fmt_type fmtype) 146 { 147 if (!symbol_conf.cumulate_callchain) { 148 int len = fmt->user_len ?: fmt->len; 149 return snprintf(hpp->buf, hpp->size, " %*s", len - 1, "N/A"); 150 } 151 152 return hpp__fmt(fmt, hpp, he, get_field, fmtstr, print_fn, fmtype); 153 } 154 155 int hpp__fmt_mem_stat(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp, 156 struct hist_entry *he, enum mem_stat_type mst, 157 const char *fmtstr, hpp_snprint_fn print_fn) 158 { 159 struct hists *hists = he->hists; 160 int mem_stat_idx = -1; 161 char *buf = hpp->buf; 162 size_t size = hpp->size; 163 u64 total = 0; 164 int ret = 0; 165 166 for (int i = 0; i < hists->nr_mem_stats; i++) { 167 if (hists->mem_stat_types[i] == mst) { 168 mem_stat_idx = i; 169 break; 170 } 171 } 172 assert(mem_stat_idx != -1); 173 174 for (int i = 0; i < MEM_STAT_LEN; i++) 175 total += he->mem_stat[mem_stat_idx].entries[i]; 176 assert(total != 0); 177 178 for (int i = 0; i < MEM_STAT_LEN; i++) { 179 u64 val = he->mem_stat[mem_stat_idx].entries[i]; 180 181 if (hists->mem_stat_total[mem_stat_idx].entries[i] == 0) 182 continue; 183 184 ret += hpp__call_print_fn(hpp, print_fn, fmtstr, 100.0 * val / total); 185 } 186 187 /* 188 * Restore original buf and size as it's where caller expects 189 * the result will be saved. 190 */ 191 hpp->buf = buf; 192 hpp->size = size; 193 194 return ret; 195 } 196 197 static int field_cmp(u64 field_a, u64 field_b) 198 { 199 if (field_a > field_b) 200 return 1; 201 if (field_a < field_b) 202 return -1; 203 return 0; 204 } 205 206 static int hist_entry__new_pair(struct hist_entry *a, struct hist_entry *b, 207 hpp_field_fn get_field, int nr_members, 208 u64 **fields_a, u64 **fields_b) 209 { 210 u64 *fa = calloc(nr_members, sizeof(*fa)), 211 *fb = calloc(nr_members, sizeof(*fb)); 212 struct hist_entry *pair; 213 214 if (!fa || !fb) 215 goto out_free; 216 217 list_for_each_entry(pair, &a->pairs.head, pairs.node) { 218 struct evsel *evsel = hists_to_evsel(pair->hists); 219 fa[evsel__group_idx(evsel)] = get_field(pair); 220 } 221 222 list_for_each_entry(pair, &b->pairs.head, pairs.node) { 223 struct evsel *evsel = hists_to_evsel(pair->hists); 224 fb[evsel__group_idx(evsel)] = get_field(pair); 225 } 226 227 *fields_a = fa; 228 *fields_b = fb; 229 return 0; 230 out_free: 231 free(fa); 232 free(fb); 233 *fields_a = *fields_b = NULL; 234 return -1; 235 } 236 237 static int __hpp__group_sort_idx(struct hist_entry *a, struct hist_entry *b, 238 hpp_field_fn get_field, int idx) 239 { 240 struct evsel *evsel = hists_to_evsel(a->hists); 241 u64 *fields_a, *fields_b; 242 int cmp, nr_members, ret, i; 243 244 cmp = field_cmp(get_field(a), get_field(b)); 245 if (!evsel__is_group_event(evsel)) 246 return cmp; 247 248 nr_members = evsel->core.nr_members; 249 if (idx < 1 || idx >= nr_members) 250 return cmp; 251 252 ret = hist_entry__new_pair(a, b, get_field, nr_members, &fields_a, &fields_b); 253 if (ret) { 254 ret = cmp; 255 goto out; 256 } 257 258 ret = field_cmp(fields_a[idx], fields_b[idx]); 259 if (ret) 260 goto out; 261 262 for (i = 1; i < nr_members; i++) { 263 if (i != idx) { 264 ret = field_cmp(fields_a[i], fields_b[i]); 265 if (ret) 266 goto out; 267 } 268 } 269 270 out: 271 free(fields_a); 272 free(fields_b); 273 274 return ret; 275 } 276 277 static int __hpp__sort(struct hist_entry *a, struct hist_entry *b, 278 hpp_field_fn get_field) 279 { 280 s64 ret; 281 int i, nr_members; 282 struct evsel *evsel; 283 u64 *fields_a, *fields_b; 284 285 if (symbol_conf.group_sort_idx && symbol_conf.event_group) { 286 return __hpp__group_sort_idx(a, b, get_field, 287 symbol_conf.group_sort_idx); 288 } 289 290 ret = field_cmp(get_field(a), get_field(b)); 291 if (ret || !symbol_conf.event_group) 292 return ret; 293 294 evsel = hists_to_evsel(a->hists); 295 if (!evsel__is_group_event(evsel)) 296 return ret; 297 298 nr_members = evsel->core.nr_members; 299 i = hist_entry__new_pair(a, b, get_field, nr_members, &fields_a, &fields_b); 300 if (i) 301 goto out; 302 303 for (i = 1; i < nr_members; i++) { 304 ret = field_cmp(fields_a[i], fields_b[i]); 305 if (ret) 306 break; 307 } 308 309 out: 310 free(fields_a); 311 free(fields_b); 312 313 return ret; 314 } 315 316 static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b, 317 hpp_field_fn get_field) 318 { 319 s64 ret = 0; 320 321 if (symbol_conf.cumulate_callchain) { 322 /* 323 * Put caller above callee when they have equal period. 324 */ 325 ret = field_cmp(get_field(a), get_field(b)); 326 if (ret) 327 return ret; 328 329 if ((a->thread == NULL ? NULL : RC_CHK_ACCESS(a->thread)) != 330 (b->thread == NULL ? NULL : RC_CHK_ACCESS(b->thread)) || 331 !hist_entry__has_callchains(a) || !symbol_conf.use_callchain) 332 return 0; 333 334 ret = b->callchain->max_depth - a->callchain->max_depth; 335 if (callchain_param.order == ORDER_CALLER) 336 ret = -ret; 337 } 338 return ret; 339 } 340 341 static bool perf_hpp__is_mem_stat_entry(struct perf_hpp_fmt *fmt); 342 343 static enum mem_stat_type hpp__mem_stat_type(struct perf_hpp_fmt *fmt) 344 { 345 if (!perf_hpp__is_mem_stat_entry(fmt)) 346 return -1; 347 348 switch (fmt->idx) { 349 case PERF_HPP__MEM_STAT_OP: 350 return PERF_MEM_STAT_OP; 351 case PERF_HPP__MEM_STAT_CACHE: 352 return PERF_MEM_STAT_CACHE; 353 case PERF_HPP__MEM_STAT_MEMORY: 354 return PERF_MEM_STAT_MEMORY; 355 case PERF_HPP__MEM_STAT_SNOOP: 356 return PERF_MEM_STAT_SNOOP; 357 default: 358 break; 359 } 360 pr_debug("Should not reach here\n"); 361 return -1; 362 } 363 364 static int64_t hpp__sort_mem_stat(struct perf_hpp_fmt *fmt __maybe_unused, 365 struct hist_entry *a, struct hist_entry *b) 366 { 367 return a->stat.period - b->stat.period; 368 } 369 370 static int hpp__width_fn(struct perf_hpp_fmt *fmt, 371 struct perf_hpp *hpp __maybe_unused, 372 struct hists *hists) 373 { 374 int len = fmt->user_len ?: fmt->len; 375 struct evsel *evsel = hists_to_evsel(hists); 376 377 if (symbol_conf.event_group) { 378 int nr = 0; 379 struct evsel *pos; 380 381 for_each_group_evsel(pos, evsel) { 382 if (!symbol_conf.skip_empty || 383 evsel__hists(pos)->stats.nr_samples) 384 nr++; 385 } 386 387 len = max(len, nr * fmt->len); 388 } 389 390 if (len < (int)strlen(fmt->name)) 391 len = strlen(fmt->name); 392 393 return len; 394 } 395 396 static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 397 struct hists *hists, int line, 398 int *span __maybe_unused) 399 { 400 int len = hpp__width_fn(fmt, hpp, hists); 401 const char *hdr = ""; 402 403 if (line == hists->hpp_list->nr_header_lines - 1) 404 hdr = fmt->name; 405 406 return scnprintf(hpp->buf, hpp->size, "%*s", len, hdr); 407 } 408 409 static int hpp__header_mem_stat_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 410 struct hists *hists, int line, 411 int *span __maybe_unused) 412 { 413 char *buf = hpp->buf; 414 int ret = 0; 415 int len; 416 enum mem_stat_type mst = hpp__mem_stat_type(fmt); 417 int mem_stat_idx = -1; 418 419 for (int i = 0; i < hists->nr_mem_stats; i++) { 420 if (hists->mem_stat_types[i] == mst) { 421 mem_stat_idx = i; 422 break; 423 } 424 } 425 assert(mem_stat_idx != -1); 426 427 if (line == 0) { 428 int left, right; 429 430 len = 0; 431 /* update fmt->len for acutally used columns only */ 432 for (int i = 0; i < MEM_STAT_LEN; i++) { 433 if (hists->mem_stat_total[mem_stat_idx].entries[i]) 434 len += MEM_STAT_PRINT_LEN; 435 } 436 fmt->len = len; 437 438 /* print header directly if single column only */ 439 if (len == MEM_STAT_PRINT_LEN) 440 return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name); 441 442 left = (len - strlen(fmt->name)) / 2 - 1; 443 right = len - left - strlen(fmt->name) - 2; 444 445 if (left < 0) 446 left = 0; 447 if (right < 0) 448 right = 0; 449 450 return scnprintf(hpp->buf, hpp->size, "%.*s %s %.*s", 451 left, graph_dotted_line, fmt->name, right, graph_dotted_line); 452 } 453 454 455 len = hpp->size; 456 for (int i = 0; i < MEM_STAT_LEN; i++) { 457 int printed; 458 459 if (hists->mem_stat_total[mem_stat_idx].entries[i] == 0) 460 continue; 461 462 printed = scnprintf(buf, len, "%*s", MEM_STAT_PRINT_LEN, 463 mem_stat_name(mst, i)); 464 ret += printed; 465 buf += printed; 466 len -= printed; 467 } 468 return ret; 469 } 470 471 int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...) 472 { 473 va_list args; 474 ssize_t ssize = hpp->size; 475 double percent; 476 int ret, len; 477 478 va_start(args, fmt); 479 len = va_arg(args, int); 480 percent = va_arg(args, double); 481 ret = percent_color_len_snprintf(hpp->buf, hpp->size, fmt, len, percent); 482 va_end(args); 483 484 return (ret >= ssize) ? (ssize - 1) : ret; 485 } 486 487 static int hpp_entry_scnprintf(struct perf_hpp *hpp, const char *fmt, ...) 488 { 489 va_list args; 490 ssize_t ssize = hpp->size; 491 int ret; 492 493 va_start(args, fmt); 494 ret = vsnprintf(hpp->buf, hpp->size, fmt, args); 495 va_end(args); 496 497 return (ret >= ssize) ? (ssize - 1) : ret; 498 } 499 500 #define __HPP_COLOR_PERCENT_FN(_type, _field, _fmttype) \ 501 static u64 he_get_##_field(struct hist_entry *he) \ 502 { \ 503 return he->stat._field; \ 504 } \ 505 \ 506 static int hpp__color_##_type(struct perf_hpp_fmt *fmt, \ 507 struct perf_hpp *hpp, struct hist_entry *he) \ 508 { \ 509 return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \ 510 hpp_color_scnprintf, _fmttype); \ 511 } 512 513 #define __HPP_ENTRY_PERCENT_FN(_type, _field, _fmttype) \ 514 static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ 515 struct perf_hpp *hpp, struct hist_entry *he) \ 516 { \ 517 return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \ 518 hpp_entry_scnprintf, _fmttype); \ 519 } 520 521 #define __HPP_SORT_FN(_type, _field) \ 522 static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 523 struct hist_entry *a, struct hist_entry *b) \ 524 { \ 525 return __hpp__sort(a, b, he_get_##_field); \ 526 } 527 528 #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field, _fmttype) \ 529 static u64 he_get_acc_##_field(struct hist_entry *he) \ 530 { \ 531 return he->stat_acc->_field; \ 532 } \ 533 \ 534 static int hpp__color_##_type(struct perf_hpp_fmt *fmt, \ 535 struct perf_hpp *hpp, struct hist_entry *he) \ 536 { \ 537 return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \ 538 hpp_color_scnprintf, _fmttype); \ 539 } 540 541 #define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field, _fmttype) \ 542 static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ 543 struct perf_hpp *hpp, struct hist_entry *he) \ 544 { \ 545 return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \ 546 hpp_entry_scnprintf, _fmttype); \ 547 } 548 549 #define __HPP_SORT_ACC_FN(_type, _field) \ 550 static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 551 struct hist_entry *a, struct hist_entry *b) \ 552 { \ 553 return __hpp__sort_acc(a, b, he_get_acc_##_field); \ 554 } 555 556 #define __HPP_ENTRY_RAW_FN(_type, _field) \ 557 static u64 he_get_raw_##_field(struct hist_entry *he) \ 558 { \ 559 return he->stat._field; \ 560 } \ 561 \ 562 static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ 563 struct perf_hpp *hpp, struct hist_entry *he) \ 564 { \ 565 return hpp__fmt(fmt, hpp, he, he_get_raw_##_field, " %*"PRIu64, \ 566 hpp_entry_scnprintf, PERF_HPP_FMT_TYPE__RAW); \ 567 } 568 569 #define __HPP_SORT_RAW_FN(_type, _field) \ 570 static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 571 struct hist_entry *a, struct hist_entry *b) \ 572 { \ 573 return __hpp__sort(a, b, he_get_raw_##_field); \ 574 } 575 576 #define __HPP_ENTRY_AVERAGE_FN(_type, _field) \ 577 static u64 he_get_##_field(struct hist_entry *he) \ 578 { \ 579 return he->stat._field; \ 580 } \ 581 \ 582 static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ 583 struct perf_hpp *hpp, struct hist_entry *he) \ 584 { \ 585 return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.1f", \ 586 hpp_entry_scnprintf, PERF_HPP_FMT_TYPE__AVERAGE); \ 587 } 588 589 #define __HPP_SORT_AVERAGE_FN(_type, _field) \ 590 static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 591 struct hist_entry *a, struct hist_entry *b) \ 592 { \ 593 return __hpp__sort(a, b, he_get_##_field); \ 594 } 595 596 #define __HPP_COLOR_MEM_STAT_FN(_name, _type) \ 597 static int hpp__color_mem_stat_##_name(struct perf_hpp_fmt *fmt, \ 598 struct perf_hpp *hpp, \ 599 struct hist_entry *he) \ 600 { \ 601 return hpp__fmt_mem_stat(fmt, hpp, he, PERF_MEM_STAT_##_type, \ 602 " %5.1f%%", hpp_color_scnprintf); \ 603 } 604 605 #define __HPP_ENTRY_MEM_STAT_FN(_name, _type) \ 606 static int hpp__entry_mem_stat_##_name(struct perf_hpp_fmt *fmt, \ 607 struct perf_hpp *hpp, \ 608 struct hist_entry *he) \ 609 { \ 610 return hpp__fmt_mem_stat(fmt, hpp, he, PERF_MEM_STAT_##_type, \ 611 " %5.1f%%", hpp_entry_scnprintf); \ 612 } 613 614 #define HPP_PERCENT_FNS(_type, _field, _fmttype) \ 615 __HPP_COLOR_PERCENT_FN(_type, _field, _fmttype) \ 616 __HPP_ENTRY_PERCENT_FN(_type, _field, _fmttype) \ 617 __HPP_SORT_FN(_type, _field) 618 619 #define HPP_PERCENT_ACC_FNS(_type, _field, _fmttype) \ 620 __HPP_COLOR_ACC_PERCENT_FN(_type, _field, _fmttype) \ 621 __HPP_ENTRY_ACC_PERCENT_FN(_type, _field, _fmttype) \ 622 __HPP_SORT_ACC_FN(_type, _field) 623 624 #define HPP_RAW_FNS(_type, _field) \ 625 __HPP_ENTRY_RAW_FN(_type, _field) \ 626 __HPP_SORT_RAW_FN(_type, _field) 627 628 #define HPP_AVERAGE_FNS(_type, _field) \ 629 __HPP_ENTRY_AVERAGE_FN(_type, _field) \ 630 __HPP_SORT_AVERAGE_FN(_type, _field) 631 632 #define HPP_MEM_STAT_FNS(_name, _type) \ 633 __HPP_COLOR_MEM_STAT_FN(_name, _type) \ 634 __HPP_ENTRY_MEM_STAT_FN(_name, _type) 635 636 HPP_PERCENT_FNS(overhead, period, PERF_HPP_FMT_TYPE__PERCENT) 637 HPP_PERCENT_FNS(latency, latency, PERF_HPP_FMT_TYPE__LATENCY) 638 HPP_PERCENT_FNS(overhead_sys, period_sys, PERF_HPP_FMT_TYPE__PERCENT) 639 HPP_PERCENT_FNS(overhead_us, period_us, PERF_HPP_FMT_TYPE__PERCENT) 640 HPP_PERCENT_FNS(overhead_guest_sys, period_guest_sys, PERF_HPP_FMT_TYPE__PERCENT) 641 HPP_PERCENT_FNS(overhead_guest_us, period_guest_us, PERF_HPP_FMT_TYPE__PERCENT) 642 HPP_PERCENT_ACC_FNS(overhead_acc, period, PERF_HPP_FMT_TYPE__PERCENT) 643 HPP_PERCENT_ACC_FNS(latency_acc, latency, PERF_HPP_FMT_TYPE__LATENCY) 644 645 HPP_RAW_FNS(samples, nr_events) 646 HPP_RAW_FNS(period, period) 647 648 HPP_AVERAGE_FNS(weight1, weight1) 649 HPP_AVERAGE_FNS(weight2, weight2) 650 HPP_AVERAGE_FNS(weight3, weight3) 651 652 HPP_MEM_STAT_FNS(op, OP) 653 HPP_MEM_STAT_FNS(cache, CACHE) 654 HPP_MEM_STAT_FNS(memory, MEMORY) 655 HPP_MEM_STAT_FNS(snoop, SNOOP) 656 657 static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused, 658 struct hist_entry *a __maybe_unused, 659 struct hist_entry *b __maybe_unused) 660 { 661 return 0; 662 } 663 664 static bool perf_hpp__is_mem_stat_entry(struct perf_hpp_fmt *fmt) 665 { 666 return fmt->sort == hpp__sort_mem_stat; 667 } 668 669 static bool perf_hpp__is_hpp_entry(struct perf_hpp_fmt *a) 670 { 671 return a->header == hpp__header_fn; 672 } 673 674 static bool hpp__equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) 675 { 676 if (!perf_hpp__is_hpp_entry(a) || !perf_hpp__is_hpp_entry(b)) 677 return false; 678 679 return a->idx == b->idx; 680 } 681 682 static bool hpp__equal_mem_stat(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) 683 { 684 if (!perf_hpp__is_mem_stat_entry(a) || !perf_hpp__is_mem_stat_entry(b)) 685 return false; 686 687 return a->entry == b->entry; 688 } 689 690 #define HPP__COLOR_PRINT_FNS(_name, _fn, _idx) \ 691 { \ 692 .name = _name, \ 693 .header = hpp__header_fn, \ 694 .width = hpp__width_fn, \ 695 .color = hpp__color_ ## _fn, \ 696 .entry = hpp__entry_ ## _fn, \ 697 .cmp = hpp__nop_cmp, \ 698 .collapse = hpp__nop_cmp, \ 699 .sort = hpp__sort_ ## _fn, \ 700 .idx = PERF_HPP__ ## _idx, \ 701 .equal = hpp__equal, \ 702 } 703 704 #define HPP__COLOR_ACC_PRINT_FNS(_name, _fn, _idx) \ 705 { \ 706 .name = _name, \ 707 .header = hpp__header_fn, \ 708 .width = hpp__width_fn, \ 709 .color = hpp__color_ ## _fn, \ 710 .entry = hpp__entry_ ## _fn, \ 711 .cmp = hpp__nop_cmp, \ 712 .collapse = hpp__nop_cmp, \ 713 .sort = hpp__sort_ ## _fn, \ 714 .idx = PERF_HPP__ ## _idx, \ 715 .equal = hpp__equal, \ 716 } 717 718 #define HPP__PRINT_FNS(_name, _fn, _idx) \ 719 { \ 720 .name = _name, \ 721 .header = hpp__header_fn, \ 722 .width = hpp__width_fn, \ 723 .entry = hpp__entry_ ## _fn, \ 724 .cmp = hpp__nop_cmp, \ 725 .collapse = hpp__nop_cmp, \ 726 .sort = hpp__sort_ ## _fn, \ 727 .idx = PERF_HPP__ ## _idx, \ 728 .equal = hpp__equal, \ 729 } 730 731 #define HPP__MEM_STAT_PRINT_FNS(_name, _fn, _type) \ 732 { \ 733 .name = _name, \ 734 .header = hpp__header_mem_stat_fn, \ 735 .width = hpp__width_fn, \ 736 .color = hpp__color_mem_stat_ ## _fn, \ 737 .entry = hpp__entry_mem_stat_ ## _fn, \ 738 .cmp = hpp__nop_cmp, \ 739 .collapse = hpp__nop_cmp, \ 740 .sort = hpp__sort_mem_stat, \ 741 .idx = PERF_HPP__MEM_STAT_ ## _type, \ 742 .equal = hpp__equal_mem_stat, \ 743 } 744 745 struct perf_hpp_fmt perf_hpp__format[] = { 746 HPP__COLOR_PRINT_FNS("Overhead", overhead, OVERHEAD), 747 HPP__COLOR_PRINT_FNS("Latency", latency, LATENCY), 748 HPP__COLOR_PRINT_FNS("sys", overhead_sys, OVERHEAD_SYS), 749 HPP__COLOR_PRINT_FNS("usr", overhead_us, OVERHEAD_US), 750 HPP__COLOR_PRINT_FNS("guest sys", overhead_guest_sys, OVERHEAD_GUEST_SYS), 751 HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us, OVERHEAD_GUEST_US), 752 HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc, OVERHEAD_ACC), 753 HPP__COLOR_ACC_PRINT_FNS("Latency", latency_acc, LATENCY_ACC), 754 HPP__PRINT_FNS("Samples", samples, SAMPLES), 755 HPP__PRINT_FNS("Period", period, PERIOD), 756 HPP__PRINT_FNS("Weight1", weight1, WEIGHT1), 757 HPP__PRINT_FNS("Weight2", weight2, WEIGHT2), 758 HPP__PRINT_FNS("Weight3", weight3, WEIGHT3), 759 HPP__MEM_STAT_PRINT_FNS("Mem Op", op, OP), 760 HPP__MEM_STAT_PRINT_FNS("Cache", cache, CACHE), 761 HPP__MEM_STAT_PRINT_FNS("Memory", memory, MEMORY), 762 HPP__MEM_STAT_PRINT_FNS("Snoop", snoop, SNOOP), 763 }; 764 765 struct perf_hpp_list perf_hpp_list = { 766 .fields = LIST_HEAD_INIT(perf_hpp_list.fields), 767 .sorts = LIST_HEAD_INIT(perf_hpp_list.sorts), 768 .nr_header_lines = 1, 769 }; 770 771 #undef HPP__COLOR_PRINT_FNS 772 #undef HPP__COLOR_ACC_PRINT_FNS 773 #undef HPP__PRINT_FNS 774 #undef HPP__MEM_STAT_PRINT_FNS 775 776 #undef HPP_PERCENT_FNS 777 #undef HPP_PERCENT_ACC_FNS 778 #undef HPP_RAW_FNS 779 #undef HPP_AVERAGE_FNS 780 #undef HPP_MEM_STAT_FNS 781 782 #undef __HPP_HEADER_FN 783 #undef __HPP_WIDTH_FN 784 #undef __HPP_COLOR_PERCENT_FN 785 #undef __HPP_ENTRY_PERCENT_FN 786 #undef __HPP_COLOR_ACC_PERCENT_FN 787 #undef __HPP_ENTRY_ACC_PERCENT_FN 788 #undef __HPP_ENTRY_RAW_FN 789 #undef __HPP_ENTRY_AVERAGE_FN 790 #undef __HPP_COLOR_MEM_STAT_FN 791 #undef __HPP_ENTRY_MEM_STAT_FN 792 793 #undef __HPP_SORT_FN 794 #undef __HPP_SORT_ACC_FN 795 #undef __HPP_SORT_RAW_FN 796 #undef __HPP_SORT_AVERAGE_FN 797 798 static void fmt_free(struct perf_hpp_fmt *fmt) 799 { 800 /* 801 * At this point fmt should be completely 802 * unhooked, if not it's a bug. 803 */ 804 BUG_ON(!list_empty(&fmt->list)); 805 BUG_ON(!list_empty(&fmt->sort_list)); 806 807 if (fmt->free) 808 fmt->free(fmt); 809 } 810 811 static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) 812 { 813 return a->equal && a->equal(a, b); 814 } 815 816 void perf_hpp__init(void) 817 { 818 int i; 819 820 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { 821 struct perf_hpp_fmt *fmt = &perf_hpp__format[i]; 822 823 INIT_LIST_HEAD(&fmt->list); 824 825 /* sort_list may be linked by setup_sorting() */ 826 if (fmt->sort_list.next == NULL) 827 INIT_LIST_HEAD(&fmt->sort_list); 828 } 829 830 /* 831 * If user specified field order, no need to setup default fields. 832 */ 833 if (is_strict_order(field_order)) 834 return; 835 836 /* 837 * Overhead and latency columns are added in setup_overhead(), 838 * so they are added implicitly here only if they were added 839 * by setup_overhead() before (have was_taken flag set). 840 * This is required because setup_overhead() has more complex 841 * logic, in particular it does not add "overhead" if user 842 * specified "latency" in sort order, and vise versa. 843 */ 844 if (symbol_conf.cumulate_callchain) { 845 /* 846 * Addition of fields is idempotent, so we add latency 847 * column twice to get desired order with simpler logic. 848 */ 849 if (symbol_conf.prefer_latency) 850 hpp_dimension__add_output(PERF_HPP__LATENCY_ACC, true); 851 hpp_dimension__add_output(PERF_HPP__OVERHEAD_ACC, true); 852 if (symbol_conf.enable_latency) 853 hpp_dimension__add_output(PERF_HPP__LATENCY_ACC, true); 854 perf_hpp__format[PERF_HPP__OVERHEAD].name = "Self"; 855 } 856 857 if (symbol_conf.prefer_latency) 858 hpp_dimension__add_output(PERF_HPP__LATENCY, true); 859 hpp_dimension__add_output(PERF_HPP__OVERHEAD, true); 860 if (symbol_conf.enable_latency) 861 hpp_dimension__add_output(PERF_HPP__LATENCY, true); 862 863 if (symbol_conf.show_cpu_utilization) { 864 hpp_dimension__add_output(PERF_HPP__OVERHEAD_SYS, false); 865 hpp_dimension__add_output(PERF_HPP__OVERHEAD_US, false); 866 867 if (perf_guest) { 868 hpp_dimension__add_output(PERF_HPP__OVERHEAD_GUEST_SYS, false); 869 hpp_dimension__add_output(PERF_HPP__OVERHEAD_GUEST_US, false); 870 } 871 } 872 873 if (symbol_conf.show_nr_samples) 874 hpp_dimension__add_output(PERF_HPP__SAMPLES, false); 875 876 if (symbol_conf.show_total_period) 877 hpp_dimension__add_output(PERF_HPP__PERIOD, false); 878 } 879 880 void perf_hpp_list__column_register(struct perf_hpp_list *list, 881 struct perf_hpp_fmt *format) 882 { 883 list_add_tail(&format->list, &list->fields); 884 } 885 886 void perf_hpp_list__register_sort_field(struct perf_hpp_list *list, 887 struct perf_hpp_fmt *format) 888 { 889 list_add_tail(&format->sort_list, &list->sorts); 890 } 891 892 void perf_hpp_list__prepend_sort_field(struct perf_hpp_list *list, 893 struct perf_hpp_fmt *format) 894 { 895 list_add(&format->sort_list, &list->sorts); 896 } 897 898 static void perf_hpp__column_unregister(struct perf_hpp_fmt *format) 899 { 900 list_del_init(&format->list); 901 list_del_init(&format->sort_list); 902 fmt_free(format); 903 } 904 905 void perf_hpp__cancel_cumulate(struct evlist *evlist) 906 { 907 struct perf_hpp_fmt *fmt, *acc, *ovh, *acc_lat, *tmp; 908 struct evsel *evsel; 909 910 if (is_strict_order(field_order)) 911 return; 912 913 ovh = &perf_hpp__format[PERF_HPP__OVERHEAD]; 914 acc = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC]; 915 acc_lat = &perf_hpp__format[PERF_HPP__LATENCY_ACC]; 916 917 perf_hpp_list__for_each_format_safe(&perf_hpp_list, fmt, tmp) { 918 if (fmt_equal(acc, fmt) || fmt_equal(acc_lat, fmt)) { 919 perf_hpp__column_unregister(fmt); 920 continue; 921 } 922 923 if (fmt_equal(ovh, fmt)) 924 fmt->name = "Overhead"; 925 } 926 927 evlist__for_each_entry(evlist, evsel) { 928 struct hists *hists = evsel__hists(evsel); 929 struct perf_hpp_list_node *node; 930 931 list_for_each_entry(node, &hists->hpp_formats, list) { 932 perf_hpp_list__for_each_format_safe(&node->hpp, fmt, tmp) { 933 if (fmt_equal(acc, fmt) || fmt_equal(acc_lat, fmt)) { 934 perf_hpp__column_unregister(fmt); 935 continue; 936 } 937 938 if (fmt_equal(ovh, fmt)) 939 fmt->name = "Overhead"; 940 } 941 } 942 } 943 } 944 945 void perf_hpp__cancel_latency(struct evlist *evlist) 946 { 947 struct perf_hpp_fmt *fmt, *lat, *acc, *tmp; 948 struct evsel *evsel; 949 950 if (is_strict_order(field_order)) 951 return; 952 if (sort_order && strstr(sort_order, "latency")) 953 return; 954 955 lat = &perf_hpp__format[PERF_HPP__LATENCY]; 956 acc = &perf_hpp__format[PERF_HPP__LATENCY_ACC]; 957 958 perf_hpp_list__for_each_format_safe(&perf_hpp_list, fmt, tmp) { 959 if (fmt_equal(lat, fmt) || fmt_equal(acc, fmt)) 960 perf_hpp__column_unregister(fmt); 961 } 962 963 evlist__for_each_entry(evlist, evsel) { 964 struct hists *hists = evsel__hists(evsel); 965 struct perf_hpp_list_node *node; 966 967 list_for_each_entry(node, &hists->hpp_formats, list) { 968 perf_hpp_list__for_each_format_safe(&node->hpp, fmt, tmp) { 969 if (fmt_equal(lat, fmt) || fmt_equal(acc, fmt)) 970 perf_hpp__column_unregister(fmt); 971 } 972 } 973 } 974 } 975 976 void perf_hpp__setup_output_field(struct perf_hpp_list *list) 977 { 978 struct perf_hpp_fmt *fmt; 979 980 /* append sort keys to output field */ 981 perf_hpp_list__for_each_sort_list(list, fmt) { 982 struct perf_hpp_fmt *pos; 983 984 /* skip sort-only fields ("sort_compute" in perf diff) */ 985 if (!fmt->entry && !fmt->color) 986 continue; 987 988 perf_hpp_list__for_each_format(list, pos) { 989 if (fmt_equal(fmt, pos)) 990 goto next; 991 } 992 993 perf_hpp__column_register(fmt); 994 next: 995 continue; 996 } 997 } 998 999 void perf_hpp__append_sort_keys(struct perf_hpp_list *list) 1000 { 1001 struct perf_hpp_fmt *fmt; 1002 1003 /* append output fields to sort keys */ 1004 perf_hpp_list__for_each_format(list, fmt) { 1005 struct perf_hpp_fmt *pos; 1006 1007 perf_hpp_list__for_each_sort_list(list, pos) { 1008 if (fmt_equal(fmt, pos)) 1009 goto next; 1010 } 1011 1012 perf_hpp__register_sort_field(fmt); 1013 next: 1014 continue; 1015 } 1016 } 1017 1018 1019 void perf_hpp__reset_output_field(struct perf_hpp_list *list) 1020 { 1021 struct perf_hpp_fmt *fmt, *tmp; 1022 1023 /* reset output fields */ 1024 perf_hpp_list__for_each_format_safe(list, fmt, tmp) 1025 perf_hpp__column_unregister(fmt); 1026 1027 /* reset sort keys */ 1028 perf_hpp_list__for_each_sort_list_safe(list, fmt, tmp) 1029 perf_hpp__column_unregister(fmt); 1030 } 1031 1032 /* 1033 * See hists__fprintf to match the column widths 1034 */ 1035 unsigned int hists__sort_list_width(struct hists *hists) 1036 { 1037 struct perf_hpp_fmt *fmt; 1038 int ret = 0; 1039 bool first = true; 1040 struct perf_hpp dummy_hpp; 1041 1042 hists__for_each_format(hists, fmt) { 1043 if (perf_hpp__should_skip(fmt, hists)) 1044 continue; 1045 1046 if (first) 1047 first = false; 1048 else 1049 ret += 2; 1050 1051 ret += fmt->width(fmt, &dummy_hpp, hists); 1052 } 1053 1054 if (verbose > 0 && hists__has(hists, sym)) /* Addr + origin */ 1055 ret += 3 + BITS_PER_LONG / 4; 1056 1057 return ret; 1058 } 1059 1060 unsigned int hists__overhead_width(struct hists *hists) 1061 { 1062 struct perf_hpp_fmt *fmt; 1063 int ret = 0; 1064 bool first = true; 1065 struct perf_hpp dummy_hpp; 1066 1067 hists__for_each_format(hists, fmt) { 1068 if (perf_hpp__is_sort_entry(fmt) || perf_hpp__is_dynamic_entry(fmt)) 1069 break; 1070 1071 if (first) 1072 first = false; 1073 else 1074 ret += 2; 1075 1076 ret += fmt->width(fmt, &dummy_hpp, hists); 1077 } 1078 1079 return ret; 1080 } 1081 1082 void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) 1083 { 1084 if (perf_hpp__is_sort_entry(fmt)) 1085 return perf_hpp__reset_sort_width(fmt, hists); 1086 1087 if (perf_hpp__is_dynamic_entry(fmt)) 1088 return; 1089 1090 BUG_ON(fmt->idx >= PERF_HPP__MAX_INDEX); 1091 1092 switch (fmt->idx) { 1093 case PERF_HPP__OVERHEAD: 1094 case PERF_HPP__LATENCY: 1095 case PERF_HPP__OVERHEAD_SYS: 1096 case PERF_HPP__OVERHEAD_US: 1097 case PERF_HPP__OVERHEAD_ACC: 1098 fmt->len = 8; 1099 break; 1100 1101 case PERF_HPP__OVERHEAD_GUEST_SYS: 1102 case PERF_HPP__OVERHEAD_GUEST_US: 1103 fmt->len = 9; 1104 break; 1105 1106 case PERF_HPP__SAMPLES: 1107 case PERF_HPP__PERIOD: 1108 fmt->len = 12; 1109 break; 1110 1111 case PERF_HPP__WEIGHT1: 1112 case PERF_HPP__WEIGHT2: 1113 case PERF_HPP__WEIGHT3: 1114 fmt->len = 8; 1115 break; 1116 1117 case PERF_HPP__MEM_STAT_OP: 1118 case PERF_HPP__MEM_STAT_CACHE: 1119 case PERF_HPP__MEM_STAT_MEMORY: 1120 case PERF_HPP__MEM_STAT_SNOOP: 1121 fmt->len = MEM_STAT_LEN * MEM_STAT_PRINT_LEN; 1122 break; 1123 1124 default: 1125 break; 1126 } 1127 } 1128 1129 void hists__reset_column_width(struct hists *hists) 1130 { 1131 struct perf_hpp_fmt *fmt; 1132 struct perf_hpp_list_node *node; 1133 1134 hists__for_each_format(hists, fmt) 1135 perf_hpp__reset_width(fmt, hists); 1136 1137 /* hierarchy entries have their own hpp list */ 1138 list_for_each_entry(node, &hists->hpp_formats, list) { 1139 perf_hpp_list__for_each_format(&node->hpp, fmt) 1140 perf_hpp__reset_width(fmt, hists); 1141 } 1142 } 1143 1144 void perf_hpp__set_user_width(const char *width_list_str) 1145 { 1146 struct perf_hpp_fmt *fmt; 1147 const char *ptr = width_list_str; 1148 1149 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) { 1150 char *p; 1151 1152 int len = strtol(ptr, &p, 10); 1153 fmt->user_len = len; 1154 1155 if (*p == ',') 1156 ptr = p + 1; 1157 else 1158 break; 1159 } 1160 } 1161 1162 static int add_hierarchy_fmt(struct hists *hists, struct perf_hpp_fmt *fmt) 1163 { 1164 struct perf_hpp_list_node *node = NULL; 1165 struct perf_hpp_fmt *fmt_copy; 1166 bool found = false; 1167 bool skip = perf_hpp__should_skip(fmt, hists); 1168 1169 list_for_each_entry(node, &hists->hpp_formats, list) { 1170 if (node->level == fmt->level) { 1171 found = true; 1172 break; 1173 } 1174 } 1175 1176 if (!found) { 1177 node = malloc(sizeof(*node)); 1178 if (node == NULL) 1179 return -1; 1180 1181 node->skip = skip; 1182 node->level = fmt->level; 1183 perf_hpp_list__init(&node->hpp); 1184 1185 hists->nr_hpp_node++; 1186 list_add_tail(&node->list, &hists->hpp_formats); 1187 } 1188 1189 fmt_copy = perf_hpp_fmt__dup(fmt); 1190 if (fmt_copy == NULL) 1191 return -1; 1192 1193 if (!skip) 1194 node->skip = false; 1195 1196 list_add_tail(&fmt_copy->list, &node->hpp.fields); 1197 list_add_tail(&fmt_copy->sort_list, &node->hpp.sorts); 1198 1199 return 0; 1200 } 1201 1202 int perf_hpp__setup_hists_formats(struct perf_hpp_list *list, 1203 struct evlist *evlist) 1204 { 1205 struct evsel *evsel; 1206 struct perf_hpp_fmt *fmt; 1207 struct hists *hists; 1208 int ret; 1209 1210 if (!symbol_conf.report_hierarchy) 1211 return 0; 1212 1213 evlist__for_each_entry(evlist, evsel) { 1214 hists = evsel__hists(evsel); 1215 1216 perf_hpp_list__for_each_sort_list(list, fmt) { 1217 if (perf_hpp__is_dynamic_entry(fmt) && 1218 !perf_hpp__defined_dynamic_entry(fmt, hists)) 1219 continue; 1220 1221 ret = add_hierarchy_fmt(hists, fmt); 1222 if (ret < 0) 1223 return ret; 1224 } 1225 } 1226 1227 return 0; 1228 } 1229 1230 int perf_hpp__alloc_mem_stats(struct perf_hpp_list *list, struct evlist *evlist) 1231 { 1232 struct perf_hpp_fmt *fmt; 1233 struct evsel *evsel; 1234 enum mem_stat_type mst[16]; 1235 unsigned nr_mem_stats = 0; 1236 1237 perf_hpp_list__for_each_format(list, fmt) { 1238 if (!perf_hpp__is_mem_stat_entry(fmt)) 1239 continue; 1240 1241 assert(nr_mem_stats < ARRAY_SIZE(mst)); 1242 mst[nr_mem_stats++] = hpp__mem_stat_type(fmt); 1243 } 1244 1245 if (nr_mem_stats == 0) 1246 return 0; 1247 1248 list->nr_header_lines = 2; 1249 1250 evlist__for_each_entry(evlist, evsel) { 1251 struct hists *hists = evsel__hists(evsel); 1252 1253 hists->mem_stat_types = calloc(nr_mem_stats, 1254 sizeof(*hists->mem_stat_types)); 1255 if (hists->mem_stat_types == NULL) 1256 return -ENOMEM; 1257 1258 hists->mem_stat_total = calloc(nr_mem_stats, 1259 sizeof(*hists->mem_stat_total)); 1260 if (hists->mem_stat_total == NULL) 1261 return -ENOMEM; 1262 1263 memcpy(hists->mem_stat_types, mst, nr_mem_stats * sizeof(*mst)); 1264 hists->nr_mem_stats = nr_mem_stats; 1265 } 1266 return 0; 1267 } 1268