Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf stat: Change color to threshold in print_metric

Colors don't mean things in CSV and JSON output, switch to a threshold
enum value that the standard output can convert to a color. Updating
the CSV and JSON output will be later changes.

Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Yicong Yang <yangyicong@hisilicon.com>
Cc: Weilin Wang <weilin.wang@intel.com>
Cc: Will Deacon <will@kernel.org>
Cc: James Clark <james.clark@linaro.org>
Cc: Mike Leach <mike.leach@linaro.org>
Cc: Leo Yan <leo.yan@linux.dev>
Cc: Sumanth Korikkar <sumanthk@linux.ibm.com>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Cc: Tim Chen <tim.c.chen@linux.intel.com>
Cc: John Garry <john.g.garry@oracle.com>
Link: https://lore.kernel.org/r/20241017175356.783793-6-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

authored by

Ian Rogers and committed by
Namhyung Kim
37b77ae9 e1cc918b

+97 -68
+1 -1
tools/perf/arch/x86/util/iostat.c
··· 444 444 iostat_value = (count->val - prev_count_val) / 445 445 ((double) count->run / count->ena); 446 446 } 447 - out->print_metric(config, out->ctx, NULL, "%8.0f", iostat_metric, 447 + out->print_metric(config, out->ctx, METRIC_THRESHOLD_UNKNOWN, "%8.0f", iostat_metric, 448 448 iostat_value / (256 * 1024)); 449 449 } 450 450
+3 -3
tools/perf/builtin-script.c
··· 2136 2136 }; 2137 2137 2138 2138 static void script_print_metric(struct perf_stat_config *config __maybe_unused, 2139 - void *ctx, const char *color, 2140 - const char *fmt, 2141 - const char *unit, double val) 2139 + void *ctx, enum metric_threshold_classify thresh, 2140 + const char *fmt, const char *unit, double val) 2142 2141 { 2143 2142 struct metric_ctx *mctx = ctx; 2143 + const char *color = metric_threshold_classify__color(thresh); 2144 2144 2145 2145 if (!fmt) 2146 2146 return;
+29 -11
tools/perf/util/stat-display.c
··· 73 73 [AGGR_GLOBAL] = "" 74 74 }; 75 75 76 + const char *metric_threshold_classify__color(enum metric_threshold_classify thresh) 77 + { 78 + const char * const colors[] = { 79 + "", /* unknown */ 80 + PERF_COLOR_RED, /* bad */ 81 + PERF_COLOR_MAGENTA, /* nearly bad */ 82 + PERF_COLOR_YELLOW, /* less good */ 83 + PERF_COLOR_GREEN, /* good */ 84 + }; 85 + static_assert(ARRAY_SIZE(colors) - 1 == METRIC_THRESHOLD_GOOD, "missing enum value"); 86 + return colors[thresh]; 87 + } 88 + 76 89 static void print_running_std(struct perf_stat_config *config, u64 run, u64 ena) 77 90 { 78 91 if (run != ena) ··· 418 405 } 419 406 420 407 static void print_metric_std(struct perf_stat_config *config, 421 - void *ctx, const char *color, const char *fmt, 422 - const char *unit, double val) 408 + void *ctx, enum metric_threshold_classify thresh, 409 + const char *fmt, const char *unit, double val) 423 410 { 424 411 struct outstate *os = ctx; 425 412 FILE *out = os->fh; 426 413 int n; 427 414 bool newline = os->newline; 415 + const char *color = metric_threshold_classify__color(thresh); 428 416 429 417 os->newline = false; 430 418 ··· 457 443 458 444 static void print_metric_csv(struct perf_stat_config *config __maybe_unused, 459 445 void *ctx, 460 - const char *color __maybe_unused, 446 + enum metric_threshold_classify thresh __maybe_unused, 461 447 const char *fmt, const char *unit, double val) 462 448 { 463 449 struct outstate *os = ctx; ··· 478 464 479 465 static void print_metric_json(struct perf_stat_config *config __maybe_unused, 480 466 void *ctx, 481 - const char *color __maybe_unused, 467 + enum metric_threshold_classify thresh __maybe_unused, 482 468 const char *fmt __maybe_unused, 483 469 const char *unit, double val) 484 470 { ··· 573 559 } 574 560 575 561 static void print_metric_only(struct perf_stat_config *config, 576 - void *ctx, const char *color, const char *fmt, 577 - const char *unit, double val) 562 + void *ctx, enum metric_threshold_classify thresh, 563 + const char *fmt, const char *unit, double val) 578 564 { 579 565 struct outstate *os = ctx; 580 566 FILE *out = os->fh; 581 567 char buf[1024], str[1024]; 582 568 unsigned mlen = config->metric_only_len; 569 + const char *color = metric_threshold_classify__color(thresh); 583 570 584 571 if (!valid_only_metric(unit)) 585 572 return; ··· 597 582 } 598 583 599 584 static void print_metric_only_csv(struct perf_stat_config *config __maybe_unused, 600 - void *ctx, const char *color __maybe_unused, 585 + void *ctx, 586 + enum metric_threshold_classify thresh __maybe_unused, 601 587 const char *fmt, 602 588 const char *unit, double val) 603 589 { ··· 620 604 } 621 605 622 606 static void print_metric_only_json(struct perf_stat_config *config __maybe_unused, 623 - void *ctx, const char *color __maybe_unused, 607 + void *ctx, 608 + enum metric_threshold_classify thresh __maybe_unused, 624 609 const char *fmt, 625 610 const char *unit, double val) 626 611 { ··· 653 636 } 654 637 655 638 static void print_metric_header(struct perf_stat_config *config, 656 - void *ctx, const char *color __maybe_unused, 639 + void *ctx, 640 + enum metric_threshold_classify thresh __maybe_unused, 657 641 const char *fmt __maybe_unused, 658 642 const char *unit, double val __maybe_unused) 659 643 { ··· 828 810 829 811 if (run == 0 || ena == 0 || counter->counts->scaled == -1) { 830 812 if (config->metric_only) { 831 - pm(config, os, NULL, "", "", 0); 813 + pm(config, os, METRIC_THRESHOLD_UNKNOWN, "", "", 0); 832 814 return; 833 815 } 834 816 ··· 883 865 perf_stat__print_shadow_stats(config, counter, uval, aggr_idx, 884 866 &out, &config->metric_events); 885 867 } else { 886 - pm(config, os, /*color=*/NULL, /*format=*/NULL, /*unit=*/"", /*val=*/0); 868 + pm(config, os, METRIC_THRESHOLD_UNKNOWN, /*format=*/NULL, /*unit=*/"", /*val=*/0); 887 869 } 888 870 889 871 if (!config->metric_only) {
+53 -52
tools/perf/util/stat-shadow.c
··· 137 137 return STAT_NONE; 138 138 } 139 139 140 - static const char *get_ratio_color(const double ratios[3], double val) 140 + static enum metric_threshold_classify get_ratio_thresh(const double ratios[3], double val) 141 141 { 142 - const char *color = PERF_COLOR_NORMAL; 142 + assert(ratios[0] > ratios[1]); 143 + assert(ratios[1] > ratios[2]); 143 144 144 - if (val > ratios[0]) 145 - color = PERF_COLOR_RED; 146 - else if (val > ratios[1]) 147 - color = PERF_COLOR_MAGENTA; 148 - else if (val > ratios[2]) 149 - color = PERF_COLOR_YELLOW; 150 - 151 - return color; 145 + return val > ratios[1] 146 + ? (val > ratios[0] ? METRIC_THRESHOLD_BAD : METRIC_THRESHOLD_NEARLY_BAD) 147 + : (val > ratios[2] ? METRIC_THRESHOLD_LESS_GOOD : METRIC_THRESHOLD_GOOD); 152 148 } 153 149 154 150 static double find_stat(const struct evsel *evsel, int aggr_idx, enum stat_type type) ··· 192 196 const struct evsel *evsel, int aggr_idx, 193 197 double numerator, struct perf_stat_output_ctx *out, 194 198 enum stat_type denominator_type, 195 - const double color_ratios[3], const char *_unit) 199 + const double thresh_ratios[3], const char *_unit) 196 200 { 197 201 double denominator = find_stat(evsel, aggr_idx, denominator_type); 198 202 double ratio = 0; 199 - const char *color = NULL; 203 + enum metric_threshold_classify thresh = METRIC_THRESHOLD_UNKNOWN; 200 204 const char *fmt = NULL; 201 205 const char *unit = NULL; 202 206 203 207 if (numerator && denominator) { 204 208 ratio = numerator / denominator * 100.0; 205 - color = get_ratio_color(color_ratios, ratio); 209 + thresh = get_ratio_thresh(thresh_ratios, ratio); 206 210 fmt = "%7.2f%%"; 207 211 unit = _unit; 208 212 } 209 - out->print_metric(config, out->ctx, color, fmt, unit, ratio); 213 + out->print_metric(config, out->ctx, thresh, fmt, unit, ratio); 210 214 } 211 215 212 216 static void print_stalled_cycles_front(struct perf_stat_config *config, ··· 214 218 int aggr_idx, double stalled, 215 219 struct perf_stat_output_ctx *out) 216 220 { 217 - static const double color_ratios[3] = {50.0, 30.0, 10.0}; 221 + const double thresh_ratios[3] = {50.0, 30.0, 10.0}; 218 222 219 - print_ratio(config, evsel, aggr_idx, stalled, out, STAT_CYCLES, color_ratios, 223 + print_ratio(config, evsel, aggr_idx, stalled, out, STAT_CYCLES, thresh_ratios, 220 224 "frontend cycles idle"); 221 225 } 222 226 ··· 225 229 int aggr_idx, double stalled, 226 230 struct perf_stat_output_ctx *out) 227 231 { 228 - static const double color_ratios[3] = {75.0, 50.0, 20.0}; 232 + const double thresh_ratios[3] = {75.0, 50.0, 20.0}; 229 233 230 - print_ratio(config, evsel, aggr_idx, stalled, out, STAT_CYCLES, color_ratios, 234 + print_ratio(config, evsel, aggr_idx, stalled, out, STAT_CYCLES, thresh_ratios, 231 235 "backend cycles idle"); 232 236 } 233 237 ··· 236 240 int aggr_idx, double misses, 237 241 struct perf_stat_output_ctx *out) 238 242 { 239 - static const double color_ratios[3] = {20.0, 10.0, 5.0}; 243 + const double thresh_ratios[3] = {20.0, 10.0, 5.0}; 240 244 241 - print_ratio(config, evsel, aggr_idx, misses, out, STAT_BRANCHES, color_ratios, 245 + print_ratio(config, evsel, aggr_idx, misses, out, STAT_BRANCHES, thresh_ratios, 242 246 "of all branches"); 243 247 } 244 248 ··· 247 251 int aggr_idx, double misses, 248 252 struct perf_stat_output_ctx *out) 249 253 { 250 - static const double color_ratios[3] = {20.0, 10.0, 5.0}; 254 + const double thresh_ratios[3] = {20.0, 10.0, 5.0}; 251 255 252 - print_ratio(config, evsel, aggr_idx, misses, out, STAT_L1_DCACHE, color_ratios, 256 + print_ratio(config, evsel, aggr_idx, misses, out, STAT_L1_DCACHE, thresh_ratios, 253 257 "of all L1-dcache accesses"); 254 258 } 255 259 ··· 258 262 int aggr_idx, double misses, 259 263 struct perf_stat_output_ctx *out) 260 264 { 261 - static const double color_ratios[3] = {20.0, 10.0, 5.0}; 265 + const double thresh_ratios[3] = {20.0, 10.0, 5.0}; 262 266 263 - print_ratio(config, evsel, aggr_idx, misses, out, STAT_L1_ICACHE, color_ratios, 267 + print_ratio(config, evsel, aggr_idx, misses, out, STAT_L1_ICACHE, thresh_ratios, 264 268 "of all L1-icache accesses"); 265 269 } 266 270 ··· 269 273 int aggr_idx, double misses, 270 274 struct perf_stat_output_ctx *out) 271 275 { 272 - static const double color_ratios[3] = {20.0, 10.0, 5.0}; 276 + const double thresh_ratios[3] = {20.0, 10.0, 5.0}; 273 277 274 - print_ratio(config, evsel, aggr_idx, misses, out, STAT_LL_CACHE, color_ratios, 278 + print_ratio(config, evsel, aggr_idx, misses, out, STAT_LL_CACHE, thresh_ratios, 275 279 "of all LL-cache accesses"); 276 280 } 277 281 ··· 280 284 int aggr_idx, double misses, 281 285 struct perf_stat_output_ctx *out) 282 286 { 283 - static const double color_ratios[3] = {20.0, 10.0, 5.0}; 287 + const double thresh_ratios[3] = {20.0, 10.0, 5.0}; 284 288 285 - print_ratio(config, evsel, aggr_idx, misses, out, STAT_DTLB_CACHE, color_ratios, 289 + print_ratio(config, evsel, aggr_idx, misses, out, STAT_DTLB_CACHE, thresh_ratios, 286 290 "of all dTLB cache accesses"); 287 291 } 288 292 ··· 291 295 int aggr_idx, double misses, 292 296 struct perf_stat_output_ctx *out) 293 297 { 294 - static const double color_ratios[3] = {20.0, 10.0, 5.0}; 298 + const double thresh_ratios[3] = {20.0, 10.0, 5.0}; 295 299 296 - print_ratio(config, evsel, aggr_idx, misses, out, STAT_ITLB_CACHE, color_ratios, 300 + print_ratio(config, evsel, aggr_idx, misses, out, STAT_ITLB_CACHE, thresh_ratios, 297 301 "of all iTLB cache accesses"); 298 302 } 299 303 ··· 302 306 int aggr_idx, double misses, 303 307 struct perf_stat_output_ctx *out) 304 308 { 305 - static const double color_ratios[3] = {20.0, 10.0, 5.0}; 309 + const double thresh_ratios[3] = {20.0, 10.0, 5.0}; 306 310 307 - print_ratio(config, evsel, aggr_idx, misses, out, STAT_CACHE_REFS, color_ratios, 311 + print_ratio(config, evsel, aggr_idx, misses, out, STAT_CACHE_REFS, thresh_ratios, 308 312 "of all cache refs"); 309 313 } 310 314 ··· 320 324 find_stat(evsel, aggr_idx, STAT_STALLED_CYCLES_BACK)); 321 325 322 326 if (cycles) { 323 - print_metric(config, ctxp, /*color=*/NULL, "%7.2f ", "insn per cycle", 324 - instructions / cycles); 327 + print_metric(config, ctxp, METRIC_THRESHOLD_UNKNOWN, "%7.2f ", 328 + "insn per cycle", instructions / cycles); 325 329 } else { 326 - print_metric(config, ctxp, /*color=*/NULL, /*fmt=*/NULL, "insn per cycle", 0); 330 + print_metric(config, ctxp, METRIC_THRESHOLD_UNKNOWN, /*fmt=*/NULL, 331 + "insn per cycle", 0); 327 332 } 328 - 329 333 if (max_stalled && instructions) { 330 334 out->new_line(config, ctxp); 331 - print_metric(config, ctxp, /*color=*/NULL, "%7.2f ", "stalled cycles per insn", 332 - max_stalled / instructions); 335 + print_metric(config, ctxp, METRIC_THRESHOLD_UNKNOWN, "%7.2f ", 336 + "stalled cycles per insn", max_stalled / instructions); 333 337 } 334 338 } 335 339 ··· 343 347 if (cycles && nsecs) { 344 348 double ratio = cycles / nsecs; 345 349 346 - out->print_metric(config, out->ctx, /*color=*/NULL, "%8.3f", "GHz", ratio); 350 + out->print_metric(config, out->ctx, METRIC_THRESHOLD_UNKNOWN, "%8.3f", 351 + "GHz", ratio); 347 352 } else { 348 - out->print_metric(config, out->ctx, /*color=*/NULL, /*fmt=*/NULL, "GHz", 0); 353 + out->print_metric(config, out->ctx, METRIC_THRESHOLD_UNKNOWN, /*fmt=*/NULL, 354 + "GHz", 0); 349 355 } 350 356 } 351 357 ··· 361 363 double wall_time = avg_stats(&walltime_nsecs_stats); 362 364 363 365 if (wall_time) { 364 - print_metric(config, ctxp, /*color=*/NULL, "%8.3f", "CPUs utilized", 366 + print_metric(config, ctxp, METRIC_THRESHOLD_UNKNOWN, "%8.3f", "CPUs utilized", 365 367 nsecs / (wall_time * evsel->scale)); 366 368 } else { 367 - print_metric(config, ctxp, /*color=*/NULL, /*fmt=*/NULL, "CPUs utilized", 0); 369 + print_metric(config, ctxp, METRIC_THRESHOLD_UNKNOWN, /*fmt=*/NULL, 370 + "CPUs utilized", 0); 368 371 } 369 372 } 370 373 ··· 499 500 double ratio, scale, threshold; 500 501 int i; 501 502 void *ctxp = out->ctx; 502 - const char *color = NULL; 503 + enum metric_threshold_classify thresh = METRIC_THRESHOLD_UNKNOWN; 503 504 504 505 pctx = expr__ctx_new(); 505 506 if (!pctx) ··· 522 523 if (metric_threshold && 523 524 expr__parse(&threshold, pctx, metric_threshold) == 0 && 524 525 !isnan(threshold)) { 525 - color = fpclassify(threshold) == FP_ZERO 526 - ? PERF_COLOR_GREEN : PERF_COLOR_RED; 526 + thresh = fpclassify(threshold) == FP_ZERO 527 + ? METRIC_THRESHOLD_GOOD : METRIC_THRESHOLD_BAD; 527 528 } 528 529 529 530 if (metric_unit && metric_name) { ··· 538 539 scnprintf(metric_bf, sizeof(metric_bf), 539 540 "%s %s", unit, metric_name); 540 541 541 - print_metric(config, ctxp, color, "%8.1f", 542 + print_metric(config, ctxp, thresh, "%8.1f", 542 543 metric_bf, ratio); 543 544 } else { 544 - print_metric(config, ctxp, color, "%8.2f", 545 + print_metric(config, ctxp, thresh, "%8.2f", 545 546 metric_name ? 546 547 metric_name : 547 548 out->force_header ? evsel->name : "", 548 549 ratio); 549 550 } 550 551 } else { 551 - print_metric(config, ctxp, color, /*fmt=*/NULL, 552 + print_metric(config, ctxp, thresh, /*fmt=*/NULL, 552 553 out->force_header ? 553 554 (metric_name ?: evsel->name) : "", 0); 554 555 } 555 556 } else { 556 - print_metric(config, ctxp, color, /*fmt=*/NULL, 557 + print_metric(config, ctxp, thresh, /*fmt=*/NULL, 557 558 out->force_header ? 558 559 (metric_name ?: evsel->name) : "", 0); 559 560 } ··· 724 725 725 726 if (unit != ' ') 726 727 snprintf(unit_buf, sizeof(unit_buf), "%c/sec", unit); 727 - print_metric(config, ctxp, /*color=*/NULL, "%8.3f", 728 + print_metric(config, ctxp, METRIC_THRESHOLD_UNKNOWN, "%8.3f", 728 729 unit_buf, ratio); 729 730 } else { 730 731 num = 0; ··· 735 736 perf_stat__print_shadow_stats_metricgroup(config, evsel, aggr_idx, 736 737 &num, NULL, out, metric_events); 737 738 738 - if (num == 0) 739 - print_metric(config, ctxp, /*color=*/NULL, /*fmt=*/NULL, /*unit=*/NULL, 0); 739 + if (num == 0) { 740 + print_metric(config, ctxp, METRIC_THRESHOLD_UNKNOWN, 741 + /*fmt=*/NULL, /*unit=*/NULL, 0); 742 + } 740 743 } 741 744 742 745 /**
+11 -1
tools/perf/util/stat.h
··· 154 154 extern struct stats walltime_nsecs_stats; 155 155 extern struct rusage_stats ru_stats; 156 156 157 + enum metric_threshold_classify { 158 + METRIC_THRESHOLD_UNKNOWN, 159 + METRIC_THRESHOLD_BAD, 160 + METRIC_THRESHOLD_NEARLY_BAD, 161 + METRIC_THRESHOLD_LESS_GOOD, 162 + METRIC_THRESHOLD_GOOD, 163 + }; 164 + const char *metric_threshold_classify__color(enum metric_threshold_classify thresh); 165 + 157 166 typedef void (*print_metric_t)(struct perf_stat_config *config, 158 - void *ctx, const char *color, 167 + void *ctx, 168 + enum metric_threshold_classify thresh, 159 169 const char *fmt, 160 170 const char *unit, 161 171 double val);