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