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