Skip to content

Commit bb5a920

Browse files
Chun-Tse Shaoacmel
authored andcommitted
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 <[email protected]> Signed-off-by: Chun-Tse Shao <[email protected]> Cc: Adrian Hunter <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: James Clark <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Kan Liang <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Yang Li <[email protected]> Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 446c595 commit bb5a920

3 files changed

Lines changed: 29 additions & 40 deletions

File tree

tools/perf/util/stat-display.c

Lines changed: 26 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -820,12 +820,6 @@ static void printout(struct perf_stat_config *config, struct outstate *os,
820820
}
821821

822822
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-
829823
ok = false;
830824

831825
if (counter->supported) {
@@ -848,33 +842,32 @@ static void printout(struct perf_stat_config *config, struct outstate *os,
848842
print_running(config, os, run, ena, /*before_metric=*/true);
849843
}
850844

851-
if (ok) {
852-
if (!config->metric_only && counter->default_metricgroup && !counter->default_show_events) {
853-
void *from = NULL;
854-
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;
859-
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-
}
867-
868-
print_noise(config, os, counter, noise, /*before_metric=*/true);
869-
print_running(config, os, run, ena, /*before_metric=*/true);
870-
from = perf_stat__print_shadow_stats_metricgroup(config, counter, aggr_idx,
871-
&num, from, &out);
872-
} while (from != NULL);
873-
} else {
874-
perf_stat__print_shadow_stats(config, counter, aggr_idx, &out);
875-
}
845+
if (!config->metric_only && counter->default_metricgroup &&
846+
!counter->default_show_events) {
847+
void *from = NULL;
848+
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;
853+
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+
}
861+
862+
print_noise(config, os, counter, noise,
863+
/*before_metric=*/true);
864+
print_running(config, os, run, ena,
865+
/*before_metric=*/true);
866+
from = perf_stat__print_shadow_stats_metricgroup(
867+
config, counter, aggr_idx, &num, from, &out);
868+
} while (from != NULL);
876869
} else {
877-
pm(config, os, METRIC_THRESHOLD_UNKNOWN, /*format=*/NULL, /*unit=*/NULL, /*val=*/0);
870+
perf_stat__print_shadow_stats(config, counter, aggr_idx, &out);
878871
}
879872

880873
if (!config->metric_only) {
@@ -987,7 +980,7 @@ static void print_counter_aggrdata(struct perf_stat_config *config,
987980
ena = aggr->counts.ena;
988981
run = aggr->counts.run;
989982

990-
if (perf_stat__skip_metric_event(counter, ena, run))
983+
if (perf_stat__skip_metric_event(counter))
991984
return;
992985

993986
if (val == 0 && should_skip_zero_counter(config, counter, &id))

tools/perf/util/stat-shadow.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ static int prepare_metric(struct perf_stat_config *config,
8383
}
8484
/* Time events are always on CPU0, the first aggregation index. */
8585
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) {
8787
/*
8888
* Not supported events will have a count of 0, which
8989
* can be confusing in a metric. Explicitly set the
@@ -335,14 +335,10 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
335335
* perf_stat__skip_metric_event - Skip the evsel in the Default metricgroup,
336336
* if it's not running or not the metric event.
337337
*/
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)
340339
{
341340
if (!evsel->default_metricgroup)
342341
return false;
343342

344-
if (!ena || !run)
345-
return true;
346-
347343
return !metricgroup__lookup(&evsel->evlist->metric_events, evsel, false);
348344
}

tools/perf/util/stat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
163163
struct evsel *evsel,
164164
int aggr_idx,
165165
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);
167167
void *perf_stat__print_shadow_stats_metricgroup(struct perf_stat_config *config,
168168
struct evsel *evsel,
169169
int aggr_idx,

0 commit comments

Comments
 (0)