1 #include <stdlib.h> 1 2 #include <stdio.h> 3 #include <inttypes.h> 4 #include <linux/string.h> 5 #include <linux/time64.h> 6 #include <math.h> 7 #include <perf/cpumap.h> 8 #include "color.h" 9 #include "counts.h" 10 #include "evlist.h" 11 #include "evsel.h" 12 #include "stat.h" 13 #include "top.h" 14 #include "thread_map.h" 15 #include "cpumap.h" 16 #include "string2.h" 17 #include <linux/ctype.h> 18 #include "cgroup.h" 19 #include <api/fs/fs.h> 20 #include "util.h" 21 #include "iostat.h" 22 #include "pmu.h" 23 #include "pmus.h" 24 25 #define CNTR_NOT_SUPPORTED "<not supporte 26 #define CNTR_NOT_COUNTED "<not counted> 27 28 #define MGROUP_LEN 50 29 #define METRIC_LEN 38 30 #define EVNAME_LEN 32 31 #define COUNTS_LEN 18 32 #define INTERVAL_LEN 16 33 #define CGROUP_LEN 16 34 #define COMM_LEN 16 35 #define PID_LEN 7 36 #define CPUS_LEN 4 37 38 static int aggr_header_lens[] = { 39 [AGGR_CORE] = 18, 40 [AGGR_CACHE] = 22, 41 [AGGR_CLUSTER] = 20, 42 [AGGR_DIE] = 12, 43 [AGGR_SOCKET] = 6, 44 [AGGR_NODE] = 6, 45 [AGGR_NONE] = 6, 46 [AGGR_THREAD] = 16, 47 [AGGR_GLOBAL] = 0, 48 }; 49 50 static const char *aggr_header_csv[] = { 51 [AGGR_CORE] = "core,cpus,", 52 [AGGR_CACHE] = "cache,cpus,", 53 [AGGR_CLUSTER] = "cluster,cpus, 54 [AGGR_DIE] = "die,cpus,", 55 [AGGR_SOCKET] = "socket,cpus," 56 [AGGR_NONE] = "cpu,", 57 [AGGR_THREAD] = "comm-pid,", 58 [AGGR_NODE] = "node,", 59 [AGGR_GLOBAL] = "" 60 }; 61 62 static const char *aggr_header_std[] = { 63 [AGGR_CORE] = "core", 64 [AGGR_CACHE] = "cache", 65 [AGGR_CLUSTER] = "cluster", 66 [AGGR_DIE] = "die", 67 [AGGR_SOCKET] = "socket", 68 [AGGR_NONE] = "cpu", 69 [AGGR_THREAD] = "comm-pid", 70 [AGGR_NODE] = "node", 71 [AGGR_GLOBAL] = "" 72 }; 73 74 static void print_running_std(struct perf_stat 75 { 76 if (run != ena) 77 fprintf(config->output, " (%. 78 } 79 80 static void print_running_csv(struct perf_stat 81 { 82 double enabled_percent = 100; 83 84 if (run != ena) 85 enabled_percent = 100 * run / 86 fprintf(config->output, "%s%" PRIu64 " 87 config->csv_sep, run, config-> 88 } 89 90 static void print_running_json(struct perf_sta 91 { 92 double enabled_percent = 100; 93 94 if (run != ena) 95 enabled_percent = 100 * run / 96 fprintf(config->output, "\"event-runti 97 run, enabled_percent); 98 } 99 100 static void print_running(struct perf_stat_con 101 u64 run, u64 ena, bo 102 { 103 if (config->json_output) { 104 if (before_metric) 105 print_running_json(con 106 } else if (config->csv_output) { 107 if (before_metric) 108 print_running_csv(conf 109 } else { 110 if (!before_metric) 111 print_running_std(conf 112 } 113 } 114 115 static void print_noise_pct_std(struct perf_st 116 double pct) 117 { 118 if (pct) 119 fprintf(config->output, " ( + 120 } 121 122 static void print_noise_pct_csv(struct perf_st 123 double pct) 124 { 125 fprintf(config->output, "%s%.2f%%", co 126 } 127 128 static void print_noise_pct_json(struct perf_s 129 double pct) 130 { 131 fprintf(config->output, "\"variance\" 132 } 133 134 static void print_noise_pct(struct perf_stat_c 135 double total, doub 136 { 137 double pct = rel_stddev_stats(total, a 138 139 if (config->json_output) { 140 if (before_metric) 141 print_noise_pct_json(c 142 } else if (config->csv_output) { 143 if (before_metric) 144 print_noise_pct_csv(co 145 } else { 146 if (!before_metric) 147 print_noise_pct_std(co 148 } 149 } 150 151 static void print_noise(struct perf_stat_confi 152 struct evsel *evsel, d 153 { 154 struct perf_stat_evsel *ps; 155 156 if (config->run_count == 1) 157 return; 158 159 ps = evsel->stats; 160 print_noise_pct(config, stddev_stats(& 161 } 162 163 static void print_cgroup_std(struct perf_stat_ 164 { 165 fprintf(config->output, " %-*s", CGROU 166 } 167 168 static void print_cgroup_csv(struct perf_stat_ 169 { 170 fprintf(config->output, "%s%s", config 171 } 172 173 static void print_cgroup_json(struct perf_stat 174 { 175 fprintf(config->output, "\"cgroup\" : 176 } 177 178 static void print_cgroup(struct perf_stat_conf 179 { 180 if (nr_cgroups || config->cgroup_list) 181 const char *cgrp_name = cgrp ? 182 183 if (config->json_output) 184 print_cgroup_json(conf 185 else if (config->csv_output) 186 print_cgroup_csv(confi 187 else 188 print_cgroup_std(confi 189 } 190 } 191 192 static void print_aggr_id_std(struct perf_stat 193 struct evsel *ev 194 { 195 FILE *output = config->output; 196 int idx = config->aggr_mode; 197 char buf[128]; 198 199 switch (config->aggr_mode) { 200 case AGGR_CORE: 201 snprintf(buf, sizeof(buf), "S% 202 break; 203 case AGGR_CACHE: 204 snprintf(buf, sizeof(buf), "S% 205 id.socket, id.die, id 206 break; 207 case AGGR_CLUSTER: 208 snprintf(buf, sizeof(buf), "S% 209 break; 210 case AGGR_DIE: 211 snprintf(buf, sizeof(buf), "S% 212 break; 213 case AGGR_SOCKET: 214 snprintf(buf, sizeof(buf), "S% 215 break; 216 case AGGR_NODE: 217 snprintf(buf, sizeof(buf), "N% 218 break; 219 case AGGR_NONE: 220 if (evsel->percore && !config- 221 snprintf(buf, sizeof(b 222 id.socket, id. 223 fprintf(output, "%-*s 224 aggr_header_le 225 } else if (id.cpu.cpu > -1) { 226 fprintf(output, "CPU%- 227 aggr_header_le 228 } 229 return; 230 case AGGR_THREAD: 231 fprintf(output, "%*s-%-*d ", 232 COMM_LEN, perf_thread_ 233 PID_LEN, perf_thread_m 234 return; 235 case AGGR_GLOBAL: 236 case AGGR_UNSET: 237 case AGGR_MAX: 238 default: 239 return; 240 } 241 242 fprintf(output, "%-*s %*d ", aggr_head 243 } 244 245 static void print_aggr_id_csv(struct perf_stat 246 struct evsel *ev 247 { 248 FILE *output = config->output; 249 const char *sep = config->csv_sep; 250 251 switch (config->aggr_mode) { 252 case AGGR_CORE: 253 fprintf(output, "S%d-D%d-C%d%s 254 id.socket, id.die, id. 255 break; 256 case AGGR_CACHE: 257 fprintf(config->output, "S%d-D 258 id.socket, id.die, id. 259 break; 260 case AGGR_CLUSTER: 261 fprintf(config->output, "S%d-D 262 id.socket, id.die, id. 263 break; 264 case AGGR_DIE: 265 fprintf(output, "S%d-D%d%s%d%s 266 id.socket, id.die, sep 267 break; 268 case AGGR_SOCKET: 269 fprintf(output, "S%d%s%d%s", 270 id.socket, sep, aggr_n 271 break; 272 case AGGR_NODE: 273 fprintf(output, "N%d%s%d%s", 274 id.node, sep, aggr_nr, 275 break; 276 case AGGR_NONE: 277 if (evsel->percore && !config- 278 fprintf(output, "S%d-D 279 id.socket, id. 280 } else if (id.cpu.cpu > -1) { 281 fprintf(output, "CPU%d 282 id.cpu.cpu, se 283 } 284 break; 285 case AGGR_THREAD: 286 fprintf(output, "%s-%d%s", 287 perf_thread_map__comm( 288 perf_thread_map__pid(e 289 sep); 290 break; 291 case AGGR_GLOBAL: 292 case AGGR_UNSET: 293 case AGGR_MAX: 294 default: 295 break; 296 } 297 } 298 299 static void print_aggr_id_json(struct perf_sta 300 struct evsel *e 301 { 302 FILE *output = config->output; 303 304 switch (config->aggr_mode) { 305 case AGGR_CORE: 306 fprintf(output, "\"core\" : \" 307 id.socket, id.die, id. 308 break; 309 case AGGR_CACHE: 310 fprintf(output, "\"cache\" : \ 311 id.socket, id.die, id. 312 break; 313 case AGGR_CLUSTER: 314 fprintf(output, "\"cluster\" : 315 id.socket, id.die, id. 316 break; 317 case AGGR_DIE: 318 fprintf(output, "\"die\" : \"S 319 id.socket, id.die, agg 320 break; 321 case AGGR_SOCKET: 322 fprintf(output, "\"socket\" : 323 id.socket, aggr_nr); 324 break; 325 case AGGR_NODE: 326 fprintf(output, "\"node\" : \" 327 id.node, aggr_nr); 328 break; 329 case AGGR_NONE: 330 if (evsel->percore && !config- 331 fprintf(output, "\"cor 332 id.socket, id. 333 } else if (id.cpu.cpu > -1) { 334 fprintf(output, "\"cpu 335 id.cpu.cpu); 336 } 337 break; 338 case AGGR_THREAD: 339 fprintf(output, "\"thread\" : 340 perf_thread_map__comm( 341 perf_thread_map__pid(e 342 break; 343 case AGGR_GLOBAL: 344 case AGGR_UNSET: 345 case AGGR_MAX: 346 default: 347 break; 348 } 349 } 350 351 static void aggr_printout(struct perf_stat_con 352 struct evsel *evsel, 353 { 354 if (config->json_output) 355 print_aggr_id_json(config, evs 356 else if (config->csv_output) 357 print_aggr_id_csv(config, evse 358 else 359 print_aggr_id_std(config, evse 360 } 361 362 struct outstate { 363 FILE *fh; 364 bool newline; 365 bool first; 366 const char *prefix; 367 int nfields; 368 int aggr_nr; 369 struct aggr_cpu_id id; 370 struct evsel *evsel; 371 struct cgroup *cgrp; 372 }; 373 374 static void new_line_std(struct perf_stat_conf 375 void *ctx) 376 { 377 struct outstate *os = ctx; 378 379 os->newline = true; 380 } 381 382 static inline void __new_line_std_csv(struct p 383 struct o 384 { 385 fputc('\n', os->fh); 386 if (os->prefix) 387 fputs(os->prefix, os->fh); 388 aggr_printout(config, os->evsel, os->i 389 } 390 391 static inline void __new_line_std(struct outst 392 { 393 fprintf(os->fh, " 394 } 395 396 static void do_new_line_std(struct perf_stat_c 397 struct outstate *o 398 { 399 __new_line_std_csv(config, os); 400 if (config->aggr_mode == AGGR_NONE) 401 fprintf(os->fh, " "); 402 __new_line_std(os); 403 } 404 405 static void print_metric_std(struct perf_stat_ 406 void *ctx, const 407 const char *unit, 408 { 409 struct outstate *os = ctx; 410 FILE *out = os->fh; 411 int n; 412 bool newline = os->newline; 413 414 os->newline = false; 415 416 if (unit == NULL || fmt == NULL) { 417 fprintf(out, "%-*s", METRIC_LE 418 return; 419 } 420 421 if (newline) 422 do_new_line_std(config, os); 423 424 n = fprintf(out, " # "); 425 if (color) 426 n += color_fprintf(out, color, 427 else 428 n += fprintf(out, fmt, val); 429 fprintf(out, " %-*s", METRIC_LEN - n - 430 } 431 432 static void new_line_csv(struct perf_stat_conf 433 { 434 struct outstate *os = ctx; 435 int i; 436 437 __new_line_std_csv(config, os); 438 for (i = 0; i < os->nfields; i++) 439 fputs(config->csv_sep, os->fh) 440 } 441 442 static void print_metric_csv(struct perf_stat_ 443 void *ctx, 444 const char *color 445 const char *fmt, 446 { 447 struct outstate *os = ctx; 448 FILE *out = os->fh; 449 char buf[64], *vals, *ends; 450 451 if (unit == NULL || fmt == NULL) { 452 fprintf(out, "%s%s", config->c 453 return; 454 } 455 snprintf(buf, sizeof(buf), fmt, val); 456 ends = vals = skip_spaces(buf); 457 while (isdigit(*ends) || *ends == '.') 458 ends++; 459 *ends = 0; 460 fprintf(out, "%s%s%s%s", config->csv_s 461 } 462 463 static void print_metric_json(struct perf_stat 464 void *ctx, 465 const char *color 466 const char *fmt _ 467 const char *unit, 468 { 469 struct outstate *os = ctx; 470 FILE *out = os->fh; 471 472 fprintf(out, "\"metric-value\" : \"%f\ 473 fprintf(out, "\"metric-unit\" : \"%s\" 474 if (!config->metric_only) 475 fprintf(out, "}"); 476 } 477 478 static void new_line_json(struct perf_stat_con 479 { 480 struct outstate *os = ctx; 481 482 fputs("\n{", os->fh); 483 if (os->prefix) 484 fprintf(os->fh, "%s", os->pref 485 aggr_printout(config, os->evsel, os->i 486 } 487 488 static void print_metricgroup_header_json(stru 489 void 490 cons 491 { 492 if (!metricgroup_name) 493 return; 494 495 fprintf(config->output, "\"metricgroup 496 new_line_json(config, ctx); 497 } 498 499 static void print_metricgroup_header_csv(struc 500 void 501 const 502 { 503 struct outstate *os = ctx; 504 int i; 505 506 if (!metricgroup_name) { 507 /* Leave space for running and 508 for (i = 0; i < os->nfields - 509 fputs(config->csv_sep, 510 return; 511 } 512 513 for (i = 0; i < os->nfields; i++) 514 fputs(config->csv_sep, os->fh) 515 fprintf(config->output, "%s", metricgr 516 new_line_csv(config, ctx); 517 } 518 519 static void print_metricgroup_header_std(struc 520 void 521 const 522 { 523 struct outstate *os = ctx; 524 int n; 525 526 if (!metricgroup_name) { 527 __new_line_std(os); 528 return; 529 } 530 531 n = fprintf(config->output, " %*s", EV 532 533 fprintf(config->output, "%*s", MGROUP_ 534 } 535 536 /* Filter out some columns that don't work wel 537 538 static bool valid_only_metric(const char *unit 539 { 540 if (!unit) 541 return false; 542 if (strstr(unit, "/sec") || 543 strstr(unit, "CPUs utilized")) 544 return false; 545 return true; 546 } 547 548 static const char *fixunit(char *buf, struct e 549 const char *unit) 550 { 551 if (!strncmp(unit, "of all", 6)) { 552 snprintf(buf, 1024, "%s %s", e 553 unit); 554 return buf; 555 } 556 return unit; 557 } 558 559 static void print_metric_only(struct perf_stat 560 void *ctx, const 561 const char *unit 562 { 563 struct outstate *os = ctx; 564 FILE *out = os->fh; 565 char buf[1024], str[1024]; 566 unsigned mlen = config->metric_only_le 567 568 if (!valid_only_metric(unit)) 569 return; 570 unit = fixunit(buf, os->evsel, unit); 571 if (mlen < strlen(unit)) 572 mlen = strlen(unit) + 1; 573 574 if (color) 575 mlen += strlen(color) + sizeof 576 577 color_snprintf(str, sizeof(str), color 578 fprintf(out, "%*s ", mlen, str); 579 os->first = false; 580 } 581 582 static void print_metric_only_csv(struct perf_ 583 void *ctx, c 584 const char * 585 const char * 586 { 587 struct outstate *os = ctx; 588 FILE *out = os->fh; 589 char buf[64], *vals, *ends; 590 char tbuf[1024]; 591 592 if (!valid_only_metric(unit)) 593 return; 594 unit = fixunit(tbuf, os->evsel, unit); 595 snprintf(buf, sizeof(buf), fmt ?: "", 596 ends = vals = skip_spaces(buf); 597 while (isdigit(*ends) || *ends == '.') 598 ends++; 599 *ends = 0; 600 fprintf(out, "%s%s", vals, config->csv 601 os->first = false; 602 } 603 604 static void print_metric_only_json(struct perf 605 void *ctx, c 606 const char * 607 const char * 608 { 609 struct outstate *os = ctx; 610 FILE *out = os->fh; 611 char buf[64], *vals, *ends; 612 char tbuf[1024]; 613 614 if (!valid_only_metric(unit)) 615 return; 616 unit = fixunit(tbuf, os->evsel, unit); 617 snprintf(buf, sizeof(buf), fmt ?: "", 618 ends = vals = skip_spaces(buf); 619 while (isdigit(*ends) || *ends == '.') 620 ends++; 621 *ends = 0; 622 if (!unit[0] || !vals[0]) 623 return; 624 fprintf(out, "%s\"%s\" : \"%s\"", os-> 625 os->first = false; 626 } 627 628 static void new_line_metric(struct perf_stat_c 629 void *ctx __maybe_ 630 { 631 } 632 633 static void print_metric_header(struct perf_st 634 void *ctx, con 635 const char *fm 636 const char *un 637 { 638 struct outstate *os = ctx; 639 char tbuf[1024]; 640 641 /* In case of iostat, print metric hea 642 if (config->iostat_run && 643 os->evsel->priv != os->evsel->evli 644 return; 645 646 if (os->evsel->cgrp != os->cgrp) 647 return; 648 649 if (!valid_only_metric(unit)) 650 return; 651 unit = fixunit(tbuf, os->evsel, unit); 652 653 if (config->json_output) 654 return; 655 else if (config->csv_output) 656 fprintf(os->fh, "%s%s", unit, 657 else 658 fprintf(os->fh, "%*s ", config 659 } 660 661 static void print_counter_value_std(struct per 662 struct evs 663 { 664 FILE *output = config->output; 665 double sc = evsel->scale; 666 const char *fmt; 667 const char *bad_count = evsel->support 668 669 if (config->big_num) 670 fmt = floor(sc) != sc ? "%'*.2 671 else 672 fmt = floor(sc) != sc ? "%*.2f 673 674 if (ok) 675 fprintf(output, fmt, COUNTS_LE 676 else 677 fprintf(output, "%*s ", COUNTS 678 679 if (evsel->unit) 680 fprintf(output, "%-*s ", confi 681 682 fprintf(output, "%-*s", EVNAME_LEN, ev 683 } 684 685 static void print_counter_value_csv(struct per 686 struct evs 687 { 688 FILE *output = config->output; 689 double sc = evsel->scale; 690 const char *sep = config->csv_sep; 691 const char *fmt = floor(sc) != sc ? "% 692 const char *bad_count = evsel->support 693 694 if (ok) 695 fprintf(output, fmt, avg, sep) 696 else 697 fprintf(output, "%s%s", bad_co 698 699 if (evsel->unit) 700 fprintf(output, "%s%s", evsel- 701 702 fprintf(output, "%s", evsel__name(evse 703 } 704 705 static void print_counter_value_json(struct pe 706 struct ev 707 { 708 FILE *output = config->output; 709 const char *bad_count = evsel->support 710 711 if (ok) 712 fprintf(output, "\"counter-val 713 else 714 fprintf(output, "\"counter-val 715 716 if (evsel->unit) 717 fprintf(output, "\"unit\" : \" 718 719 fprintf(output, "\"event\" : \"%s\", " 720 } 721 722 static void print_counter_value(struct perf_st 723 struct evsel * 724 { 725 if (config->json_output) 726 print_counter_value_json(confi 727 else if (config->csv_output) 728 print_counter_value_csv(config 729 else 730 print_counter_value_std(config 731 } 732 733 static void abs_printout(struct perf_stat_conf 734 struct aggr_cpu_id id 735 struct evsel *evsel, 736 { 737 aggr_printout(config, evsel, id, aggr_ 738 print_counter_value(config, evsel, avg 739 print_cgroup(config, evsel->cgrp); 740 } 741 742 static bool is_mixed_hw_group(struct evsel *co 743 { 744 struct evlist *evlist = counter->evlis 745 u32 pmu_type = counter->core.attr.type 746 struct evsel *pos; 747 748 if (counter->core.nr_members < 2) 749 return false; 750 751 evlist__for_each_entry(evlist, pos) { 752 /* software events can be part 753 if (pos->core.attr.type == PER 754 continue; 755 if (pmu_type == PERF_TYPE_SOFT 756 pmu_type = pos->core.a 757 continue; 758 } 759 if (pmu_type != pos->core.attr 760 return true; 761 } 762 763 return false; 764 } 765 766 static bool evlist__has_hybrid(struct evlist * 767 { 768 struct evsel *evsel; 769 770 if (perf_pmus__num_core_pmus() == 1) 771 return false; 772 773 evlist__for_each_entry(evlist, evsel) 774 if (evsel->core.is_pmu_core) 775 return true; 776 } 777 778 return false; 779 } 780 781 static void printout(struct perf_stat_config * 782 double uval, u64 run, u64 783 { 784 struct perf_stat_output_ctx out; 785 print_metric_t pm; 786 new_line_t nl; 787 print_metricgroup_header_t pmh; 788 bool ok = true; 789 struct evsel *counter = os->evsel; 790 791 if (config->csv_output) { 792 pm = config->metric_only ? pri 793 nl = config->metric_only ? new 794 pmh = print_metricgroup_header 795 os->nfields = 4 + (counter->cg 796 } else if (config->json_output) { 797 pm = config->metric_only ? pri 798 nl = config->metric_only ? new 799 pmh = print_metricgroup_header 800 } else { 801 pm = config->metric_only ? pri 802 nl = config->metric_only ? new 803 pmh = print_metricgroup_header 804 } 805 806 if (run == 0 || ena == 0 || counter->c 807 if (config->metric_only) { 808 pm(config, os, NULL, " 809 return; 810 } 811 812 ok = false; 813 814 if (counter->supported) { 815 if (!evlist__has_hybri 816 config->print_ 817 if (is_mixed_h 818 config 819 } 820 } 821 } 822 823 out.print_metric = pm; 824 out.new_line = nl; 825 out.print_metricgroup_header = pmh; 826 out.ctx = os; 827 out.force_header = false; 828 829 if (!config->metric_only && !counter-> 830 abs_printout(config, os->id, o 831 832 print_noise(config, counter, n 833 print_running(config, run, ena 834 } 835 836 if (ok) { 837 if (!config->metric_only && co 838 void *from = NULL; 839 840 aggr_printout(config, 841 /* Print out all the m 842 do { 843 int num = 0; 844 845 /* Print out t 846 if (from) { 847 if (co 848 849 else 850 851 } 852 853 print_noise(co 854 print_running( 855 from = perf_st 856 857 858 } while (from != NULL) 859 } else 860 perf_stat__print_shado 861 862 } else { 863 pm(config, os, /*color=*/NULL, 864 } 865 866 if (!config->metric_only) { 867 print_noise(config, counter, n 868 print_running(config, run, ena 869 } 870 } 871 872 static void uniquify_event_name(struct evsel * 873 { 874 char *new_name; 875 char *config; 876 int ret = 0; 877 878 if (counter->uniquified_name || counte 879 !counter->pmu_name || !strncmp(evs 880 str 881 return; 882 883 config = strchr(counter->name, '/'); 884 if (config) { 885 if (asprintf(&new_name, 886 "%s%s", counter-> 887 free(counter->name); 888 counter->name = new_na 889 } 890 } else { 891 if (evsel__is_hybrid(counter)) 892 ret = asprintf(&new_na 893 counter 894 } else { 895 ret = asprintf(&new_na 896 counter 897 } 898 899 if (ret) { 900 free(counter->name); 901 counter->name = new_na 902 } 903 } 904 905 counter->uniquified_name = true; 906 } 907 908 static bool hybrid_uniquify(struct evsel *evse 909 { 910 return evsel__is_hybrid(evsel) && !con 911 } 912 913 static void uniquify_counter(struct perf_stat_ 914 { 915 if (config->aggr_mode == AGGR_NONE || 916 uniquify_event_name(counter); 917 } 918 919 /** 920 * should_skip_zero_count() - Check if the eve 921 * @config: The perf stat configuration (inclu 922 * @counter: The evsel with its associated cpu 923 * @id: The aggregation id that is being queri 924 * 925 * Due to mismatch between the event cpumap or 926 * aggregation mode, sometimes it'd iterate th 927 * which does not contain any values. 928 * 929 * For example, uncore events have dedicated C 930 * result for other CPUs should be zero and sk 931 * 932 * Return: %true if the value should NOT be pr 933 * needs to be printed like "<not counted>" or 934 */ 935 static bool should_skip_zero_counter(struct pe 936 struct ev 937 const str 938 { 939 struct perf_cpu cpu; 940 int idx; 941 942 /* 943 * Skip value 0 when enabling --per-th 944 * otherwise it will have too many 0 o 945 */ 946 if (config->aggr_mode == AGGR_THREAD & 947 return true; 948 949 /* Tool events have the software PMU b 950 if (evsel__is_tool(counter)) 951 return true; 952 953 /* 954 * Skip value 0 when it's an uncore ev 955 * does not belong to the PMU cpumask. 956 */ 957 if (!counter->pmu || !counter->pmu->is 958 return false; 959 960 perf_cpu_map__for_each_cpu(cpu, idx, c 961 struct aggr_cpu_id own_id = co 962 963 if (aggr_cpu_id__equal(id, &ow 964 return false; 965 } 966 return true; 967 } 968 969 static void print_counter_aggrdata(struct perf 970 struct evse 971 struct outs 972 { 973 FILE *output = config->output; 974 u64 ena, run, val; 975 double uval; 976 struct perf_stat_evsel *ps = counter-> 977 struct perf_stat_aggr *aggr = &ps->agg 978 struct aggr_cpu_id id = config->aggr_m 979 double avg = aggr->counts.val; 980 bool metric_only = config->metric_only 981 982 os->id = id; 983 os->aggr_nr = aggr->nr; 984 os->evsel = counter; 985 986 /* Skip already merged uncore/hybrid e 987 if (counter->merged_stat) 988 return; 989 990 uniquify_counter(config, counter); 991 992 val = aggr->counts.val; 993 ena = aggr->counts.ena; 994 run = aggr->counts.run; 995 996 if (perf_stat__skip_metric_event(count 997 return; 998 999 if (val == 0 && should_skip_zero_count 1000 return; 1001 1002 if (!metric_only) { 1003 if (config->json_output) 1004 fputc('{', output); 1005 if (os->prefix) 1006 fprintf(output, "%s", 1007 else if (config->summary && c 1008 !config->no_csv_summ 1009 fprintf(output, "%s%s 1010 } 1011 1012 uval = val * counter->scale; 1013 1014 printout(config, os, uval, run, ena, 1015 1016 if (!metric_only) 1017 fputc('\n', output); 1018 } 1019 1020 static void print_metric_begin(struct perf_st 1021 struct evlist 1022 struct outstat 1023 { 1024 struct perf_stat_aggr *aggr; 1025 struct aggr_cpu_id id; 1026 struct evsel *evsel; 1027 1028 os->first = true; 1029 if (!config->metric_only) 1030 return; 1031 1032 if (config->json_output) 1033 fputc('{', config->output); 1034 if (os->prefix) 1035 fprintf(config->output, "%s", 1036 1037 evsel = evlist__first(evlist); 1038 id = config->aggr_map->map[aggr_idx]; 1039 aggr = &evsel->stats->aggr[aggr_idx]; 1040 aggr_printout(config, evsel, id, aggr 1041 1042 print_cgroup(config, os->cgrp ? : evs 1043 } 1044 1045 static void print_metric_end(struct perf_stat 1046 { 1047 FILE *output = config->output; 1048 1049 if (!config->metric_only) 1050 return; 1051 1052 if (config->json_output) { 1053 if (os->first) 1054 fputs("\"metric-value 1055 fputc('}', output); 1056 } 1057 fputc('\n', output); 1058 } 1059 1060 static void print_aggr(struct perf_stat_confi 1061 struct evlist *evlist, 1062 struct outstate *os) 1063 { 1064 struct evsel *counter; 1065 int aggr_idx; 1066 1067 if (!config->aggr_map || !config->agg 1068 return; 1069 1070 /* 1071 * With metric_only everything is on 1072 * Without each counter has its own l 1073 */ 1074 cpu_aggr_map__for_each_idx(aggr_idx, 1075 print_metric_begin(config, ev 1076 1077 evlist__for_each_entry(evlist 1078 print_counter_aggrdat 1079 } 1080 print_metric_end(config, os); 1081 } 1082 } 1083 1084 static void print_aggr_cgroup(struct perf_sta 1085 struct evlist * 1086 struct outstate 1087 { 1088 struct evsel *counter, *evsel; 1089 int aggr_idx; 1090 1091 if (!config->aggr_map || !config->agg 1092 return; 1093 1094 evlist__for_each_entry(evlist, evsel) 1095 if (os->cgrp == evsel->cgrp) 1096 continue; 1097 1098 os->cgrp = evsel->cgrp; 1099 1100 cpu_aggr_map__for_each_idx(ag 1101 print_metric_begin(co 1102 1103 evlist__for_each_entr 1104 if (counter-> 1105 conti 1106 1107 print_counter 1108 } 1109 print_metric_end(conf 1110 } 1111 } 1112 } 1113 1114 static void print_counter(struct perf_stat_co 1115 struct evsel *count 1116 { 1117 int aggr_idx; 1118 1119 /* AGGR_THREAD doesn't have config->a 1120 if (!config->aggr_map) 1121 return; 1122 1123 cpu_aggr_map__for_each_idx(aggr_idx, 1124 print_counter_aggrdata(config 1125 } 1126 } 1127 1128 static void print_no_aggr_metric(struct perf_ 1129 struct evlis 1130 struct outst 1131 { 1132 int all_idx; 1133 struct perf_cpu cpu; 1134 1135 perf_cpu_map__for_each_cpu(cpu, all_i 1136 struct evsel *counter; 1137 bool first = true; 1138 1139 evlist__for_each_entry(evlist 1140 u64 ena, run, val; 1141 double uval; 1142 struct perf_stat_evse 1143 int aggr_idx = 0; 1144 1145 if (!perf_cpu_map__ha 1146 continue; 1147 1148 cpu_aggr_map__for_eac 1149 if (config->a 1150 break 1151 } 1152 1153 os->evsel = counter; 1154 os->id = aggr_cpu_id_ 1155 if (first) { 1156 print_metric_ 1157 first = false 1158 } 1159 val = ps->aggr[aggr_i 1160 ena = ps->aggr[aggr_i 1161 run = ps->aggr[aggr_i 1162 1163 uval = val * counter- 1164 printout(config, os, 1165 } 1166 if (!first) 1167 print_metric_end(conf 1168 } 1169 } 1170 1171 static void print_metric_headers_std(struct p 1172 bool no_ 1173 { 1174 fputc(' ', config->output); 1175 1176 if (!no_indent) { 1177 int len = aggr_header_lens[co 1178 1179 if (nr_cgroups || config->cgr 1180 len += CGROUP_LEN + 1 1181 1182 fprintf(config->output, "%*s" 1183 } 1184 } 1185 1186 static void print_metric_headers_csv(struct p 1187 bool no_ 1188 { 1189 const char *p; 1190 1191 if (config->interval) 1192 fprintf(config->output, "time 1193 if (config->iostat_run) 1194 return; 1195 1196 p = aggr_header_csv[config->aggr_mode 1197 while (*p) { 1198 if (*p == ',') 1199 fputs(config->csv_sep 1200 else 1201 fputc(*p, config->out 1202 p++; 1203 } 1204 } 1205 1206 static void print_metric_headers_json(struct 1207 bool no 1208 { 1209 } 1210 1211 static void print_metric_headers(struct perf_ 1212 struct evlis 1213 { 1214 struct evsel *counter; 1215 struct outstate os = { 1216 .fh = config->output 1217 }; 1218 struct perf_stat_output_ctx out = { 1219 .ctx = &os, 1220 .print_metric = print_metric_ 1221 .new_line = new_line_metric, 1222 .force_header = true, 1223 }; 1224 1225 if (config->json_output) 1226 print_metric_headers_json(con 1227 else if (config->csv_output) 1228 print_metric_headers_csv(conf 1229 else 1230 print_metric_headers_std(conf 1231 1232 if (config->iostat_run) 1233 iostat_print_header_prefix(co 1234 1235 if (config->cgroup_list) 1236 os.cgrp = evlist__first(evlis 1237 1238 /* Print metrics headers only */ 1239 evlist__for_each_entry(evlist, counte 1240 if (!config->iostat_run && 1241 config->aggr_mode != AGGR 1242 continue; 1243 1244 os.evsel = counter; 1245 1246 perf_stat__print_shadow_stats 1247 1248 1249 1250 } 1251 1252 if (!config->json_output) 1253 fputc('\n', config->output); 1254 } 1255 1256 static void prepare_interval(struct perf_stat 1257 char *prefix, si 1258 { 1259 if (config->iostat_run) 1260 return; 1261 1262 if (config->json_output) 1263 scnprintf(prefix, len, "\"int 1264 (unsigned long) ts- 1265 else if (config->csv_output) 1266 scnprintf(prefix, len, "%lu.% 1267 (unsigned long) ts- 1268 else 1269 scnprintf(prefix, len, "%6lu. 1270 (unsigned long) ts- 1271 } 1272 1273 static void print_header_interval_std(struct 1274 struct 1275 struct 1276 int arg 1277 const c 1278 { 1279 FILE *output = config->output; 1280 1281 switch (config->aggr_mode) { 1282 case AGGR_NODE: 1283 case AGGR_SOCKET: 1284 case AGGR_DIE: 1285 case AGGR_CLUSTER: 1286 case AGGR_CACHE: 1287 case AGGR_CORE: 1288 fprintf(output, "#%*s %-*s cp 1289 INTERVAL_LEN - 1, "ti 1290 aggr_header_lens[conf 1291 aggr_header_std[confi 1292 break; 1293 case AGGR_NONE: 1294 fprintf(output, "#%*s %-*s", 1295 INTERVAL_LEN - 1, "ti 1296 aggr_header_lens[conf 1297 aggr_header_std[confi 1298 break; 1299 case AGGR_THREAD: 1300 fprintf(output, "#%*s %*s-%-* 1301 INTERVAL_LEN - 1, "ti 1302 COMM_LEN, "comm", PID 1303 break; 1304 case AGGR_GLOBAL: 1305 default: 1306 if (!config->iostat_run) 1307 fprintf(output, "#%*s 1308 INTERVAL_LEN 1309 case AGGR_UNSET: 1310 case AGGR_MAX: 1311 break; 1312 } 1313 1314 if (config->metric_only) 1315 print_metric_headers(config, 1316 else 1317 fprintf(output, " %*s %*s eve 1318 COUNTS_LEN, "counts", 1319 } 1320 1321 static void print_header_std(struct perf_stat 1322 struct target *_ 1323 int argc, const 1324 { 1325 FILE *output = config->output; 1326 int i; 1327 1328 fprintf(output, "\n"); 1329 fprintf(output, " Performance counter 1330 if (_target->bpf_str) 1331 fprintf(output, "\'BPF progra 1332 else if (_target->system_wide) 1333 fprintf(output, "\'system wid 1334 else if (_target->cpu_list) 1335 fprintf(output, "\'CPU(s) %s" 1336 else if (!target__has_task(_target)) 1337 fprintf(output, "\'%s", argv 1338 for (i = 1; argv && (i < argc 1339 fprintf(output, " %s" 1340 } else if (_target->pid) 1341 fprintf(output, "process id \ 1342 else 1343 fprintf(output, "thread id \' 1344 1345 fprintf(output, "\'"); 1346 if (config->run_count > 1) 1347 fprintf(output, " (%d runs)", 1348 fprintf(output, ":\n\n"); 1349 1350 if (config->metric_only) 1351 print_metric_headers(config, 1352 } 1353 1354 static void print_header_csv(struct perf_stat 1355 struct target *_ 1356 struct evlist *e 1357 int argc __maybe 1358 const char **arg 1359 { 1360 if (config->metric_only) 1361 print_metric_headers(config, 1362 } 1363 static void print_header_json(struct perf_sta 1364 struct target * 1365 struct evlist * 1366 int argc __mayb 1367 const char **ar 1368 { 1369 if (config->metric_only) 1370 print_metric_headers(config, 1371 } 1372 1373 static void print_header(struct perf_stat_con 1374 struct target *_targ 1375 struct evlist *evlis 1376 int argc, const char 1377 { 1378 static int num_print_iv; 1379 1380 fflush(stdout); 1381 1382 if (config->interval_clear) 1383 puts(CONSOLE_CLEAR); 1384 1385 if (num_print_iv == 0 || config->inte 1386 if (config->json_output) 1387 print_header_json(con 1388 else if (config->csv_output) 1389 print_header_csv(conf 1390 else if (config->interval) 1391 print_header_interval 1392 else 1393 print_header_std(conf 1394 } 1395 1396 if (num_print_iv++ == 25) 1397 num_print_iv = 0; 1398 } 1399 1400 static int get_precision(double num) 1401 { 1402 if (num > 1) 1403 return 0; 1404 1405 return lround(ceil(-log10(num))); 1406 } 1407 1408 static void print_table(struct perf_stat_conf 1409 FILE *output, int pre 1410 { 1411 char tmp[64]; 1412 int idx, indent = 0; 1413 1414 scnprintf(tmp, 64, " %17.*f", precisi 1415 while (tmp[indent] == ' ') 1416 indent++; 1417 1418 fprintf(output, "%*s# Table of indivi 1419 1420 for (idx = 0; idx < config->run_count 1421 double run = (double) config- 1422 int h, n = 1 + abs((int) (100 1423 1424 fprintf(output, " %17.*f (%+. 1425 precision, run, preci 1426 1427 for (h = 0; h < n; h++) 1428 fprintf(output, "#"); 1429 1430 fprintf(output, "\n"); 1431 } 1432 1433 fprintf(output, "\n%*s# Final result: 1434 } 1435 1436 static double timeval2double(struct timeval * 1437 { 1438 return t->tv_sec + (double) t->tv_use 1439 } 1440 1441 static void print_footer(struct perf_stat_con 1442 { 1443 double avg = avg_stats(config->wallti 1444 FILE *output = config->output; 1445 1446 if (config->interval || config->csv_o 1447 return; 1448 1449 if (!config->null_run) 1450 fprintf(output, "\n"); 1451 1452 if (config->run_count == 1) { 1453 fprintf(output, " %17.9f seco 1454 1455 if (config->ru_display) { 1456 double ru_utime = tim 1457 double ru_stime = tim 1458 1459 fprintf(output, "\n\n 1460 fprintf(output, " %17 1461 fprintf(output, " %17 1462 } 1463 } else { 1464 double sd = stddev_stats(conf 1465 /* 1466 * Display at most 2 more sig 1467 * digits than the stddev ina 1468 */ 1469 int precision = get_precision 1470 1471 if (config->walltime_run_tabl 1472 print_table(config, o 1473 1474 fprintf(output, " %17.*f +- % 1475 precision, avg, preci 1476 1477 print_noise_pct(config, sd, a 1478 } 1479 fprintf(output, "\n\n"); 1480 1481 if (config->print_free_counters_hint 1482 fprintf(output, 1483 "Some events weren't counted. Try disabling t 1484 " echo 0 > /proc/sys/kernel/nmi_watchdo 1485 " perf stat ...\n" 1486 " echo 1 > /proc/sys/kernel/nmi_watchdo 1487 1488 if (config->print_mixed_hw_group_erro 1489 fprintf(output, 1490 "The events in group 1491 "the same PMU. Try re 1492 } 1493 1494 static void print_percore(struct perf_stat_co 1495 struct evsel *count 1496 { 1497 bool metric_only = config->metric_onl 1498 FILE *output = config->output; 1499 struct cpu_aggr_map *core_map; 1500 int aggr_idx, core_map_len = 0; 1501 1502 if (!config->aggr_map || !config->agg 1503 return; 1504 1505 if (config->percore_show_thread) 1506 return print_counter(config, 1507 1508 /* 1509 * core_map will hold the aggr_cpu_id 1510 * printed so that each core is print 1511 */ 1512 core_map = cpu_aggr_map__empty_new(co 1513 if (core_map == NULL) { 1514 fprintf(output, "Cannot alloc 1515 return; 1516 } 1517 1518 cpu_aggr_map__for_each_idx(aggr_idx, 1519 struct perf_cpu curr_cpu = co 1520 struct aggr_cpu_id core_id = 1521 bool found = false; 1522 1523 for (int i = 0; i < core_map_ 1524 if (aggr_cpu_id__equa 1525 found = true; 1526 break; 1527 } 1528 } 1529 if (found) 1530 continue; 1531 1532 print_counter_aggrdata(config 1533 1534 core_map->map[core_map_len++] 1535 } 1536 free(core_map); 1537 1538 if (metric_only) 1539 fputc('\n', output); 1540 } 1541 1542 static void print_cgroup_counter(struct perf_ 1543 struct outst 1544 { 1545 struct evsel *counter; 1546 1547 evlist__for_each_entry(evlist, counte 1548 if (os->cgrp != counter->cgrp 1549 if (os->cgrp != NULL) 1550 print_metric_ 1551 1552 os->cgrp = counter->c 1553 print_metric_begin(co 1554 } 1555 1556 print_counter(config, counter 1557 } 1558 if (os->cgrp) 1559 print_metric_end(config, os); 1560 } 1561 1562 void evlist__print_counters(struct evlist *ev 1563 struct target *_t 1564 int argc, const c 1565 { 1566 bool metric_only = config->metric_onl 1567 int interval = config->interval; 1568 struct evsel *counter; 1569 char buf[64]; 1570 struct outstate os = { 1571 .fh = config->output, 1572 .first = true, 1573 }; 1574 1575 if (config->iostat_run) 1576 evlist->selected = evlist__fi 1577 1578 if (interval) { 1579 os.prefix = buf; 1580 prepare_interval(config, buf, 1581 } 1582 1583 print_header(config, _target, evlist, 1584 1585 switch (config->aggr_mode) { 1586 case AGGR_CORE: 1587 case AGGR_CACHE: 1588 case AGGR_CLUSTER: 1589 case AGGR_DIE: 1590 case AGGR_SOCKET: 1591 case AGGR_NODE: 1592 if (config->cgroup_list) 1593 print_aggr_cgroup(con 1594 else 1595 print_aggr(config, ev 1596 break; 1597 case AGGR_THREAD: 1598 case AGGR_GLOBAL: 1599 if (config->iostat_run) { 1600 iostat_print_counters 1601 1602 } else if (config->cgroup_lis 1603 print_cgroup_counter( 1604 } else { 1605 print_metric_begin(co 1606 evlist__for_each_entr 1607 print_counter 1608 } 1609 print_metric_end(conf 1610 } 1611 break; 1612 case AGGR_NONE: 1613 if (metric_only) 1614 print_no_aggr_metric( 1615 else { 1616 evlist__for_each_entr 1617 if (counter-> 1618 print 1619 else 1620 print 1621 } 1622 } 1623 break; 1624 case AGGR_MAX: 1625 case AGGR_UNSET: 1626 default: 1627 break; 1628 } 1629 1630 print_footer(config); 1631 1632 fflush(config->output); 1633 } 1634
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.