root/tools/perf/util/stat-display.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. print_running
  2. print_noise_pct
  3. print_noise
  4. print_cgroup
  5. aggr_printout
  6. new_line_std
  7. do_new_line_std
  8. print_metric_std
  9. new_line_csv
  10. print_metric_csv
  11. valid_only_metric
  12. fixunit
  13. print_metric_only
  14. print_metric_only_csv
  15. new_line_metric
  16. print_metric_header
  17. first_shadow_cpu
  18. abs_printout
  19. is_mixed_hw_group
  20. printout
  21. aggr_update_shadow
  22. uniquify_event_name
  23. collect_all_aliases
  24. collect_data
  25. aggr_cb
  26. print_counter_aggrdata
  27. print_aggr
  28. cmp_val
  29. sort_aggr_thread
  30. print_aggr_thread
  31. counter_aggr_cb
  32. print_counter_aggr
  33. counter_cb
  34. print_counter
  35. print_no_aggr_metric
  36. print_metric_headers
  37. print_interval
  38. print_header
  39. get_precision
  40. print_table
  41. timeval2double
  42. print_footer
  43. print_percore
  44. perf_evlist__print_counters

   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 "color.h"
   8 #include "counts.h"
   9 #include "evlist.h"
  10 #include "evsel.h"
  11 #include "stat.h"
  12 #include "top.h"
  13 #include "thread_map.h"
  14 #include "cpumap.h"
  15 #include "string2.h"
  16 #include <linux/ctype.h>
  17 #include "cgroup.h"
  18 #include <api/fs/fs.h>
  19 
  20 #define CNTR_NOT_SUPPORTED      "<not supported>"
  21 #define CNTR_NOT_COUNTED        "<not counted>"
  22 
  23 static void print_running(struct perf_stat_config *config,
  24                           u64 run, u64 ena)
  25 {
  26         if (config->csv_output) {
  27                 fprintf(config->output, "%s%" PRIu64 "%s%.2f",
  28                                         config->csv_sep,
  29                                         run,
  30                                         config->csv_sep,
  31                                         ena ? 100.0 * run / ena : 100.0);
  32         } else if (run != ena) {
  33                 fprintf(config->output, "  (%.2f%%)", 100.0 * run / ena);
  34         }
  35 }
  36 
  37 static void print_noise_pct(struct perf_stat_config *config,
  38                             double total, double avg)
  39 {
  40         double pct = rel_stddev_stats(total, avg);
  41 
  42         if (config->csv_output)
  43                 fprintf(config->output, "%s%.2f%%", config->csv_sep, pct);
  44         else if (pct)
  45                 fprintf(config->output, "  ( +-%6.2f%% )", pct);
  46 }
  47 
  48 static void print_noise(struct perf_stat_config *config,
  49                         struct evsel *evsel, double avg)
  50 {
  51         struct perf_stat_evsel *ps;
  52 
  53         if (config->run_count == 1)
  54                 return;
  55 
  56         ps = evsel->stats;
  57         print_noise_pct(config, stddev_stats(&ps->res_stats[0]), avg);
  58 }
  59 
  60 static void print_cgroup(struct perf_stat_config *config, struct evsel *evsel)
  61 {
  62         if (nr_cgroups) {
  63                 const char *cgrp_name = evsel->cgrp ? evsel->cgrp->name  : "";
  64                 fprintf(config->output, "%s%s", config->csv_sep, cgrp_name);
  65         }
  66 }
  67 
  68 
  69 static void aggr_printout(struct perf_stat_config *config,
  70                           struct evsel *evsel, int id, int nr)
  71 {
  72         switch (config->aggr_mode) {
  73         case AGGR_CORE:
  74                 fprintf(config->output, "S%d-D%d-C%*d%s%*d%s",
  75                         cpu_map__id_to_socket(id),
  76                         cpu_map__id_to_die(id),
  77                         config->csv_output ? 0 : -8,
  78                         cpu_map__id_to_cpu(id),
  79                         config->csv_sep,
  80                         config->csv_output ? 0 : 4,
  81                         nr,
  82                         config->csv_sep);
  83                 break;
  84         case AGGR_DIE:
  85                 fprintf(config->output, "S%d-D%*d%s%*d%s",
  86                         cpu_map__id_to_socket(id << 16),
  87                         config->csv_output ? 0 : -8,
  88                         cpu_map__id_to_die(id << 16),
  89                         config->csv_sep,
  90                         config->csv_output ? 0 : 4,
  91                         nr,
  92                         config->csv_sep);
  93                 break;
  94         case AGGR_SOCKET:
  95                 fprintf(config->output, "S%*d%s%*d%s",
  96                         config->csv_output ? 0 : -5,
  97                         id,
  98                         config->csv_sep,
  99                         config->csv_output ? 0 : 4,
 100                         nr,
 101                         config->csv_sep);
 102                         break;
 103         case AGGR_NONE:
 104                 if (evsel->percore) {
 105                         fprintf(config->output, "S%d-D%d-C%*d%s",
 106                                 cpu_map__id_to_socket(id),
 107                                 cpu_map__id_to_die(id),
 108                                 config->csv_output ? 0 : -5,
 109                                 cpu_map__id_to_cpu(id), config->csv_sep);
 110                 } else {
 111                         fprintf(config->output, "CPU%*d%s ",
 112                                 config->csv_output ? 0 : -5,
 113                                 evsel__cpus(evsel)->map[id],
 114                                 config->csv_sep);
 115                 }
 116                 break;
 117         case AGGR_THREAD:
 118                 fprintf(config->output, "%*s-%*d%s",
 119                         config->csv_output ? 0 : 16,
 120                         perf_thread_map__comm(evsel->core.threads, id),
 121                         config->csv_output ? 0 : -8,
 122                         perf_thread_map__pid(evsel->core.threads, id),
 123                         config->csv_sep);
 124                 break;
 125         case AGGR_GLOBAL:
 126         case AGGR_UNSET:
 127         default:
 128                 break;
 129         }
 130 }
 131 
 132 struct outstate {
 133         FILE *fh;
 134         bool newline;
 135         const char *prefix;
 136         int  nfields;
 137         int  id, nr;
 138         struct evsel *evsel;
 139 };
 140 
 141 #define METRIC_LEN  35
 142 
 143 static void new_line_std(struct perf_stat_config *config __maybe_unused,
 144                          void *ctx)
 145 {
 146         struct outstate *os = ctx;
 147 
 148         os->newline = true;
 149 }
 150 
 151 static void do_new_line_std(struct perf_stat_config *config,
 152                             struct outstate *os)
 153 {
 154         fputc('\n', os->fh);
 155         fputs(os->prefix, os->fh);
 156         aggr_printout(config, os->evsel, os->id, os->nr);
 157         if (config->aggr_mode == AGGR_NONE)
 158                 fprintf(os->fh, "        ");
 159         fprintf(os->fh, "                                                 ");
 160 }
 161 
 162 static void print_metric_std(struct perf_stat_config *config,
 163                              void *ctx, const char *color, const char *fmt,
 164                              const char *unit, double val)
 165 {
 166         struct outstate *os = ctx;
 167         FILE *out = os->fh;
 168         int n;
 169         bool newline = os->newline;
 170 
 171         os->newline = false;
 172 
 173         if (unit == NULL || fmt == NULL) {
 174                 fprintf(out, "%-*s", METRIC_LEN, "");
 175                 return;
 176         }
 177 
 178         if (newline)
 179                 do_new_line_std(config, os);
 180 
 181         n = fprintf(out, " # ");
 182         if (color)
 183                 n += color_fprintf(out, color, fmt, val);
 184         else
 185                 n += fprintf(out, fmt, val);
 186         fprintf(out, " %-*s", METRIC_LEN - n - 1, unit);
 187 }
 188 
 189 static void new_line_csv(struct perf_stat_config *config, void *ctx)
 190 {
 191         struct outstate *os = ctx;
 192         int i;
 193 
 194         fputc('\n', os->fh);
 195         if (os->prefix)
 196                 fprintf(os->fh, "%s%s", os->prefix, config->csv_sep);
 197         aggr_printout(config, os->evsel, os->id, os->nr);
 198         for (i = 0; i < os->nfields; i++)
 199                 fputs(config->csv_sep, os->fh);
 200 }
 201 
 202 static void print_metric_csv(struct perf_stat_config *config __maybe_unused,
 203                              void *ctx,
 204                              const char *color __maybe_unused,
 205                              const char *fmt, const char *unit, double val)
 206 {
 207         struct outstate *os = ctx;
 208         FILE *out = os->fh;
 209         char buf[64], *vals, *ends;
 210 
 211         if (unit == NULL || fmt == NULL) {
 212                 fprintf(out, "%s%s", config->csv_sep, config->csv_sep);
 213                 return;
 214         }
 215         snprintf(buf, sizeof(buf), fmt, val);
 216         ends = vals = skip_spaces(buf);
 217         while (isdigit(*ends) || *ends == '.')
 218                 ends++;
 219         *ends = 0;
 220         fprintf(out, "%s%s%s%s", config->csv_sep, vals, config->csv_sep, skip_spaces(unit));
 221 }
 222 
 223 /* Filter out some columns that don't work well in metrics only mode */
 224 
 225 static bool valid_only_metric(const char *unit)
 226 {
 227         if (!unit)
 228                 return false;
 229         if (strstr(unit, "/sec") ||
 230             strstr(unit, "hz") ||
 231             strstr(unit, "Hz") ||
 232             strstr(unit, "CPUs utilized"))
 233                 return false;
 234         return true;
 235 }
 236 
 237 static const char *fixunit(char *buf, struct evsel *evsel,
 238                            const char *unit)
 239 {
 240         if (!strncmp(unit, "of all", 6)) {
 241                 snprintf(buf, 1024, "%s %s", perf_evsel__name(evsel),
 242                          unit);
 243                 return buf;
 244         }
 245         return unit;
 246 }
 247 
 248 static void print_metric_only(struct perf_stat_config *config,
 249                               void *ctx, const char *color, const char *fmt,
 250                               const char *unit, double val)
 251 {
 252         struct outstate *os = ctx;
 253         FILE *out = os->fh;
 254         char buf[1024], str[1024];
 255         unsigned mlen = config->metric_only_len;
 256 
 257         if (!valid_only_metric(unit))
 258                 return;
 259         unit = fixunit(buf, os->evsel, unit);
 260         if (mlen < strlen(unit))
 261                 mlen = strlen(unit) + 1;
 262 
 263         if (color)
 264                 mlen += strlen(color) + sizeof(PERF_COLOR_RESET) - 1;
 265 
 266         color_snprintf(str, sizeof(str), color ?: "", fmt, val);
 267         fprintf(out, "%*s ", mlen, str);
 268 }
 269 
 270 static void print_metric_only_csv(struct perf_stat_config *config __maybe_unused,
 271                                   void *ctx, const char *color __maybe_unused,
 272                                   const char *fmt,
 273                                   const char *unit, double val)
 274 {
 275         struct outstate *os = ctx;
 276         FILE *out = os->fh;
 277         char buf[64], *vals, *ends;
 278         char tbuf[1024];
 279 
 280         if (!valid_only_metric(unit))
 281                 return;
 282         unit = fixunit(tbuf, os->evsel, unit);
 283         snprintf(buf, sizeof buf, fmt, val);
 284         ends = vals = skip_spaces(buf);
 285         while (isdigit(*ends) || *ends == '.')
 286                 ends++;
 287         *ends = 0;
 288         fprintf(out, "%s%s", vals, config->csv_sep);
 289 }
 290 
 291 static void new_line_metric(struct perf_stat_config *config __maybe_unused,
 292                             void *ctx __maybe_unused)
 293 {
 294 }
 295 
 296 static void print_metric_header(struct perf_stat_config *config,
 297                                 void *ctx, const char *color __maybe_unused,
 298                                 const char *fmt __maybe_unused,
 299                                 const char *unit, double val __maybe_unused)
 300 {
 301         struct outstate *os = ctx;
 302         char tbuf[1024];
 303 
 304         if (!valid_only_metric(unit))
 305                 return;
 306         unit = fixunit(tbuf, os->evsel, unit);
 307         if (config->csv_output)
 308                 fprintf(os->fh, "%s%s", unit, config->csv_sep);
 309         else
 310                 fprintf(os->fh, "%*s ", config->metric_only_len, unit);
 311 }
 312 
 313 static int first_shadow_cpu(struct perf_stat_config *config,
 314                             struct evsel *evsel, int id)
 315 {
 316         struct evlist *evlist = evsel->evlist;
 317         int i;
 318 
 319         if (!config->aggr_get_id)
 320                 return 0;
 321 
 322         if (config->aggr_mode == AGGR_NONE)
 323                 return id;
 324 
 325         if (config->aggr_mode == AGGR_GLOBAL)
 326                 return 0;
 327 
 328         for (i = 0; i < perf_evsel__nr_cpus(evsel); i++) {
 329                 int cpu2 = evsel__cpus(evsel)->map[i];
 330 
 331                 if (config->aggr_get_id(config, evlist->core.cpus, cpu2) == id)
 332                         return cpu2;
 333         }
 334         return 0;
 335 }
 336 
 337 static void abs_printout(struct perf_stat_config *config,
 338                          int id, int nr, struct evsel *evsel, double avg)
 339 {
 340         FILE *output = config->output;
 341         double sc =  evsel->scale;
 342         const char *fmt;
 343 
 344         if (config->csv_output) {
 345                 fmt = floor(sc) != sc ?  "%.2f%s" : "%.0f%s";
 346         } else {
 347                 if (config->big_num)
 348                         fmt = floor(sc) != sc ? "%'18.2f%s" : "%'18.0f%s";
 349                 else
 350                         fmt = floor(sc) != sc ? "%18.2f%s" : "%18.0f%s";
 351         }
 352 
 353         aggr_printout(config, evsel, id, nr);
 354 
 355         fprintf(output, fmt, avg, config->csv_sep);
 356 
 357         if (evsel->unit)
 358                 fprintf(output, "%-*s%s",
 359                         config->csv_output ? 0 : config->unit_width,
 360                         evsel->unit, config->csv_sep);
 361 
 362         fprintf(output, "%-*s", config->csv_output ? 0 : 25, perf_evsel__name(evsel));
 363 
 364         print_cgroup(config, evsel);
 365 }
 366 
 367 static bool is_mixed_hw_group(struct evsel *counter)
 368 {
 369         struct evlist *evlist = counter->evlist;
 370         u32 pmu_type = counter->core.attr.type;
 371         struct evsel *pos;
 372 
 373         if (counter->core.nr_members < 2)
 374                 return false;
 375 
 376         evlist__for_each_entry(evlist, pos) {
 377                 /* software events can be part of any hardware group */
 378                 if (pos->core.attr.type == PERF_TYPE_SOFTWARE)
 379                         continue;
 380                 if (pmu_type == PERF_TYPE_SOFTWARE) {
 381                         pmu_type = pos->core.attr.type;
 382                         continue;
 383                 }
 384                 if (pmu_type != pos->core.attr.type)
 385                         return true;
 386         }
 387 
 388         return false;
 389 }
 390 
 391 static void printout(struct perf_stat_config *config, int id, int nr,
 392                      struct evsel *counter, double uval,
 393                      char *prefix, u64 run, u64 ena, double noise,
 394                      struct runtime_stat *st)
 395 {
 396         struct perf_stat_output_ctx out;
 397         struct outstate os = {
 398                 .fh = config->output,
 399                 .prefix = prefix ? prefix : "",
 400                 .id = id,
 401                 .nr = nr,
 402                 .evsel = counter,
 403         };
 404         print_metric_t pm = print_metric_std;
 405         new_line_t nl;
 406 
 407         if (config->metric_only) {
 408                 nl = new_line_metric;
 409                 if (config->csv_output)
 410                         pm = print_metric_only_csv;
 411                 else
 412                         pm = print_metric_only;
 413         } else
 414                 nl = new_line_std;
 415 
 416         if (config->csv_output && !config->metric_only) {
 417                 static int aggr_fields[] = {
 418                         [AGGR_GLOBAL] = 0,
 419                         [AGGR_THREAD] = 1,
 420                         [AGGR_NONE] = 1,
 421                         [AGGR_SOCKET] = 2,
 422                         [AGGR_DIE] = 2,
 423                         [AGGR_CORE] = 2,
 424                 };
 425 
 426                 pm = print_metric_csv;
 427                 nl = new_line_csv;
 428                 os.nfields = 3;
 429                 os.nfields += aggr_fields[config->aggr_mode];
 430                 if (counter->cgrp)
 431                         os.nfields++;
 432         }
 433         if (run == 0 || ena == 0 || counter->counts->scaled == -1) {
 434                 if (config->metric_only) {
 435                         pm(config, &os, NULL, "", "", 0);
 436                         return;
 437                 }
 438                 aggr_printout(config, counter, id, nr);
 439 
 440                 fprintf(config->output, "%*s%s",
 441                         config->csv_output ? 0 : 18,
 442                         counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
 443                         config->csv_sep);
 444 
 445                 if (counter->supported) {
 446                         config->print_free_counters_hint = 1;
 447                         if (is_mixed_hw_group(counter))
 448                                 config->print_mixed_hw_group_error = 1;
 449                 }
 450 
 451                 fprintf(config->output, "%-*s%s",
 452                         config->csv_output ? 0 : config->unit_width,
 453                         counter->unit, config->csv_sep);
 454 
 455                 fprintf(config->output, "%*s",
 456                         config->csv_output ? 0 : -25,
 457                         perf_evsel__name(counter));
 458 
 459                 print_cgroup(config, counter);
 460 
 461                 if (!config->csv_output)
 462                         pm(config, &os, NULL, NULL, "", 0);
 463                 print_noise(config, counter, noise);
 464                 print_running(config, run, ena);
 465                 if (config->csv_output)
 466                         pm(config, &os, NULL, NULL, "", 0);
 467                 return;
 468         }
 469 
 470         if (!config->metric_only)
 471                 abs_printout(config, id, nr, counter, uval);
 472 
 473         out.print_metric = pm;
 474         out.new_line = nl;
 475         out.ctx = &os;
 476         out.force_header = false;
 477 
 478         if (config->csv_output && !config->metric_only) {
 479                 print_noise(config, counter, noise);
 480                 print_running(config, run, ena);
 481         }
 482 
 483         perf_stat__print_shadow_stats(config, counter, uval,
 484                                 first_shadow_cpu(config, counter, id),
 485                                 &out, &config->metric_events, st);
 486         if (!config->csv_output && !config->metric_only) {
 487                 print_noise(config, counter, noise);
 488                 print_running(config, run, ena);
 489         }
 490 }
 491 
 492 static void aggr_update_shadow(struct perf_stat_config *config,
 493                                struct evlist *evlist)
 494 {
 495         int cpu, s2, id, s;
 496         u64 val;
 497         struct evsel *counter;
 498 
 499         for (s = 0; s < config->aggr_map->nr; s++) {
 500                 id = config->aggr_map->map[s];
 501                 evlist__for_each_entry(evlist, counter) {
 502                         val = 0;
 503                         for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
 504                                 s2 = config->aggr_get_id(config, evlist->core.cpus, cpu);
 505                                 if (s2 != id)
 506                                         continue;
 507                                 val += perf_counts(counter->counts, cpu, 0)->val;
 508                         }
 509                         perf_stat__update_shadow_stats(counter, val,
 510                                         first_shadow_cpu(config, counter, id),
 511                                         &rt_stat);
 512                 }
 513         }
 514 }
 515 
 516 static void uniquify_event_name(struct evsel *counter)
 517 {
 518         char *new_name;
 519         char *config;
 520 
 521         if (counter->uniquified_name ||
 522             !counter->pmu_name || !strncmp(counter->name, counter->pmu_name,
 523                                            strlen(counter->pmu_name)))
 524                 return;
 525 
 526         config = strchr(counter->name, '/');
 527         if (config) {
 528                 if (asprintf(&new_name,
 529                              "%s%s", counter->pmu_name, config) > 0) {
 530                         free(counter->name);
 531                         counter->name = new_name;
 532                 }
 533         } else {
 534                 if (asprintf(&new_name,
 535                              "%s [%s]", counter->name, counter->pmu_name) > 0) {
 536                         free(counter->name);
 537                         counter->name = new_name;
 538                 }
 539         }
 540 
 541         counter->uniquified_name = true;
 542 }
 543 
 544 static void collect_all_aliases(struct perf_stat_config *config, struct evsel *counter,
 545                             void (*cb)(struct perf_stat_config *config, struct evsel *counter, void *data,
 546                                        bool first),
 547                             void *data)
 548 {
 549         struct evlist *evlist = counter->evlist;
 550         struct evsel *alias;
 551 
 552         alias = list_prepare_entry(counter, &(evlist->core.entries), core.node);
 553         list_for_each_entry_continue (alias, &evlist->core.entries, core.node) {
 554                 if (strcmp(perf_evsel__name(alias), perf_evsel__name(counter)) ||
 555                     alias->scale != counter->scale ||
 556                     alias->cgrp != counter->cgrp ||
 557                     strcmp(alias->unit, counter->unit) ||
 558                     perf_evsel__is_clock(alias) != perf_evsel__is_clock(counter) ||
 559                     !strcmp(alias->pmu_name, counter->pmu_name))
 560                         break;
 561                 alias->merged_stat = true;
 562                 cb(config, alias, data, false);
 563         }
 564 }
 565 
 566 static bool collect_data(struct perf_stat_config *config, struct evsel *counter,
 567                             void (*cb)(struct perf_stat_config *config, struct evsel *counter, void *data,
 568                                        bool first),
 569                             void *data)
 570 {
 571         if (counter->merged_stat)
 572                 return false;
 573         cb(config, counter, data, true);
 574         if (config->no_merge)
 575                 uniquify_event_name(counter);
 576         else if (counter->auto_merge_stats)
 577                 collect_all_aliases(config, counter, cb, data);
 578         return true;
 579 }
 580 
 581 struct aggr_data {
 582         u64 ena, run, val;
 583         int id;
 584         int nr;
 585         int cpu;
 586 };
 587 
 588 static void aggr_cb(struct perf_stat_config *config,
 589                     struct evsel *counter, void *data, bool first)
 590 {
 591         struct aggr_data *ad = data;
 592         int cpu, s2;
 593 
 594         for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
 595                 struct perf_counts_values *counts;
 596 
 597                 s2 = config->aggr_get_id(config, evsel__cpus(counter), cpu);
 598                 if (s2 != ad->id)
 599                         continue;
 600                 if (first)
 601                         ad->nr++;
 602                 counts = perf_counts(counter->counts, cpu, 0);
 603                 /*
 604                  * When any result is bad, make them all to give
 605                  * consistent output in interval mode.
 606                  */
 607                 if (counts->ena == 0 || counts->run == 0 ||
 608                     counter->counts->scaled == -1) {
 609                         ad->ena = 0;
 610                         ad->run = 0;
 611                         break;
 612                 }
 613                 ad->val += counts->val;
 614                 ad->ena += counts->ena;
 615                 ad->run += counts->run;
 616         }
 617 }
 618 
 619 static void print_counter_aggrdata(struct perf_stat_config *config,
 620                                    struct evsel *counter, int s,
 621                                    char *prefix, bool metric_only,
 622                                    bool *first)
 623 {
 624         struct aggr_data ad;
 625         FILE *output = config->output;
 626         u64 ena, run, val;
 627         int id, nr;
 628         double uval;
 629 
 630         ad.id = id = config->aggr_map->map[s];
 631         ad.val = ad.ena = ad.run = 0;
 632         ad.nr = 0;
 633         if (!collect_data(config, counter, aggr_cb, &ad))
 634                 return;
 635 
 636         nr = ad.nr;
 637         ena = ad.ena;
 638         run = ad.run;
 639         val = ad.val;
 640         if (*first && metric_only) {
 641                 *first = false;
 642                 aggr_printout(config, counter, id, nr);
 643         }
 644         if (prefix && !metric_only)
 645                 fprintf(output, "%s", prefix);
 646 
 647         uval = val * counter->scale;
 648         printout(config, id, nr, counter, uval, prefix,
 649                  run, ena, 1.0, &rt_stat);
 650         if (!metric_only)
 651                 fputc('\n', output);
 652 }
 653 
 654 static void print_aggr(struct perf_stat_config *config,
 655                        struct evlist *evlist,
 656                        char *prefix)
 657 {
 658         bool metric_only = config->metric_only;
 659         FILE *output = config->output;
 660         struct evsel *counter;
 661         int s;
 662         bool first;
 663 
 664         if (!(config->aggr_map || config->aggr_get_id))
 665                 return;
 666 
 667         aggr_update_shadow(config, evlist);
 668 
 669         /*
 670          * With metric_only everything is on a single line.
 671          * Without each counter has its own line.
 672          */
 673         for (s = 0; s < config->aggr_map->nr; s++) {
 674                 if (prefix && metric_only)
 675                         fprintf(output, "%s", prefix);
 676 
 677                 first = true;
 678                 evlist__for_each_entry(evlist, counter) {
 679                         print_counter_aggrdata(config, counter, s,
 680                                                prefix, metric_only,
 681                                                &first);
 682                 }
 683                 if (metric_only)
 684                         fputc('\n', output);
 685         }
 686 }
 687 
 688 static int cmp_val(const void *a, const void *b)
 689 {
 690         return ((struct perf_aggr_thread_value *)b)->val -
 691                 ((struct perf_aggr_thread_value *)a)->val;
 692 }
 693 
 694 static struct perf_aggr_thread_value *sort_aggr_thread(
 695                                         struct evsel *counter,
 696                                         int nthreads, int ncpus,
 697                                         int *ret,
 698                                         struct target *_target)
 699 {
 700         int cpu, thread, i = 0;
 701         double uval;
 702         struct perf_aggr_thread_value *buf;
 703 
 704         buf = calloc(nthreads, sizeof(struct perf_aggr_thread_value));
 705         if (!buf)
 706                 return NULL;
 707 
 708         for (thread = 0; thread < nthreads; thread++) {
 709                 u64 ena = 0, run = 0, val = 0;
 710 
 711                 for (cpu = 0; cpu < ncpus; cpu++) {
 712                         val += perf_counts(counter->counts, cpu, thread)->val;
 713                         ena += perf_counts(counter->counts, cpu, thread)->ena;
 714                         run += perf_counts(counter->counts, cpu, thread)->run;
 715                 }
 716 
 717                 uval = val * counter->scale;
 718 
 719                 /*
 720                  * Skip value 0 when enabling --per-thread globally,
 721                  * otherwise too many 0 output.
 722                  */
 723                 if (uval == 0.0 && target__has_per_thread(_target))
 724                         continue;
 725 
 726                 buf[i].counter = counter;
 727                 buf[i].id = thread;
 728                 buf[i].uval = uval;
 729                 buf[i].val = val;
 730                 buf[i].run = run;
 731                 buf[i].ena = ena;
 732                 i++;
 733         }
 734 
 735         qsort(buf, i, sizeof(struct perf_aggr_thread_value), cmp_val);
 736 
 737         if (ret)
 738                 *ret = i;
 739 
 740         return buf;
 741 }
 742 
 743 static void print_aggr_thread(struct perf_stat_config *config,
 744                               struct target *_target,
 745                               struct evsel *counter, char *prefix)
 746 {
 747         FILE *output = config->output;
 748         int nthreads = perf_thread_map__nr(counter->core.threads);
 749         int ncpus = perf_cpu_map__nr(counter->core.cpus);
 750         int thread, sorted_threads, id;
 751         struct perf_aggr_thread_value *buf;
 752 
 753         buf = sort_aggr_thread(counter, nthreads, ncpus, &sorted_threads, _target);
 754         if (!buf) {
 755                 perror("cannot sort aggr thread");
 756                 return;
 757         }
 758 
 759         for (thread = 0; thread < sorted_threads; thread++) {
 760                 if (prefix)
 761                         fprintf(output, "%s", prefix);
 762 
 763                 id = buf[thread].id;
 764                 if (config->stats)
 765                         printout(config, id, 0, buf[thread].counter, buf[thread].uval,
 766                                  prefix, buf[thread].run, buf[thread].ena, 1.0,
 767                                  &config->stats[id]);
 768                 else
 769                         printout(config, id, 0, buf[thread].counter, buf[thread].uval,
 770                                  prefix, buf[thread].run, buf[thread].ena, 1.0,
 771                                  &rt_stat);
 772                 fputc('\n', output);
 773         }
 774 
 775         free(buf);
 776 }
 777 
 778 struct caggr_data {
 779         double avg, avg_enabled, avg_running;
 780 };
 781 
 782 static void counter_aggr_cb(struct perf_stat_config *config __maybe_unused,
 783                             struct evsel *counter, void *data,
 784                             bool first __maybe_unused)
 785 {
 786         struct caggr_data *cd = data;
 787         struct perf_stat_evsel *ps = counter->stats;
 788 
 789         cd->avg += avg_stats(&ps->res_stats[0]);
 790         cd->avg_enabled += avg_stats(&ps->res_stats[1]);
 791         cd->avg_running += avg_stats(&ps->res_stats[2]);
 792 }
 793 
 794 /*
 795  * Print out the results of a single counter:
 796  * aggregated counts in system-wide mode
 797  */
 798 static void print_counter_aggr(struct perf_stat_config *config,
 799                                struct evsel *counter, char *prefix)
 800 {
 801         bool metric_only = config->metric_only;
 802         FILE *output = config->output;
 803         double uval;
 804         struct caggr_data cd = { .avg = 0.0 };
 805 
 806         if (!collect_data(config, counter, counter_aggr_cb, &cd))
 807                 return;
 808 
 809         if (prefix && !metric_only)
 810                 fprintf(output, "%s", prefix);
 811 
 812         uval = cd.avg * counter->scale;
 813         printout(config, -1, 0, counter, uval, prefix, cd.avg_running, cd.avg_enabled,
 814                  cd.avg, &rt_stat);
 815         if (!metric_only)
 816                 fprintf(output, "\n");
 817 }
 818 
 819 static void counter_cb(struct perf_stat_config *config __maybe_unused,
 820                        struct evsel *counter, void *data,
 821                        bool first __maybe_unused)
 822 {
 823         struct aggr_data *ad = data;
 824 
 825         ad->val += perf_counts(counter->counts, ad->cpu, 0)->val;
 826         ad->ena += perf_counts(counter->counts, ad->cpu, 0)->ena;
 827         ad->run += perf_counts(counter->counts, ad->cpu, 0)->run;
 828 }
 829 
 830 /*
 831  * Print out the results of a single counter:
 832  * does not use aggregated count in system-wide
 833  */
 834 static void print_counter(struct perf_stat_config *config,
 835                           struct evsel *counter, char *prefix)
 836 {
 837         FILE *output = config->output;
 838         u64 ena, run, val;
 839         double uval;
 840         int cpu;
 841 
 842         for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
 843                 struct aggr_data ad = { .cpu = cpu };
 844 
 845                 if (!collect_data(config, counter, counter_cb, &ad))
 846                         return;
 847                 val = ad.val;
 848                 ena = ad.ena;
 849                 run = ad.run;
 850 
 851                 if (prefix)
 852                         fprintf(output, "%s", prefix);
 853 
 854                 uval = val * counter->scale;
 855                 printout(config, cpu, 0, counter, uval, prefix, run, ena, 1.0,
 856                          &rt_stat);
 857 
 858                 fputc('\n', output);
 859         }
 860 }
 861 
 862 static void print_no_aggr_metric(struct perf_stat_config *config,
 863                                  struct evlist *evlist,
 864                                  char *prefix)
 865 {
 866         int cpu;
 867         int nrcpus = 0;
 868         struct evsel *counter;
 869         u64 ena, run, val;
 870         double uval;
 871 
 872         nrcpus = evlist->core.cpus->nr;
 873         for (cpu = 0; cpu < nrcpus; cpu++) {
 874                 bool first = true;
 875 
 876                 if (prefix)
 877                         fputs(prefix, config->output);
 878                 evlist__for_each_entry(evlist, counter) {
 879                         if (first) {
 880                                 aggr_printout(config, counter, cpu, 0);
 881                                 first = false;
 882                         }
 883                         val = perf_counts(counter->counts, cpu, 0)->val;
 884                         ena = perf_counts(counter->counts, cpu, 0)->ena;
 885                         run = perf_counts(counter->counts, cpu, 0)->run;
 886 
 887                         uval = val * counter->scale;
 888                         printout(config, cpu, 0, counter, uval, prefix, run, ena, 1.0,
 889                                  &rt_stat);
 890                 }
 891                 fputc('\n', config->output);
 892         }
 893 }
 894 
 895 static int aggr_header_lens[] = {
 896         [AGGR_CORE] = 24,
 897         [AGGR_DIE] = 18,
 898         [AGGR_SOCKET] = 12,
 899         [AGGR_NONE] = 6,
 900         [AGGR_THREAD] = 24,
 901         [AGGR_GLOBAL] = 0,
 902 };
 903 
 904 static const char *aggr_header_csv[] = {
 905         [AGGR_CORE]     =       "core,cpus,",
 906         [AGGR_DIE]      =       "die,cpus",
 907         [AGGR_SOCKET]   =       "socket,cpus",
 908         [AGGR_NONE]     =       "cpu,",
 909         [AGGR_THREAD]   =       "comm-pid,",
 910         [AGGR_GLOBAL]   =       ""
 911 };
 912 
 913 static void print_metric_headers(struct perf_stat_config *config,
 914                                  struct evlist *evlist,
 915                                  const char *prefix, bool no_indent)
 916 {
 917         struct perf_stat_output_ctx out;
 918         struct evsel *counter;
 919         struct outstate os = {
 920                 .fh = config->output
 921         };
 922 
 923         if (prefix)
 924                 fprintf(config->output, "%s", prefix);
 925 
 926         if (!config->csv_output && !no_indent)
 927                 fprintf(config->output, "%*s",
 928                         aggr_header_lens[config->aggr_mode], "");
 929         if (config->csv_output) {
 930                 if (config->interval)
 931                         fputs("time,", config->output);
 932                 fputs(aggr_header_csv[config->aggr_mode], config->output);
 933         }
 934 
 935         /* Print metrics headers only */
 936         evlist__for_each_entry(evlist, counter) {
 937                 os.evsel = counter;
 938                 out.ctx = &os;
 939                 out.print_metric = print_metric_header;
 940                 out.new_line = new_line_metric;
 941                 out.force_header = true;
 942                 os.evsel = counter;
 943                 perf_stat__print_shadow_stats(config, counter, 0,
 944                                               0,
 945                                               &out,
 946                                               &config->metric_events,
 947                                               &rt_stat);
 948         }
 949         fputc('\n', config->output);
 950 }
 951 
 952 static void print_interval(struct perf_stat_config *config,
 953                            struct evlist *evlist,
 954                            char *prefix, struct timespec *ts)
 955 {
 956         bool metric_only = config->metric_only;
 957         unsigned int unit_width = config->unit_width;
 958         FILE *output = config->output;
 959         static int num_print_interval;
 960 
 961         if (config->interval_clear)
 962                 puts(CONSOLE_CLEAR);
 963 
 964         sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, config->csv_sep);
 965 
 966         if ((num_print_interval == 0 && !config->csv_output) || config->interval_clear) {
 967                 switch (config->aggr_mode) {
 968                 case AGGR_SOCKET:
 969                         fprintf(output, "#           time socket cpus");
 970                         if (!metric_only)
 971                                 fprintf(output, "             counts %*s events\n", unit_width, "unit");
 972                         break;
 973                 case AGGR_DIE:
 974                         fprintf(output, "#           time die          cpus");
 975                         if (!metric_only)
 976                                 fprintf(output, "             counts %*s events\n", unit_width, "unit");
 977                         break;
 978                 case AGGR_CORE:
 979                         fprintf(output, "#           time core            cpus");
 980                         if (!metric_only)
 981                                 fprintf(output, "             counts %*s events\n", unit_width, "unit");
 982                         break;
 983                 case AGGR_NONE:
 984                         fprintf(output, "#           time CPU    ");
 985                         if (!metric_only)
 986                                 fprintf(output, "                counts %*s events\n", unit_width, "unit");
 987                         break;
 988                 case AGGR_THREAD:
 989                         fprintf(output, "#           time             comm-pid");
 990                         if (!metric_only)
 991                                 fprintf(output, "                  counts %*s events\n", unit_width, "unit");
 992                         break;
 993                 case AGGR_GLOBAL:
 994                 default:
 995                         fprintf(output, "#           time");
 996                         if (!metric_only)
 997                                 fprintf(output, "             counts %*s events\n", unit_width, "unit");
 998                 case AGGR_UNSET:
 999                         break;
1000                 }
1001         }
1002 
1003         if ((num_print_interval == 0 || config->interval_clear) && metric_only)
1004                 print_metric_headers(config, evlist, " ", true);
1005         if (++num_print_interval == 25)
1006                 num_print_interval = 0;
1007 }
1008 
1009 static void print_header(struct perf_stat_config *config,
1010                          struct target *_target,
1011                          int argc, const char **argv)
1012 {
1013         FILE *output = config->output;
1014         int i;
1015 
1016         fflush(stdout);
1017 
1018         if (!config->csv_output) {
1019                 fprintf(output, "\n");
1020                 fprintf(output, " Performance counter stats for ");
1021                 if (_target->system_wide)
1022                         fprintf(output, "\'system wide");
1023                 else if (_target->cpu_list)
1024                         fprintf(output, "\'CPU(s) %s", _target->cpu_list);
1025                 else if (!target__has_task(_target)) {
1026                         fprintf(output, "\'%s", argv ? argv[0] : "pipe");
1027                         for (i = 1; argv && (i < argc); i++)
1028                                 fprintf(output, " %s", argv[i]);
1029                 } else if (_target->pid)
1030                         fprintf(output, "process id \'%s", _target->pid);
1031                 else
1032                         fprintf(output, "thread id \'%s", _target->tid);
1033 
1034                 fprintf(output, "\'");
1035                 if (config->run_count > 1)
1036                         fprintf(output, " (%d runs)", config->run_count);
1037                 fprintf(output, ":\n\n");
1038         }
1039 }
1040 
1041 static int get_precision(double num)
1042 {
1043         if (num > 1)
1044                 return 0;
1045 
1046         return lround(ceil(-log10(num)));
1047 }
1048 
1049 static void print_table(struct perf_stat_config *config,
1050                         FILE *output, int precision, double avg)
1051 {
1052         char tmp[64];
1053         int idx, indent = 0;
1054 
1055         scnprintf(tmp, 64, " %17.*f", precision, avg);
1056         while (tmp[indent] == ' ')
1057                 indent++;
1058 
1059         fprintf(output, "%*s# Table of individual measurements:\n", indent, "");
1060 
1061         for (idx = 0; idx < config->run_count; idx++) {
1062                 double run = (double) config->walltime_run[idx] / NSEC_PER_SEC;
1063                 int h, n = 1 + abs((int) (100.0 * (run - avg)/run) / 5);
1064 
1065                 fprintf(output, " %17.*f (%+.*f) ",
1066                         precision, run, precision, run - avg);
1067 
1068                 for (h = 0; h < n; h++)
1069                         fprintf(output, "#");
1070 
1071                 fprintf(output, "\n");
1072         }
1073 
1074         fprintf(output, "\n%*s# Final result:\n", indent, "");
1075 }
1076 
1077 static double timeval2double(struct timeval *t)
1078 {
1079         return t->tv_sec + (double) t->tv_usec/USEC_PER_SEC;
1080 }
1081 
1082 static void print_footer(struct perf_stat_config *config)
1083 {
1084         double avg = avg_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC;
1085         FILE *output = config->output;
1086         int n;
1087 
1088         if (!config->null_run)
1089                 fprintf(output, "\n");
1090 
1091         if (config->run_count == 1) {
1092                 fprintf(output, " %17.9f seconds time elapsed", avg);
1093 
1094                 if (config->ru_display) {
1095                         double ru_utime = timeval2double(&config->ru_data.ru_utime);
1096                         double ru_stime = timeval2double(&config->ru_data.ru_stime);
1097 
1098                         fprintf(output, "\n\n");
1099                         fprintf(output, " %17.9f seconds user\n", ru_utime);
1100                         fprintf(output, " %17.9f seconds sys\n", ru_stime);
1101                 }
1102         } else {
1103                 double sd = stddev_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC;
1104                 /*
1105                  * Display at most 2 more significant
1106                  * digits than the stddev inaccuracy.
1107                  */
1108                 int precision = get_precision(sd) + 2;
1109 
1110                 if (config->walltime_run_table)
1111                         print_table(config, output, precision, avg);
1112 
1113                 fprintf(output, " %17.*f +- %.*f seconds time elapsed",
1114                         precision, avg, precision, sd);
1115 
1116                 print_noise_pct(config, sd, avg);
1117         }
1118         fprintf(output, "\n\n");
1119 
1120         if (config->print_free_counters_hint &&
1121             sysctl__read_int("kernel/nmi_watchdog", &n) >= 0 &&
1122             n > 0)
1123                 fprintf(output,
1124 "Some events weren't counted. Try disabling the NMI watchdog:\n"
1125 "       echo 0 > /proc/sys/kernel/nmi_watchdog\n"
1126 "       perf stat ...\n"
1127 "       echo 1 > /proc/sys/kernel/nmi_watchdog\n");
1128 
1129         if (config->print_mixed_hw_group_error)
1130                 fprintf(output,
1131                         "The events in group usually have to be from "
1132                         "the same PMU. Try reorganizing the group.\n");
1133 }
1134 
1135 static void print_percore(struct perf_stat_config *config,
1136                           struct evsel *counter, char *prefix)
1137 {
1138         bool metric_only = config->metric_only;
1139         FILE *output = config->output;
1140         int s;
1141         bool first = true;
1142 
1143         if (!(config->aggr_map || config->aggr_get_id))
1144                 return;
1145 
1146         for (s = 0; s < config->aggr_map->nr; s++) {
1147                 if (prefix && metric_only)
1148                         fprintf(output, "%s", prefix);
1149 
1150                 print_counter_aggrdata(config, counter, s,
1151                                        prefix, metric_only,
1152                                        &first);
1153         }
1154 
1155         if (metric_only)
1156                 fputc('\n', output);
1157 }
1158 
1159 void
1160 perf_evlist__print_counters(struct evlist *evlist,
1161                             struct perf_stat_config *config,
1162                             struct target *_target,
1163                             struct timespec *ts,
1164                             int argc, const char **argv)
1165 {
1166         bool metric_only = config->metric_only;
1167         int interval = config->interval;
1168         struct evsel *counter;
1169         char buf[64], *prefix = NULL;
1170 
1171         if (interval)
1172                 print_interval(config, evlist, prefix = buf, ts);
1173         else
1174                 print_header(config, _target, argc, argv);
1175 
1176         if (metric_only) {
1177                 static int num_print_iv;
1178 
1179                 if (num_print_iv == 0 && !interval)
1180                         print_metric_headers(config, evlist, prefix, false);
1181                 if (num_print_iv++ == 25)
1182                         num_print_iv = 0;
1183                 if (config->aggr_mode == AGGR_GLOBAL && prefix)
1184                         fprintf(config->output, "%s", prefix);
1185         }
1186 
1187         switch (config->aggr_mode) {
1188         case AGGR_CORE:
1189         case AGGR_DIE:
1190         case AGGR_SOCKET:
1191                 print_aggr(config, evlist, prefix);
1192                 break;
1193         case AGGR_THREAD:
1194                 evlist__for_each_entry(evlist, counter) {
1195                         print_aggr_thread(config, _target, counter, prefix);
1196                 }
1197                 break;
1198         case AGGR_GLOBAL:
1199                 evlist__for_each_entry(evlist, counter) {
1200                         print_counter_aggr(config, counter, prefix);
1201                 }
1202                 if (metric_only)
1203                         fputc('\n', config->output);
1204                 break;
1205         case AGGR_NONE:
1206                 if (metric_only)
1207                         print_no_aggr_metric(config, evlist, prefix);
1208                 else {
1209                         evlist__for_each_entry(evlist, counter) {
1210                                 if (counter->percore)
1211                                         print_percore(config, counter, prefix);
1212                                 else
1213                                         print_counter(config, counter, prefix);
1214                         }
1215                 }
1216                 break;
1217         case AGGR_UNSET:
1218         default:
1219                 break;
1220         }
1221 
1222         if (!interval && !config->csv_output)
1223                 print_footer(config);
1224 
1225         fflush(config->output);
1226 }

/* [<][>][^][v][top][bottom][index][help] */