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