1 #include <stdlib.h> 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 "debug.h" 11 #include "evlist.h" 12 #include "evsel.h" 13 #include "stat.h" 14 #include "top.h" 15 #include "thread_map.h" 16 #include "cpumap.h" 17 #include "string2.h" 18 #include <linux/ctype.h> 19 #include "cgroup.h" 20 #include <api/fs/fs.h> 21 #include "util.h" 22 #include "iostat.h" 23 #include "pmu.h" 24 #include "pmus.h" 25 #include "tool_pmu.h" 26 27 #define CNTR_NOT_SUPPORTED "<not supported>" 28 #define CNTR_NOT_COUNTED "<not counted>" 29 30 #define MGROUP_LEN 50 31 #define METRIC_LEN 38 32 #define EVNAME_LEN 32 33 #define COUNTS_LEN 18 34 #define INTERVAL_LEN 16 35 #define CGROUP_LEN 16 36 #define COMM_LEN 16 37 #define PID_LEN 7 38 #define CPUS_LEN 4 39 40 static int aggr_header_lens[] = { 41 [AGGR_CORE] = 18, 42 [AGGR_CACHE] = 22, 43 [AGGR_CLUSTER] = 20, 44 [AGGR_DIE] = 12, 45 [AGGR_SOCKET] = 6, 46 [AGGR_NODE] = 6, 47 [AGGR_NONE] = 6, 48 [AGGR_THREAD] = 16, 49 [AGGR_GLOBAL] = 0, 50 }; 51 52 static const char *aggr_header_csv[] = { 53 [AGGR_CORE] = "core,cpus,", 54 [AGGR_CACHE] = "cache,cpus,", 55 [AGGR_CLUSTER] = "cluster,cpus,", 56 [AGGR_DIE] = "die,cpus,", 57 [AGGR_SOCKET] = "socket,cpus,", 58 [AGGR_NONE] = "cpu,", 59 [AGGR_THREAD] = "comm-pid,", 60 [AGGR_NODE] = "node,", 61 [AGGR_GLOBAL] = "" 62 }; 63 64 static const char *aggr_header_std[] = { 65 [AGGR_CORE] = "core", 66 [AGGR_CACHE] = "cache", 67 [AGGR_CLUSTER] = "cluster", 68 [AGGR_DIE] = "die", 69 [AGGR_SOCKET] = "socket", 70 [AGGR_NONE] = "cpu", 71 [AGGR_THREAD] = "comm-pid", 72 [AGGR_NODE] = "node", 73 [AGGR_GLOBAL] = "" 74 }; 75 76 const char *metric_threshold_classify__color(enum metric_threshold_classify thresh) 77 { 78 const char * const colors[] = { 79 "", /* unknown */ 80 PERF_COLOR_RED, /* bad */ 81 PERF_COLOR_MAGENTA, /* nearly bad */ 82 PERF_COLOR_YELLOW, /* less good */ 83 PERF_COLOR_GREEN, /* good */ 84 }; 85 static_assert(ARRAY_SIZE(colors) - 1 == METRIC_THRESHOLD_GOOD, "missing enum value"); 86 return colors[thresh]; 87 } 88 89 static const char *metric_threshold_classify__str(enum metric_threshold_classify thresh) 90 { 91 const char * const strs[] = { 92 "unknown", 93 "bad", 94 "nearly bad", 95 "less good", 96 "good", 97 }; 98 static_assert(ARRAY_SIZE(strs) - 1 == METRIC_THRESHOLD_GOOD, "missing enum value"); 99 return strs[thresh]; 100 } 101 102 static void print_running_std(struct perf_stat_config *config, u64 run, u64 ena) 103 { 104 if (run != ena) 105 fprintf(config->output, " (%.2f%%)", 100.0 * run / ena); 106 } 107 108 static void print_running_csv(struct perf_stat_config *config, u64 run, u64 ena) 109 { 110 double enabled_percent = 100; 111 112 if (run != ena) 113 enabled_percent = 100 * run / ena; 114 fprintf(config->output, "%s%" PRIu64 "%s%.2f", 115 config->csv_sep, run, config->csv_sep, enabled_percent); 116 } 117 struct outstate { 118 /* Std mode: insert a newline before the next metric */ 119 bool newline; 120 /* JSON mode: track need for comma for a previous field or not */ 121 bool first; 122 /* Num CSV separators remaining to pad out when not all fields are printed */ 123 int csv_col_pad; 124 125 /* 126 * The following don't track state across fields, but are here as a shortcut to 127 * pass data to the print functions. The alternative would be to update the 128 * function signatures of the entire print stack to pass them through. 129 */ 130 /* Place to output to */ 131 FILE * const fh; 132 /* Lines are timestamped in --interval-print mode */ 133 char timestamp[64]; 134 /* Num items aggregated in current line. See struct perf_stat_aggr.nr */ 135 int aggr_nr; 136 /* Core/socket/die etc ID for the current line */ 137 struct aggr_cpu_id id; 138 /* Event for current line */ 139 struct evsel *evsel; 140 /* Cgroup for current line */ 141 struct cgroup *cgrp; 142 }; 143 144 static const char *json_sep(struct outstate *os) 145 { 146 const char *sep = os->first ? "" : ", "; 147 148 os->first = false; 149 return sep; 150 } 151 152 #define json_out(os, format, ...) fprintf((os)->fh, "%s" format, json_sep(os), ##__VA_ARGS__) 153 154 static void print_running_json(struct outstate *os, u64 run, u64 ena) 155 { 156 double enabled_percent = 100; 157 158 if (run != ena) 159 enabled_percent = 100 * run / ena; 160 json_out(os, "\"event-runtime\" : %" PRIu64 ", \"pcnt-running\" : %.2f", 161 run, enabled_percent); 162 } 163 164 static void print_running(struct perf_stat_config *config, struct outstate *os, 165 u64 run, u64 ena, bool before_metric) 166 { 167 if (config->json_output) { 168 if (before_metric) 169 print_running_json(os, run, ena); 170 } else if (config->csv_output) { 171 if (before_metric) 172 print_running_csv(config, run, ena); 173 } else { 174 if (!before_metric) 175 print_running_std(config, run, ena); 176 } 177 } 178 179 static void print_noise_pct_std(struct perf_stat_config *config, 180 double pct) 181 { 182 if (pct) 183 fprintf(config->output, " ( +-%6.2f%% )", pct); 184 } 185 186 static void print_noise_pct_csv(struct perf_stat_config *config, 187 double pct) 188 { 189 fprintf(config->output, "%s%.2f%%", config->csv_sep, pct); 190 } 191 192 static void print_noise_pct_json(struct outstate *os, 193 double pct) 194 { 195 json_out(os, "\"variance\" : %.2f", pct); 196 } 197 198 static void print_noise_pct(struct perf_stat_config *config, struct outstate *os, 199 double total, double avg, bool before_metric) 200 { 201 double pct = rel_stddev_stats(total, avg); 202 203 if (config->json_output) { 204 if (before_metric) 205 print_noise_pct_json(os, pct); 206 } else if (config->csv_output) { 207 if (before_metric) 208 print_noise_pct_csv(config, pct); 209 } else { 210 if (!before_metric) 211 print_noise_pct_std(config, pct); 212 } 213 } 214 215 static void print_noise(struct perf_stat_config *config, struct outstate *os, 216 struct evsel *evsel, double avg, bool before_metric) 217 { 218 struct perf_stat_evsel *ps; 219 220 if (config->run_count == 1) 221 return; 222 223 ps = evsel->stats; 224 print_noise_pct(config, os, stddev_stats(&ps->res_stats), avg, before_metric); 225 } 226 227 static void print_cgroup_std(struct perf_stat_config *config, const char *cgrp_name) 228 { 229 fprintf(config->output, " %-*s", CGROUP_LEN, cgrp_name); 230 } 231 232 static void print_cgroup_csv(struct perf_stat_config *config, const char *cgrp_name) 233 { 234 fprintf(config->output, "%s%s", config->csv_sep, cgrp_name); 235 } 236 237 static void print_cgroup_json(struct outstate *os, const char *cgrp_name) 238 { 239 json_out(os, "\"cgroup\" : \"%s\"", cgrp_name); 240 } 241 242 static void print_cgroup(struct perf_stat_config *config, struct outstate *os, 243 struct cgroup *cgrp) 244 { 245 if (nr_cgroups || config->cgroup_list) { 246 const char *cgrp_name = cgrp ? cgrp->name : ""; 247 248 if (config->json_output) 249 print_cgroup_json(os, cgrp_name); 250 else if (config->csv_output) 251 print_cgroup_csv(config, cgrp_name); 252 else 253 print_cgroup_std(config, cgrp_name); 254 } 255 } 256 257 static void print_aggr_id_std(struct perf_stat_config *config, 258 struct evsel *evsel, struct aggr_cpu_id id, int aggr_nr) 259 { 260 FILE *output = config->output; 261 int idx = config->aggr_mode; 262 char buf[128]; 263 264 switch (config->aggr_mode) { 265 case AGGR_CORE: 266 snprintf(buf, sizeof(buf), "S%d-D%d-C%d", id.socket, id.die, id.core); 267 break; 268 case AGGR_CACHE: 269 snprintf(buf, sizeof(buf), "S%d-D%d-L%d-ID%d", 270 id.socket, id.die, id.cache_lvl, id.cache); 271 break; 272 case AGGR_CLUSTER: 273 snprintf(buf, sizeof(buf), "S%d-D%d-CLS%d", id.socket, id.die, id.cluster); 274 break; 275 case AGGR_DIE: 276 snprintf(buf, sizeof(buf), "S%d-D%d", id.socket, id.die); 277 break; 278 case AGGR_SOCKET: 279 snprintf(buf, sizeof(buf), "S%d", id.socket); 280 break; 281 case AGGR_NODE: 282 snprintf(buf, sizeof(buf), "N%d", id.node); 283 break; 284 case AGGR_NONE: 285 if (evsel->percore && !config->percore_show_thread) { 286 snprintf(buf, sizeof(buf), "S%d-D%d-C%d ", 287 id.socket, id.die, id.core); 288 fprintf(output, "%-*s ", 289 aggr_header_lens[AGGR_CORE], buf); 290 } else if (id.cpu.cpu > -1) { 291 fprintf(output, "CPU%-*d ", 292 aggr_header_lens[AGGR_NONE] - 3, id.cpu.cpu); 293 } 294 return; 295 case AGGR_THREAD: 296 fprintf(output, "%*s-%-*d ", 297 COMM_LEN, perf_thread_map__comm(evsel->core.threads, id.thread_idx), 298 PID_LEN, perf_thread_map__pid(evsel->core.threads, id.thread_idx)); 299 return; 300 case AGGR_GLOBAL: 301 case AGGR_UNSET: 302 case AGGR_MAX: 303 default: 304 return; 305 } 306 307 fprintf(output, "%-*s %*d ", aggr_header_lens[idx], buf, 4, aggr_nr); 308 } 309 310 static void print_aggr_id_csv(struct perf_stat_config *config, 311 struct evsel *evsel, struct aggr_cpu_id id, int aggr_nr) 312 { 313 FILE *output = config->output; 314 const char *sep = config->csv_sep; 315 316 switch (config->aggr_mode) { 317 case AGGR_CORE: 318 fprintf(output, "S%d-D%d-C%d%s%d%s", 319 id.socket, id.die, id.core, sep, aggr_nr, sep); 320 break; 321 case AGGR_CACHE: 322 fprintf(config->output, "S%d-D%d-L%d-ID%d%s%d%s", 323 id.socket, id.die, id.cache_lvl, id.cache, sep, aggr_nr, sep); 324 break; 325 case AGGR_CLUSTER: 326 fprintf(config->output, "S%d-D%d-CLS%d%s%d%s", 327 id.socket, id.die, id.cluster, sep, aggr_nr, sep); 328 break; 329 case AGGR_DIE: 330 fprintf(output, "S%d-D%d%s%d%s", 331 id.socket, id.die, sep, aggr_nr, sep); 332 break; 333 case AGGR_SOCKET: 334 fprintf(output, "S%d%s%d%s", 335 id.socket, sep, aggr_nr, sep); 336 break; 337 case AGGR_NODE: 338 fprintf(output, "N%d%s%d%s", 339 id.node, sep, aggr_nr, sep); 340 break; 341 case AGGR_NONE: 342 if (evsel->percore && !config->percore_show_thread) { 343 fprintf(output, "S%d-D%d-C%d%s", 344 id.socket, id.die, id.core, sep); 345 } else if (id.cpu.cpu > -1) { 346 fprintf(output, "CPU%d%s", 347 id.cpu.cpu, sep); 348 } 349 break; 350 case AGGR_THREAD: 351 fprintf(output, "%s-%d%s", 352 perf_thread_map__comm(evsel->core.threads, id.thread_idx), 353 perf_thread_map__pid(evsel->core.threads, id.thread_idx), 354 sep); 355 break; 356 case AGGR_GLOBAL: 357 case AGGR_UNSET: 358 case AGGR_MAX: 359 default: 360 break; 361 } 362 } 363 364 static void print_aggr_id_json(struct perf_stat_config *config, struct outstate *os, 365 struct evsel *evsel, struct aggr_cpu_id id, int aggr_nr) 366 { 367 switch (config->aggr_mode) { 368 case AGGR_CORE: 369 json_out(os, "\"core\" : \"S%d-D%d-C%d\", \"aggregate-number\" : %d", 370 id.socket, id.die, id.core, aggr_nr); 371 break; 372 case AGGR_CACHE: 373 json_out(os, "\"cache\" : \"S%d-D%d-L%d-ID%d\", \"aggregate-number\" : %d", 374 id.socket, id.die, id.cache_lvl, id.cache, aggr_nr); 375 break; 376 case AGGR_CLUSTER: 377 json_out(os, "\"cluster\" : \"S%d-D%d-CLS%d\", \"aggregate-number\" : %d", 378 id.socket, id.die, id.cluster, aggr_nr); 379 break; 380 case AGGR_DIE: 381 json_out(os, "\"die\" : \"S%d-D%d\", \"aggregate-number\" : %d", 382 id.socket, id.die, aggr_nr); 383 break; 384 case AGGR_SOCKET: 385 json_out(os, "\"socket\" : \"S%d\", \"aggregate-number\" : %d", 386 id.socket, aggr_nr); 387 break; 388 case AGGR_NODE: 389 json_out(os, "\"node\" : \"N%d\", \"aggregate-number\" : %d", 390 id.node, aggr_nr); 391 break; 392 case AGGR_NONE: 393 if (evsel->percore && !config->percore_show_thread) { 394 json_out(os, "\"core\" : \"S%d-D%d-C%d\"", 395 id.socket, id.die, id.core); 396 } else if (id.cpu.cpu > -1) { 397 json_out(os, "\"cpu\" : \"%d\"", 398 id.cpu.cpu); 399 } 400 break; 401 case AGGR_THREAD: 402 json_out(os, "\"thread\" : \"%s-%d\"", 403 perf_thread_map__comm(evsel->core.threads, id.thread_idx), 404 perf_thread_map__pid(evsel->core.threads, id.thread_idx)); 405 break; 406 case AGGR_GLOBAL: 407 case AGGR_UNSET: 408 case AGGR_MAX: 409 default: 410 break; 411 } 412 } 413 414 static void aggr_printout(struct perf_stat_config *config, struct outstate *os, 415 struct evsel *evsel, struct aggr_cpu_id id, int aggr_nr) 416 { 417 if (config->json_output) 418 print_aggr_id_json(config, os, evsel, id, aggr_nr); 419 else if (config->csv_output) 420 print_aggr_id_csv(config, evsel, id, aggr_nr); 421 else 422 print_aggr_id_std(config, evsel, id, aggr_nr); 423 } 424 425 static void new_line_std(struct perf_stat_config *config __maybe_unused, 426 void *ctx) 427 { 428 struct outstate *os = ctx; 429 430 os->newline = true; 431 } 432 433 static inline void __new_line_std_csv(struct perf_stat_config *config, 434 struct outstate *os) 435 { 436 fputc('\n', os->fh); 437 if (config->interval) 438 fputs(os->timestamp, os->fh); 439 aggr_printout(config, os, os->evsel, os->id, os->aggr_nr); 440 } 441 442 static inline void __new_line_std(struct outstate *os) 443 { 444 fprintf(os->fh, " "); 445 } 446 447 static void do_new_line_std(struct perf_stat_config *config, 448 struct outstate *os) 449 { 450 __new_line_std_csv(config, os); 451 if (config->aggr_mode == AGGR_NONE) 452 fprintf(os->fh, " "); 453 __new_line_std(os); 454 } 455 456 static void print_metric_std(struct perf_stat_config *config, 457 void *ctx, enum metric_threshold_classify thresh, 458 const char *fmt, const char *unit, double val) 459 { 460 struct outstate *os = ctx; 461 FILE *out = os->fh; 462 int n; 463 bool newline = os->newline; 464 const char *color = metric_threshold_classify__color(thresh); 465 466 os->newline = false; 467 468 if (unit == NULL || fmt == NULL) { 469 fprintf(out, "%-*s", METRIC_LEN, ""); 470 return; 471 } 472 473 if (newline) 474 do_new_line_std(config, os); 475 476 n = fprintf(out, " # "); 477 if (color) 478 n += color_fprintf(out, color, fmt, val); 479 else 480 n += fprintf(out, fmt, val); 481 fprintf(out, " %-*s", METRIC_LEN - n - 1, unit); 482 } 483 484 static void new_line_csv(struct perf_stat_config *config, void *ctx) 485 { 486 struct outstate *os = ctx; 487 int i; 488 489 __new_line_std_csv(config, os); 490 for (i = 0; i < os->csv_col_pad; i++) 491 fputs(config->csv_sep, os->fh); 492 } 493 494 static void print_metric_csv(struct perf_stat_config *config __maybe_unused, 495 void *ctx, 496 enum metric_threshold_classify thresh __maybe_unused, 497 const char *fmt, const char *unit, double val) 498 { 499 struct outstate *os = ctx; 500 FILE *out = os->fh; 501 char buf[64], *vals, *ends; 502 503 if (unit == NULL || fmt == NULL) { 504 fprintf(out, "%s%s", config->csv_sep, config->csv_sep); 505 return; 506 } 507 snprintf(buf, sizeof(buf), fmt, val); 508 ends = vals = skip_spaces(buf); 509 while (isdigit(*ends) || *ends == '.') 510 ends++; 511 *ends = 0; 512 fprintf(out, "%s%s%s%s", config->csv_sep, vals, config->csv_sep, skip_spaces(unit)); 513 } 514 515 static void print_metric_json(struct perf_stat_config *config __maybe_unused, 516 void *ctx, 517 enum metric_threshold_classify thresh, 518 const char *fmt __maybe_unused, 519 const char *unit, double val) 520 { 521 struct outstate *os = ctx; 522 FILE *out = os->fh; 523 524 if (unit) { 525 json_out(os, "\"metric-value\" : \"%f\", \"metric-unit\" : \"%s\"", val, unit); 526 if (thresh != METRIC_THRESHOLD_UNKNOWN) { 527 json_out(os, "\"metric-threshold\" : \"%s\"", 528 metric_threshold_classify__str(thresh)); 529 } 530 } 531 if (!config->metric_only) 532 fprintf(out, "}"); 533 } 534 535 static void new_line_json(struct perf_stat_config *config, void *ctx) 536 { 537 struct outstate *os = ctx; 538 539 fputs("\n{", os->fh); 540 os->first = true; 541 if (config->interval) 542 json_out(os, "%s", os->timestamp); 543 544 aggr_printout(config, os, os->evsel, os->id, os->aggr_nr); 545 } 546 547 static void print_metricgroup_header_json(struct perf_stat_config *config, 548 void *ctx, 549 const char *metricgroup_name) 550 { 551 if (!metricgroup_name) 552 return; 553 554 json_out((struct outstate *) ctx, "\"metricgroup\" : \"%s\"}", metricgroup_name); 555 new_line_json(config, ctx); 556 } 557 558 static void print_metricgroup_header_csv(struct perf_stat_config *config, 559 void *ctx, 560 const char *metricgroup_name) 561 { 562 struct outstate *os = ctx; 563 int i; 564 565 if (!metricgroup_name) { 566 /* Leave space for running and enabling */ 567 for (i = 0; i < os->csv_col_pad - 2; i++) 568 fputs(config->csv_sep, os->fh); 569 return; 570 } 571 572 for (i = 0; i < os->csv_col_pad; i++) 573 fputs(config->csv_sep, os->fh); 574 fprintf(config->output, "%s", metricgroup_name); 575 new_line_csv(config, ctx); 576 } 577 578 static void print_metricgroup_header_std(struct perf_stat_config *config, 579 void *ctx, 580 const char *metricgroup_name) 581 { 582 struct outstate *os = ctx; 583 int n; 584 585 if (!metricgroup_name) { 586 __new_line_std(os); 587 return; 588 } 589 590 n = fprintf(config->output, " %*s", EVNAME_LEN, metricgroup_name); 591 592 fprintf(config->output, "%*s", MGROUP_LEN - n - 1, ""); 593 } 594 595 /* Filter out some columns that don't work well in metrics only mode */ 596 597 static bool valid_only_metric(const char *unit) 598 { 599 if (!unit) 600 return false; 601 if (strstr(unit, "/sec") || 602 strstr(unit, "CPUs utilized")) 603 return false; 604 return true; 605 } 606 607 static const char *fixunit(char *buf, struct evsel *evsel, 608 const char *unit) 609 { 610 if (!strncmp(unit, "of all", 6)) { 611 snprintf(buf, 1024, "%s %s", evsel__name(evsel), 612 unit); 613 return buf; 614 } 615 return unit; 616 } 617 618 static void print_metric_only(struct perf_stat_config *config, 619 void *ctx, enum metric_threshold_classify thresh, 620 const char *fmt, const char *unit, double val) 621 { 622 struct outstate *os = ctx; 623 FILE *out = os->fh; 624 char buf[1024], str[1024]; 625 unsigned mlen = config->metric_only_len; 626 const char *color = metric_threshold_classify__color(thresh); 627 628 if (!valid_only_metric(unit)) 629 return; 630 unit = fixunit(buf, os->evsel, unit); 631 if (mlen < strlen(unit)) 632 mlen = strlen(unit) + 1; 633 634 if (color) 635 mlen += strlen(color) + sizeof(PERF_COLOR_RESET) - 1; 636 637 color_snprintf(str, sizeof(str), color ?: "", fmt ?: "", val); 638 fprintf(out, "%*s ", mlen, str); 639 os->first = false; 640 } 641 642 static void print_metric_only_csv(struct perf_stat_config *config __maybe_unused, 643 void *ctx, 644 enum metric_threshold_classify thresh __maybe_unused, 645 const char *fmt, 646 const char *unit, double val) 647 { 648 struct outstate *os = ctx; 649 FILE *out = os->fh; 650 char buf[64], *vals, *ends; 651 char tbuf[1024]; 652 653 if (!valid_only_metric(unit)) 654 return; 655 unit = fixunit(tbuf, os->evsel, unit); 656 snprintf(buf, sizeof(buf), fmt ?: "", val); 657 ends = vals = skip_spaces(buf); 658 while (isdigit(*ends) || *ends == '.') 659 ends++; 660 *ends = 0; 661 fprintf(out, "%s%s", vals, config->csv_sep); 662 os->first = false; 663 } 664 665 static void print_metric_only_json(struct perf_stat_config *config __maybe_unused, 666 void *ctx, 667 enum metric_threshold_classify thresh __maybe_unused, 668 const char *fmt, 669 const char *unit, double val) 670 { 671 struct outstate *os = ctx; 672 char buf[64], *ends; 673 char tbuf[1024]; 674 const char *vals; 675 676 if (!valid_only_metric(unit)) 677 return; 678 unit = fixunit(tbuf, os->evsel, unit); 679 if (!unit[0]) 680 return; 681 snprintf(buf, sizeof(buf), fmt ?: "", val); 682 vals = ends = skip_spaces(buf); 683 while (isdigit(*ends) || *ends == '.') 684 ends++; 685 *ends = 0; 686 if (!vals[0]) 687 vals = "none"; 688 json_out(os, "\"%s\" : \"%s\"", unit, vals); 689 } 690 691 static void print_metric_header(struct perf_stat_config *config, 692 void *ctx, 693 enum metric_threshold_classify thresh __maybe_unused, 694 const char *fmt __maybe_unused, 695 const char *unit, double val __maybe_unused) 696 { 697 struct outstate *os = ctx; 698 char tbuf[1024]; 699 700 /* In case of iostat, print metric header for first root port only */ 701 if (config->iostat_run && 702 os->evsel->priv != os->evsel->evlist->selected->priv) 703 return; 704 705 if (os->evsel->cgrp != os->cgrp) 706 return; 707 708 if (!valid_only_metric(unit)) 709 return; 710 unit = fixunit(tbuf, os->evsel, unit); 711 712 if (config->json_output) 713 return; 714 else if (config->csv_output) 715 fprintf(os->fh, "%s%s", unit, config->csv_sep); 716 else 717 fprintf(os->fh, "%*s ", config->metric_only_len, unit); 718 } 719 720 static void print_counter_value_std(struct perf_stat_config *config, 721 struct evsel *evsel, double avg, bool ok) 722 { 723 FILE *output = config->output; 724 double sc = evsel->scale; 725 const char *fmt; 726 const char *bad_count = evsel->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED; 727 728 if (config->big_num) 729 fmt = floor(sc) != sc ? "%'*.2f " : "%'*.0f "; 730 else 731 fmt = floor(sc) != sc ? "%*.2f " : "%*.0f "; 732 733 if (ok) 734 fprintf(output, fmt, COUNTS_LEN, avg); 735 else 736 fprintf(output, "%*s ", COUNTS_LEN, bad_count); 737 738 if (evsel->unit) 739 fprintf(output, "%-*s ", config->unit_width, evsel->unit); 740 741 fprintf(output, "%-*s", EVNAME_LEN, evsel__name(evsel)); 742 } 743 744 static void print_counter_value_csv(struct perf_stat_config *config, 745 struct evsel *evsel, double avg, bool ok) 746 { 747 FILE *output = config->output; 748 double sc = evsel->scale; 749 const char *sep = config->csv_sep; 750 const char *fmt = floor(sc) != sc ? "%.2f%s" : "%.0f%s"; 751 const char *bad_count = evsel->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED; 752 753 if (ok) 754 fprintf(output, fmt, avg, sep); 755 else 756 fprintf(output, "%s%s", bad_count, sep); 757 758 if (evsel->unit) 759 fprintf(output, "%s%s", evsel->unit, sep); 760 761 fprintf(output, "%s", evsel__name(evsel)); 762 } 763 764 static void print_counter_value_json(struct outstate *os, 765 struct evsel *evsel, double avg, bool ok) 766 { 767 const char *bad_count = evsel->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED; 768 769 if (ok) 770 json_out(os, "\"counter-value\" : \"%f\"", avg); 771 else 772 json_out(os, "\"counter-value\" : \"%s\"", bad_count); 773 774 if (evsel->unit) 775 json_out(os, "\"unit\" : \"%s\"", evsel->unit); 776 777 json_out(os, "\"event\" : \"%s\"", evsel__name(evsel)); 778 } 779 780 static void print_counter_value(struct perf_stat_config *config, struct outstate *os, 781 struct evsel *evsel, double avg, bool ok) 782 { 783 if (config->json_output) 784 print_counter_value_json(os, evsel, avg, ok); 785 else if (config->csv_output) 786 print_counter_value_csv(config, evsel, avg, ok); 787 else 788 print_counter_value_std(config, evsel, avg, ok); 789 } 790 791 static void abs_printout(struct perf_stat_config *config, 792 struct outstate *os, 793 struct aggr_cpu_id id, int aggr_nr, 794 struct evsel *evsel, double avg, bool ok) 795 { 796 aggr_printout(config, os, evsel, id, aggr_nr); 797 print_counter_value(config, os, evsel, avg, ok); 798 print_cgroup(config, os, evsel->cgrp); 799 } 800 801 static bool is_mixed_hw_group(struct evsel *counter) 802 { 803 struct evlist *evlist = counter->evlist; 804 u32 pmu_type = counter->core.attr.type; 805 struct evsel *pos; 806 807 if (counter->core.nr_members < 2) 808 return false; 809 810 evlist__for_each_entry(evlist, pos) { 811 /* software events can be part of any hardware group */ 812 if (pos->core.attr.type == PERF_TYPE_SOFTWARE) 813 continue; 814 if (pmu_type == PERF_TYPE_SOFTWARE) { 815 pmu_type = pos->core.attr.type; 816 continue; 817 } 818 if (pmu_type != pos->core.attr.type) 819 return true; 820 } 821 822 return false; 823 } 824 825 static bool evlist__has_hybrid(struct evlist *evlist) 826 { 827 struct evsel *evsel; 828 829 if (perf_pmus__num_core_pmus() == 1) 830 return false; 831 832 evlist__for_each_entry(evlist, evsel) { 833 if (evsel->core.is_pmu_core) 834 return true; 835 } 836 837 return false; 838 } 839 840 static void printout(struct perf_stat_config *config, struct outstate *os, 841 double uval, u64 run, u64 ena, double noise, int aggr_idx) 842 { 843 struct perf_stat_output_ctx out; 844 print_metric_t pm; 845 new_line_t nl; 846 print_metricgroup_header_t pmh; 847 bool ok = true; 848 struct evsel *counter = os->evsel; 849 850 if (config->csv_output) { 851 pm = config->metric_only ? print_metric_only_csv : print_metric_csv; 852 nl = config->metric_only ? NULL : new_line_csv; 853 pmh = print_metricgroup_header_csv; 854 os->csv_col_pad = 4 + (counter->cgrp ? 1 : 0); 855 } else if (config->json_output) { 856 pm = config->metric_only ? print_metric_only_json : print_metric_json; 857 nl = config->metric_only ? NULL : new_line_json; 858 pmh = print_metricgroup_header_json; 859 } else { 860 pm = config->metric_only ? print_metric_only : print_metric_std; 861 nl = config->metric_only ? NULL : new_line_std; 862 pmh = print_metricgroup_header_std; 863 } 864 865 if (run == 0 || ena == 0 || counter->counts->scaled == -1) { 866 if (config->metric_only) { 867 pm(config, os, METRIC_THRESHOLD_UNKNOWN, /*format=*/NULL, 868 /*unit=*/NULL, /*val=*/0); 869 return; 870 } 871 872 ok = false; 873 874 if (counter->supported) { 875 if (!evlist__has_hybrid(counter->evlist)) { 876 config->print_free_counters_hint = 1; 877 if (is_mixed_hw_group(counter)) 878 config->print_mixed_hw_group_error = 1; 879 } 880 } 881 } 882 883 out.print_metric = pm; 884 out.new_line = nl; 885 out.print_metricgroup_header = pmh; 886 out.ctx = os; 887 out.force_header = false; 888 889 if (!config->metric_only && !counter->default_metricgroup) { 890 abs_printout(config, os, os->id, os->aggr_nr, counter, uval, ok); 891 892 print_noise(config, os, counter, noise, /*before_metric=*/true); 893 print_running(config, os, run, ena, /*before_metric=*/true); 894 } 895 896 if (ok) { 897 if (!config->metric_only && counter->default_metricgroup) { 898 void *from = NULL; 899 900 aggr_printout(config, os, os->evsel, os->id, os->aggr_nr); 901 /* Print out all the metricgroup with the same metric event. */ 902 do { 903 int num = 0; 904 905 /* Print out the new line for the next new metricgroup. */ 906 if (from) { 907 if (config->json_output) 908 new_line_json(config, (void *)os); 909 else 910 __new_line_std_csv(config, os); 911 } 912 913 print_noise(config, os, counter, noise, /*before_metric=*/true); 914 print_running(config, os, run, ena, /*before_metric=*/true); 915 from = perf_stat__print_shadow_stats_metricgroup(config, counter, aggr_idx, 916 &num, from, &out, 917 &config->metric_events); 918 } while (from != NULL); 919 } else 920 perf_stat__print_shadow_stats(config, counter, uval, aggr_idx, 921 &out, &config->metric_events); 922 } else { 923 pm(config, os, METRIC_THRESHOLD_UNKNOWN, /*format=*/NULL, /*unit=*/NULL, /*val=*/0); 924 } 925 926 if (!config->metric_only) { 927 print_noise(config, os, counter, noise, /*before_metric=*/false); 928 print_running(config, os, run, ena, /*before_metric=*/false); 929 } 930 } 931 932 static void evsel__uniquify_counter(struct evsel *counter) 933 { 934 const char *name, *pmu_name; 935 char *new_name, *config; 936 int ret; 937 938 /* No uniquification necessary. */ 939 if (!counter->needs_uniquify) 940 return; 941 942 /* The evsel was already uniquified. */ 943 if (counter->uniquified_name) 944 return; 945 946 /* Avoid checking to uniquify twice. */ 947 counter->uniquified_name = true; 948 949 name = evsel__name(counter); 950 pmu_name = counter->pmu->name; 951 /* Already prefixed by the PMU name. */ 952 if (!strncmp(name, pmu_name, strlen(pmu_name))) 953 return; 954 955 config = strchr(name, '/'); 956 if (config) { 957 int len = config - name; 958 959 if (config[1] == '/') { 960 /* case: event// */ 961 ret = asprintf(&new_name, "%s/%.*s/%s", pmu_name, len, name, config + 2); 962 } else { 963 /* case: event/.../ */ 964 ret = asprintf(&new_name, "%s/%.*s,%s", pmu_name, len, name, config + 1); 965 } 966 } else { 967 config = strchr(name, ':'); 968 if (config) { 969 /* case: event:.. */ 970 int len = config - name; 971 972 ret = asprintf(&new_name, "%s/%.*s/%s", pmu_name, len, name, config + 1); 973 } else { 974 /* case: event */ 975 ret = asprintf(&new_name, "%s/%s/", pmu_name, name); 976 } 977 } 978 if (ret > 0) { 979 free(counter->name); 980 counter->name = new_name; 981 } else { 982 /* ENOMEM from asprintf. */ 983 counter->uniquified_name = false; 984 } 985 } 986 987 /** 988 * should_skip_zero_count() - Check if the event should print 0 values. 989 * @config: The perf stat configuration (including aggregation mode). 990 * @counter: The evsel with its associated cpumap. 991 * @id: The aggregation id that is being queried. 992 * 993 * Due to mismatch between the event cpumap or thread-map and the 994 * aggregation mode, sometimes it'd iterate the counter with the map 995 * which does not contain any values. 996 * 997 * For example, uncore events have dedicated CPUs to manage them, 998 * result for other CPUs should be zero and skipped. 999 * 1000 * Return: %true if the value should NOT be printed, %false if the value 1001 * needs to be printed like "<not counted>" or "<not supported>". 1002 */ 1003 static bool should_skip_zero_counter(struct perf_stat_config *config, 1004 struct evsel *counter, 1005 const struct aggr_cpu_id *id) 1006 { 1007 struct perf_cpu cpu; 1008 int idx; 1009 1010 /* 1011 * Skip unsupported default events when not verbose. (default events 1012 * are all marked 'skippable'). 1013 */ 1014 if (verbose == 0 && counter->skippable && !counter->supported) 1015 return true; 1016 1017 /* 1018 * Skip value 0 when enabling --per-thread globally, 1019 * otherwise it will have too many 0 output. 1020 */ 1021 if (config->aggr_mode == AGGR_THREAD && config->system_wide) 1022 return true; 1023 1024 /* 1025 * Many tool events are only gathered on the first index, skip other 1026 * zero values. 1027 */ 1028 if (evsel__is_tool(counter)) { 1029 struct aggr_cpu_id own_id = 1030 config->aggr_get_id(config, (struct perf_cpu){ .cpu = 0 }); 1031 1032 return !aggr_cpu_id__equal(id, &own_id); 1033 } 1034 1035 /* 1036 * Skip value 0 when it's an uncore event and the given aggr id 1037 * does not belong to the PMU cpumask. 1038 */ 1039 if (!counter->pmu || !counter->pmu->is_uncore) 1040 return false; 1041 1042 perf_cpu_map__for_each_cpu(cpu, idx, counter->pmu->cpus) { 1043 struct aggr_cpu_id own_id = config->aggr_get_id(config, cpu); 1044 1045 if (aggr_cpu_id__equal(id, &own_id)) 1046 return false; 1047 } 1048 return true; 1049 } 1050 1051 static void print_counter_aggrdata(struct perf_stat_config *config, 1052 struct evsel *counter, int aggr_idx, 1053 struct outstate *os) 1054 { 1055 FILE *output = config->output; 1056 u64 ena, run, val; 1057 double uval; 1058 struct perf_stat_evsel *ps = counter->stats; 1059 struct perf_stat_aggr *aggr = &ps->aggr[aggr_idx]; 1060 struct aggr_cpu_id id = config->aggr_map->map[aggr_idx]; 1061 double avg = aggr->counts.val; 1062 bool metric_only = config->metric_only; 1063 1064 os->id = id; 1065 os->aggr_nr = aggr->nr; 1066 os->evsel = counter; 1067 1068 /* Skip already merged uncore/hybrid events */ 1069 if (counter->merged_stat) 1070 return; 1071 1072 evsel__uniquify_counter(counter); 1073 1074 val = aggr->counts.val; 1075 ena = aggr->counts.ena; 1076 run = aggr->counts.run; 1077 1078 if (perf_stat__skip_metric_event(counter, &config->metric_events, ena, run)) 1079 return; 1080 1081 if (val == 0 && should_skip_zero_counter(config, counter, &id)) 1082 return; 1083 1084 if (!metric_only) { 1085 if (config->json_output) { 1086 os->first = true; 1087 fputc('{', output); 1088 } 1089 if (config->interval) { 1090 if (config->json_output) 1091 json_out(os, "%s", os->timestamp); 1092 else 1093 fprintf(output, "%s", os->timestamp); 1094 } else if (config->summary && config->csv_output && 1095 !config->no_csv_summary) 1096 fprintf(output, "%s%s", "summary", config->csv_sep); 1097 } 1098 1099 uval = val * counter->scale; 1100 1101 printout(config, os, uval, run, ena, avg, aggr_idx); 1102 1103 if (!metric_only) 1104 fputc('\n', output); 1105 } 1106 1107 static void print_metric_begin(struct perf_stat_config *config, 1108 struct evlist *evlist, 1109 struct outstate *os, int aggr_idx) 1110 { 1111 struct perf_stat_aggr *aggr; 1112 struct aggr_cpu_id id; 1113 struct evsel *evsel; 1114 1115 os->first = true; 1116 if (!config->metric_only) 1117 return; 1118 1119 if (config->json_output) 1120 fputc('{', config->output); 1121 1122 if (config->interval) { 1123 if (config->json_output) 1124 json_out(os, "%s", os->timestamp); 1125 else 1126 fprintf(config->output, "%s", os->timestamp); 1127 } 1128 evsel = evlist__first(evlist); 1129 id = config->aggr_map->map[aggr_idx]; 1130 aggr = &evsel->stats->aggr[aggr_idx]; 1131 aggr_printout(config, os, evsel, id, aggr->nr); 1132 1133 print_cgroup(config, os, os->cgrp ? : evsel->cgrp); 1134 } 1135 1136 static void print_metric_end(struct perf_stat_config *config, struct outstate *os) 1137 { 1138 FILE *output = config->output; 1139 1140 if (!config->metric_only) 1141 return; 1142 1143 if (config->json_output) { 1144 if (os->first) 1145 fputs("\"metric-value\" : \"none\"", output); 1146 fputc('}', output); 1147 } 1148 fputc('\n', output); 1149 } 1150 1151 static void print_aggr(struct perf_stat_config *config, 1152 struct evlist *evlist, 1153 struct outstate *os) 1154 { 1155 struct evsel *counter; 1156 int aggr_idx; 1157 1158 if (!config->aggr_map || !config->aggr_get_id) 1159 return; 1160 1161 /* 1162 * With metric_only everything is on a single line. 1163 * Without each counter has its own line. 1164 */ 1165 cpu_aggr_map__for_each_idx(aggr_idx, config->aggr_map) { 1166 print_metric_begin(config, evlist, os, aggr_idx); 1167 1168 evlist__for_each_entry(evlist, counter) { 1169 print_counter_aggrdata(config, counter, aggr_idx, os); 1170 } 1171 print_metric_end(config, os); 1172 } 1173 } 1174 1175 static void print_aggr_cgroup(struct perf_stat_config *config, 1176 struct evlist *evlist, 1177 struct outstate *os) 1178 { 1179 struct evsel *counter, *evsel; 1180 int aggr_idx; 1181 1182 if (!config->aggr_map || !config->aggr_get_id) 1183 return; 1184 1185 evlist__for_each_entry(evlist, evsel) { 1186 if (os->cgrp == evsel->cgrp) 1187 continue; 1188 1189 os->cgrp = evsel->cgrp; 1190 1191 cpu_aggr_map__for_each_idx(aggr_idx, config->aggr_map) { 1192 print_metric_begin(config, evlist, os, aggr_idx); 1193 1194 evlist__for_each_entry(evlist, counter) { 1195 if (counter->cgrp != os->cgrp) 1196 continue; 1197 1198 print_counter_aggrdata(config, counter, aggr_idx, os); 1199 } 1200 print_metric_end(config, os); 1201 } 1202 } 1203 } 1204 1205 static void print_counter(struct perf_stat_config *config, 1206 struct evsel *counter, struct outstate *os) 1207 { 1208 int aggr_idx; 1209 1210 /* AGGR_THREAD doesn't have config->aggr_get_id */ 1211 if (!config->aggr_map) 1212 return; 1213 1214 cpu_aggr_map__for_each_idx(aggr_idx, config->aggr_map) { 1215 print_counter_aggrdata(config, counter, aggr_idx, os); 1216 } 1217 } 1218 1219 static void print_no_aggr_metric(struct perf_stat_config *config, 1220 struct evlist *evlist, 1221 struct outstate *os) 1222 { 1223 int all_idx; 1224 struct perf_cpu cpu; 1225 1226 perf_cpu_map__for_each_cpu(cpu, all_idx, evlist->core.user_requested_cpus) { 1227 struct evsel *counter; 1228 bool first = true; 1229 1230 evlist__for_each_entry(evlist, counter) { 1231 u64 ena, run, val; 1232 double uval; 1233 struct perf_stat_evsel *ps = counter->stats; 1234 int aggr_idx = 0; 1235 1236 if (!perf_cpu_map__has(evsel__cpus(counter), cpu)) 1237 continue; 1238 1239 cpu_aggr_map__for_each_idx(aggr_idx, config->aggr_map) { 1240 if (config->aggr_map->map[aggr_idx].cpu.cpu == cpu.cpu) 1241 break; 1242 } 1243 1244 os->evsel = counter; 1245 os->id = aggr_cpu_id__cpu(cpu, /*data=*/NULL); 1246 if (first) { 1247 print_metric_begin(config, evlist, os, aggr_idx); 1248 first = false; 1249 } 1250 val = ps->aggr[aggr_idx].counts.val; 1251 ena = ps->aggr[aggr_idx].counts.ena; 1252 run = ps->aggr[aggr_idx].counts.run; 1253 1254 uval = val * counter->scale; 1255 printout(config, os, uval, run, ena, 1.0, aggr_idx); 1256 } 1257 if (!first) 1258 print_metric_end(config, os); 1259 } 1260 } 1261 1262 static void print_metric_headers_std(struct perf_stat_config *config, 1263 bool no_indent) 1264 { 1265 fputc(' ', config->output); 1266 1267 if (!no_indent) { 1268 int len = aggr_header_lens[config->aggr_mode]; 1269 1270 if (nr_cgroups || config->cgroup_list) 1271 len += CGROUP_LEN + 1; 1272 1273 fprintf(config->output, "%*s", len, ""); 1274 } 1275 } 1276 1277 static void print_metric_headers_csv(struct perf_stat_config *config, 1278 bool no_indent __maybe_unused) 1279 { 1280 const char *p; 1281 1282 if (config->interval) 1283 fprintf(config->output, "time%s", config->csv_sep); 1284 if (config->iostat_run) 1285 return; 1286 1287 p = aggr_header_csv[config->aggr_mode]; 1288 while (*p) { 1289 if (*p == ',') 1290 fputs(config->csv_sep, config->output); 1291 else 1292 fputc(*p, config->output); 1293 p++; 1294 } 1295 } 1296 1297 static void print_metric_headers_json(struct perf_stat_config *config __maybe_unused, 1298 bool no_indent __maybe_unused) 1299 { 1300 } 1301 1302 static void print_metric_headers(struct perf_stat_config *config, 1303 struct evlist *evlist, bool no_indent) 1304 { 1305 struct evsel *counter; 1306 struct outstate os = { 1307 .fh = config->output 1308 }; 1309 struct perf_stat_output_ctx out = { 1310 .ctx = &os, 1311 .print_metric = print_metric_header, 1312 .new_line = NULL, 1313 .force_header = true, 1314 }; 1315 1316 if (config->json_output) 1317 print_metric_headers_json(config, no_indent); 1318 else if (config->csv_output) 1319 print_metric_headers_csv(config, no_indent); 1320 else 1321 print_metric_headers_std(config, no_indent); 1322 1323 if (config->iostat_run) 1324 iostat_print_header_prefix(config); 1325 1326 if (config->cgroup_list) 1327 os.cgrp = evlist__first(evlist)->cgrp; 1328 1329 /* Print metrics headers only */ 1330 evlist__for_each_entry(evlist, counter) { 1331 if (!config->iostat_run && 1332 config->aggr_mode != AGGR_NONE && counter->metric_leader != counter) 1333 continue; 1334 1335 os.evsel = counter; 1336 1337 perf_stat__print_shadow_stats(config, counter, 0, 1338 0, 1339 &out, 1340 &config->metric_events); 1341 } 1342 1343 if (!config->json_output) 1344 fputc('\n', config->output); 1345 } 1346 1347 static void prepare_timestamp(struct perf_stat_config *config, 1348 struct outstate *os, struct timespec *ts) 1349 { 1350 if (config->iostat_run) 1351 return; 1352 1353 if (config->json_output) 1354 scnprintf(os->timestamp, sizeof(os->timestamp), "\"interval\" : %lu.%09lu", 1355 (unsigned long) ts->tv_sec, ts->tv_nsec); 1356 else if (config->csv_output) 1357 scnprintf(os->timestamp, sizeof(os->timestamp), "%lu.%09lu%s", 1358 (unsigned long) ts->tv_sec, ts->tv_nsec, config->csv_sep); 1359 else 1360 scnprintf(os->timestamp, sizeof(os->timestamp), "%6lu.%09lu ", 1361 (unsigned long) ts->tv_sec, ts->tv_nsec); 1362 } 1363 1364 static void print_header_interval_std(struct perf_stat_config *config, 1365 struct target *_target __maybe_unused, 1366 struct evlist *evlist, 1367 int argc __maybe_unused, 1368 const char **argv __maybe_unused) 1369 { 1370 FILE *output = config->output; 1371 1372 switch (config->aggr_mode) { 1373 case AGGR_NODE: 1374 case AGGR_SOCKET: 1375 case AGGR_DIE: 1376 case AGGR_CLUSTER: 1377 case AGGR_CACHE: 1378 case AGGR_CORE: 1379 fprintf(output, "#%*s %-*s cpus", 1380 INTERVAL_LEN - 1, "time", 1381 aggr_header_lens[config->aggr_mode], 1382 aggr_header_std[config->aggr_mode]); 1383 break; 1384 case AGGR_NONE: 1385 fprintf(output, "#%*s %-*s", 1386 INTERVAL_LEN - 1, "time", 1387 aggr_header_lens[config->aggr_mode], 1388 aggr_header_std[config->aggr_mode]); 1389 break; 1390 case AGGR_THREAD: 1391 fprintf(output, "#%*s %*s-%-*s", 1392 INTERVAL_LEN - 1, "time", 1393 COMM_LEN, "comm", PID_LEN, "pid"); 1394 break; 1395 case AGGR_GLOBAL: 1396 default: 1397 if (!config->iostat_run) 1398 fprintf(output, "#%*s", 1399 INTERVAL_LEN - 1, "time"); 1400 case AGGR_UNSET: 1401 case AGGR_MAX: 1402 break; 1403 } 1404 1405 if (config->metric_only) 1406 print_metric_headers(config, evlist, true); 1407 else 1408 fprintf(output, " %*s %*s events\n", 1409 COUNTS_LEN, "counts", config->unit_width, "unit"); 1410 } 1411 1412 static void print_header_std(struct perf_stat_config *config, 1413 struct target *_target, struct evlist *evlist, 1414 int argc, const char **argv) 1415 { 1416 FILE *output = config->output; 1417 int i; 1418 1419 fprintf(output, "\n"); 1420 fprintf(output, " Performance counter stats for "); 1421 if (_target->bpf_str) 1422 fprintf(output, "\'BPF program(s) %s", _target->bpf_str); 1423 else if (_target->system_wide) 1424 fprintf(output, "\'system wide"); 1425 else if (_target->cpu_list) 1426 fprintf(output, "\'CPU(s) %s", _target->cpu_list); 1427 else if (!target__has_task(_target)) { 1428 fprintf(output, "\'%s", argv ? argv[0] : "pipe"); 1429 for (i = 1; argv && (i < argc); i++) 1430 fprintf(output, " %s", argv[i]); 1431 } else if (_target->pid) 1432 fprintf(output, "process id \'%s", _target->pid); 1433 else 1434 fprintf(output, "thread id \'%s", _target->tid); 1435 1436 fprintf(output, "\'"); 1437 if (config->run_count > 1) 1438 fprintf(output, " (%d runs)", config->run_count); 1439 fprintf(output, ":\n\n"); 1440 1441 if (config->metric_only) 1442 print_metric_headers(config, evlist, false); 1443 } 1444 1445 static void print_header_csv(struct perf_stat_config *config, 1446 struct target *_target __maybe_unused, 1447 struct evlist *evlist, 1448 int argc __maybe_unused, 1449 const char **argv __maybe_unused) 1450 { 1451 if (config->metric_only) 1452 print_metric_headers(config, evlist, true); 1453 } 1454 static void print_header_json(struct perf_stat_config *config, 1455 struct target *_target __maybe_unused, 1456 struct evlist *evlist, 1457 int argc __maybe_unused, 1458 const char **argv __maybe_unused) 1459 { 1460 if (config->metric_only) 1461 print_metric_headers(config, evlist, true); 1462 } 1463 1464 static void print_header(struct perf_stat_config *config, 1465 struct target *_target, 1466 struct evlist *evlist, 1467 int argc, const char **argv) 1468 { 1469 static int num_print_iv; 1470 1471 fflush(stdout); 1472 1473 if (config->interval_clear) 1474 puts(CONSOLE_CLEAR); 1475 1476 if (num_print_iv == 0 || config->interval_clear) { 1477 if (config->json_output) 1478 print_header_json(config, _target, evlist, argc, argv); 1479 else if (config->csv_output) 1480 print_header_csv(config, _target, evlist, argc, argv); 1481 else if (config->interval) 1482 print_header_interval_std(config, _target, evlist, argc, argv); 1483 else 1484 print_header_std(config, _target, evlist, argc, argv); 1485 } 1486 1487 if (num_print_iv++ == 25) 1488 num_print_iv = 0; 1489 } 1490 1491 static int get_precision(double num) 1492 { 1493 if (num > 1) 1494 return 0; 1495 1496 return lround(ceil(-log10(num))); 1497 } 1498 1499 static void print_table(struct perf_stat_config *config, 1500 FILE *output, int precision, double avg) 1501 { 1502 char tmp[64]; 1503 int idx, indent = 0; 1504 1505 scnprintf(tmp, 64, " %17.*f", precision, avg); 1506 while (tmp[indent] == ' ') 1507 indent++; 1508 1509 fprintf(output, "%*s# Table of individual measurements:\n", indent, ""); 1510 1511 for (idx = 0; idx < config->run_count; idx++) { 1512 double run = (double) config->walltime_run[idx] / NSEC_PER_SEC; 1513 int h, n = 1 + abs((int) (100.0 * (run - avg)/run) / 5); 1514 1515 fprintf(output, " %17.*f (%+.*f) ", 1516 precision, run, precision, run - avg); 1517 1518 for (h = 0; h < n; h++) 1519 fprintf(output, "#"); 1520 1521 fprintf(output, "\n"); 1522 } 1523 1524 fprintf(output, "\n%*s# Final result:\n", indent, ""); 1525 } 1526 1527 static double timeval2double(struct timeval *t) 1528 { 1529 return t->tv_sec + (double) t->tv_usec/USEC_PER_SEC; 1530 } 1531 1532 static void print_footer(struct perf_stat_config *config) 1533 { 1534 double avg = avg_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC; 1535 FILE *output = config->output; 1536 1537 if (config->interval || config->csv_output || config->json_output) 1538 return; 1539 1540 if (!config->null_run) 1541 fprintf(output, "\n"); 1542 1543 if (config->run_count == 1) { 1544 fprintf(output, " %17.9f seconds time elapsed", avg); 1545 1546 if (config->ru_display) { 1547 double ru_utime = timeval2double(&config->ru_data.ru_utime); 1548 double ru_stime = timeval2double(&config->ru_data.ru_stime); 1549 1550 fprintf(output, "\n\n"); 1551 fprintf(output, " %17.9f seconds user\n", ru_utime); 1552 fprintf(output, " %17.9f seconds sys\n", ru_stime); 1553 } 1554 } else { 1555 double sd = stddev_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC; 1556 /* 1557 * Display at most 2 more significant 1558 * digits than the stddev inaccuracy. 1559 */ 1560 int precision = get_precision(sd) + 2; 1561 1562 if (config->walltime_run_table) 1563 print_table(config, output, precision, avg); 1564 1565 fprintf(output, " %17.*f +- %.*f seconds time elapsed", 1566 precision, avg, precision, sd); 1567 1568 print_noise_pct(config, NULL, sd, avg, /*before_metric=*/false); 1569 } 1570 fprintf(output, "\n\n"); 1571 1572 if (config->print_free_counters_hint && sysctl__nmi_watchdog_enabled()) 1573 fprintf(output, 1574 "Some events weren't counted. Try disabling the NMI watchdog:\n" 1575 " echo 0 > /proc/sys/kernel/nmi_watchdog\n" 1576 " perf stat ...\n" 1577 " echo 1 > /proc/sys/kernel/nmi_watchdog\n"); 1578 1579 if (config->print_mixed_hw_group_error) 1580 fprintf(output, 1581 "The events in group usually have to be from " 1582 "the same PMU. Try reorganizing the group.\n"); 1583 } 1584 1585 static void print_percore(struct perf_stat_config *config, 1586 struct evsel *counter, struct outstate *os) 1587 { 1588 bool metric_only = config->metric_only; 1589 FILE *output = config->output; 1590 struct cpu_aggr_map *core_map; 1591 int aggr_idx, core_map_len = 0; 1592 1593 if (!config->aggr_map || !config->aggr_get_id) 1594 return; 1595 1596 if (config->percore_show_thread) 1597 return print_counter(config, counter, os); 1598 1599 /* 1600 * core_map will hold the aggr_cpu_id for the cores that have been 1601 * printed so that each core is printed just once. 1602 */ 1603 core_map = cpu_aggr_map__empty_new(config->aggr_map->nr); 1604 if (core_map == NULL) { 1605 fprintf(output, "Cannot allocate per-core aggr map for display\n"); 1606 return; 1607 } 1608 1609 cpu_aggr_map__for_each_idx(aggr_idx, config->aggr_map) { 1610 struct perf_cpu curr_cpu = config->aggr_map->map[aggr_idx].cpu; 1611 struct aggr_cpu_id core_id = aggr_cpu_id__core(curr_cpu, NULL); 1612 bool found = false; 1613 1614 for (int i = 0; i < core_map_len; i++) { 1615 if (aggr_cpu_id__equal(&core_map->map[i], &core_id)) { 1616 found = true; 1617 break; 1618 } 1619 } 1620 if (found) 1621 continue; 1622 1623 print_counter_aggrdata(config, counter, aggr_idx, os); 1624 1625 core_map->map[core_map_len++] = core_id; 1626 } 1627 free(core_map); 1628 1629 if (metric_only) 1630 fputc('\n', output); 1631 } 1632 1633 static void print_cgroup_counter(struct perf_stat_config *config, struct evlist *evlist, 1634 struct outstate *os) 1635 { 1636 struct evsel *counter; 1637 1638 evlist__for_each_entry(evlist, counter) { 1639 if (os->cgrp != counter->cgrp) { 1640 if (os->cgrp != NULL) 1641 print_metric_end(config, os); 1642 1643 os->cgrp = counter->cgrp; 1644 print_metric_begin(config, evlist, os, /*aggr_idx=*/0); 1645 } 1646 1647 print_counter(config, counter, os); 1648 } 1649 if (os->cgrp) 1650 print_metric_end(config, os); 1651 } 1652 1653 /* Should uniquify be disabled for the evlist? */ 1654 static bool evlist__disable_uniquify(const struct evlist *evlist) 1655 { 1656 struct evsel *counter; 1657 struct perf_pmu *last_pmu = NULL; 1658 bool first = true; 1659 1660 evlist__for_each_entry(evlist, counter) { 1661 /* If PMUs vary then uniquify can be useful. */ 1662 if (!first && counter->pmu != last_pmu) 1663 return false; 1664 first = false; 1665 if (counter->pmu) { 1666 /* Allow uniquify for uncore PMUs. */ 1667 if (!counter->pmu->is_core) 1668 return false; 1669 /* Keep hybrid event names uniquified for clarity. */ 1670 if (perf_pmus__num_core_pmus() > 1) 1671 return false; 1672 } 1673 } 1674 return true; 1675 } 1676 1677 static void evsel__set_needs_uniquify(struct evsel *counter, const struct perf_stat_config *config) 1678 { 1679 struct evsel *evsel; 1680 1681 if (counter->merged_stat) { 1682 /* Counter won't be shown. */ 1683 return; 1684 } 1685 1686 if (counter->use_config_name || counter->is_libpfm_event) { 1687 /* Original name will be used. */ 1688 return; 1689 } 1690 1691 if (!config->hybrid_merge && evsel__is_hybrid(counter)) { 1692 /* Unique hybrid counters necessary. */ 1693 counter->needs_uniquify = true; 1694 return; 1695 } 1696 1697 if (counter->core.attr.type < PERF_TYPE_MAX && counter->core.attr.type != PERF_TYPE_RAW) { 1698 /* Legacy event, don't uniquify. */ 1699 return; 1700 } 1701 1702 if (counter->pmu && counter->pmu->is_core && 1703 counter->alternate_hw_config != PERF_COUNT_HW_MAX) { 1704 /* A sysfs or json event replacing a legacy event, don't uniquify. */ 1705 return; 1706 } 1707 1708 if (config->aggr_mode == AGGR_NONE) { 1709 /* Always unique with no aggregation. */ 1710 counter->needs_uniquify = true; 1711 return; 1712 } 1713 1714 /* 1715 * Do other non-merged events in the evlist have the same name? If so 1716 * uniquify is necessary. 1717 */ 1718 evlist__for_each_entry(counter->evlist, evsel) { 1719 if (evsel == counter || evsel->merged_stat) 1720 continue; 1721 1722 if (evsel__name_is(counter, evsel__name(evsel))) { 1723 counter->needs_uniquify = true; 1724 return; 1725 } 1726 } 1727 } 1728 1729 static void evlist__set_needs_uniquify(struct evlist *evlist, const struct perf_stat_config *config) 1730 { 1731 struct evsel *counter; 1732 1733 if (evlist__disable_uniquify(evlist)) { 1734 evlist__for_each_entry(evlist, counter) 1735 counter->uniquified_name = true; 1736 return; 1737 } 1738 1739 evlist__for_each_entry(evlist, counter) 1740 evsel__set_needs_uniquify(counter, config); 1741 } 1742 1743 void evlist__print_counters(struct evlist *evlist, struct perf_stat_config *config, 1744 struct target *_target, struct timespec *ts, 1745 int argc, const char **argv) 1746 { 1747 bool metric_only = config->metric_only; 1748 struct evsel *counter; 1749 struct outstate os = { 1750 .fh = config->output, 1751 .first = true, 1752 }; 1753 1754 evlist__set_needs_uniquify(evlist, config); 1755 1756 if (config->iostat_run) 1757 evlist->selected = evlist__first(evlist); 1758 1759 if (config->interval) 1760 prepare_timestamp(config, &os, ts); 1761 1762 print_header(config, _target, evlist, argc, argv); 1763 1764 switch (config->aggr_mode) { 1765 case AGGR_CORE: 1766 case AGGR_CACHE: 1767 case AGGR_CLUSTER: 1768 case AGGR_DIE: 1769 case AGGR_SOCKET: 1770 case AGGR_NODE: 1771 if (config->cgroup_list) 1772 print_aggr_cgroup(config, evlist, &os); 1773 else 1774 print_aggr(config, evlist, &os); 1775 break; 1776 case AGGR_THREAD: 1777 case AGGR_GLOBAL: 1778 if (config->iostat_run) { 1779 iostat_print_counters(evlist, config, ts, os.timestamp, 1780 (iostat_print_counter_t)print_counter, &os); 1781 } else if (config->cgroup_list) { 1782 print_cgroup_counter(config, evlist, &os); 1783 } else { 1784 print_metric_begin(config, evlist, &os, /*aggr_idx=*/0); 1785 evlist__for_each_entry(evlist, counter) { 1786 print_counter(config, counter, &os); 1787 } 1788 print_metric_end(config, &os); 1789 } 1790 break; 1791 case AGGR_NONE: 1792 if (metric_only) 1793 print_no_aggr_metric(config, evlist, &os); 1794 else { 1795 evlist__for_each_entry(evlist, counter) { 1796 if (counter->percore) 1797 print_percore(config, counter, &os); 1798 else 1799 print_counter(config, counter, &os); 1800 } 1801 } 1802 break; 1803 case AGGR_MAX: 1804 case AGGR_UNSET: 1805 default: 1806 break; 1807 } 1808 1809 print_footer(config); 1810 1811 fflush(config->output); 1812 } 1813