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

Configure Feed

Select the types of activity you want to include in your feed.

perf stat: Ensure metrics are displayed even with failed events

Currently, `perf stat` skips or hides metrics when the underlying
hardware events cannot be counted (e.g., due to insufficient permissions
or unsupported events).

In `--metric-only` mode, this often results in missing columns or blank
spaces, making the output difficult to parse.

Modify the logic to ensure metrics are consistently displayed by
propagating NAN (Not a Number) through the expression evaluator.
Specifically:

1. Update `prepare_metric()` in stat-shadow.c to treat uncounted events
(where `run == 0`) as NAN. This leverages the existing math in expr.y
to propagate NAN through metric expressions.

2. Remove the early return in the display logic's `printout()` function
that was previously skipping metrics in `--metric-only` mode for
failed events.
l
3. Simplify `perf_stat__skip_metric_event()` to no longer depend on
event runtime.

Tested:

1. `perf all metrics test` did not crash while paranoid is 2.

2. Multiple combinations with `CPUs_utilized` while paranoid is 2.

$ ./perf stat -M CPUs_utilized -a -- sleep 1

Performance counter stats for 'system wide':

<not supported> msec cpu-clock:u # nan CPUs CPUs_utilized
1,006,356,120 duration_time

1.004375550 seconds time elapsed

$ ./perf stat -M CPUs_utilized -a -j -- sleep 1
{"counter-value" : "<not supported>", "unit" : "msec", "event" : "cpu-clock:u", "event-runtime" : 0, "pcnt-running" : 100.00, "metric-value" : "nan", "metric-unit" : "CPUs CPUs_utilized"}
{"counter-value" : "1006642462.000000", "unit" : "", "event" : "duration_time", "event-runtime" : 1, "pcnt-running" : 100.00}

$ ./perf stat -M CPUs_utilized -a --metric-only -- sleep 1

Performance counter stats for 'system wide':

CPUs CPUs_utilized
nan

1.004424652 seconds time elapsed

$ ./perf stat -M CPUs_utilized -a --metric-only -j -- sleep 1
{"CPUs CPUs_utilized" : "none"}

Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Chun-Tse Shao <ctshao@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Yang Li <yang.lee@linux.alibaba.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Chun-Tse Shao and committed by
Arnaldo Carvalho de Melo
bb5a920b 446c595d

+26 -37
+23 -30
tools/perf/util/stat-display.c
··· 820 820 } 821 821 822 822 if (run == 0 || ena == 0 || counter->counts->scaled == -1) { 823 - if (config->metric_only) { 824 - pm(config, os, METRIC_THRESHOLD_UNKNOWN, /*format=*/NULL, 825 - /*unit=*/NULL, /*val=*/0); 826 - return; 827 - } 828 - 829 823 ok = false; 830 824 831 825 if (counter->supported) { ··· 842 848 print_running(config, os, run, ena, /*before_metric=*/true); 843 849 } 844 850 845 - if (ok) { 846 - if (!config->metric_only && counter->default_metricgroup && !counter->default_show_events) { 847 - void *from = NULL; 851 + if (!config->metric_only && counter->default_metricgroup && 852 + !counter->default_show_events) { 853 + void *from = NULL; 848 854 849 - aggr_printout(config, os, os->evsel, os->id, os->aggr_nr); 850 - /* Print out all the metricgroup with the same metric event. */ 851 - do { 852 - int num = 0; 855 + aggr_printout(config, os, os->evsel, os->id, os->aggr_nr); 856 + /* Print out all the metricgroup with the same metric event. */ 857 + do { 858 + int num = 0; 853 859 854 - /* Print out the new line for the next new metricgroup. */ 855 - if (from) { 856 - if (config->json_output) 857 - new_line_json(config, (void *)os); 858 - else 859 - __new_line_std_csv(config, os); 860 - } 860 + /* Print out the new line for the next new metricgroup. */ 861 + if (from) { 862 + if (config->json_output) 863 + new_line_json(config, (void *)os); 864 + else 865 + __new_line_std_csv(config, os); 866 + } 861 867 862 - print_noise(config, os, counter, noise, /*before_metric=*/true); 863 - print_running(config, os, run, ena, /*before_metric=*/true); 864 - from = perf_stat__print_shadow_stats_metricgroup(config, counter, aggr_idx, 865 - &num, from, &out); 866 - } while (from != NULL); 867 - } else { 868 - perf_stat__print_shadow_stats(config, counter, aggr_idx, &out); 869 - } 868 + print_noise(config, os, counter, noise, 869 + /*before_metric=*/true); 870 + print_running(config, os, run, ena, 871 + /*before_metric=*/true); 872 + from = perf_stat__print_shadow_stats_metricgroup( 873 + config, counter, aggr_idx, &num, from, &out); 874 + } while (from != NULL); 870 875 } else { 871 - pm(config, os, METRIC_THRESHOLD_UNKNOWN, /*format=*/NULL, /*unit=*/NULL, /*val=*/0); 876 + perf_stat__print_shadow_stats(config, counter, aggr_idx, &out); 872 877 } 873 878 874 879 if (!config->metric_only) { ··· 980 987 ena = aggr->counts.ena; 981 988 run = aggr->counts.run; 982 989 983 - if (perf_stat__skip_metric_event(counter, ena, run)) 990 + if (perf_stat__skip_metric_event(counter)) 984 991 return; 985 992 986 993 if (val == 0 && should_skip_zero_counter(config, counter, &id))
+2 -6
tools/perf/util/stat-shadow.c
··· 83 83 } 84 84 /* Time events are always on CPU0, the first aggregation index. */ 85 85 aggr = &ps->aggr[is_tool_time ? tool_aggr_idx : aggr_idx]; 86 - if (!aggr || !metric_events[i]->supported) { 86 + if (!aggr || !metric_events[i]->supported || aggr->counts.run == 0) { 87 87 /* 88 88 * Not supported events will have a count of 0, which 89 89 * can be confusing in a metric. Explicitly set the ··· 335 335 * perf_stat__skip_metric_event - Skip the evsel in the Default metricgroup, 336 336 * if it's not running or not the metric event. 337 337 */ 338 - bool perf_stat__skip_metric_event(struct evsel *evsel, 339 - u64 ena, u64 run) 338 + bool perf_stat__skip_metric_event(struct evsel *evsel) 340 339 { 341 340 if (!evsel->default_metricgroup) 342 341 return false; 343 - 344 - if (!ena || !run) 345 - return true; 346 342 347 343 return !metricgroup__lookup(&evsel->evlist->metric_events, evsel, false); 348 344 }
+1 -1
tools/perf/util/stat.h
··· 163 163 struct evsel *evsel, 164 164 int aggr_idx, 165 165 struct perf_stat_output_ctx *out); 166 - bool perf_stat__skip_metric_event(struct evsel *evsel, u64 ena, u64 run); 166 + bool perf_stat__skip_metric_event(struct evsel *evsel); 167 167 void *perf_stat__print_shadow_stats_metricgroup(struct perf_stat_config *config, 168 168 struct evsel *evsel, 169 169 int aggr_idx,