mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 04:24:31 +01:00
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>
This commit is contained in:
parent
446c595dc0
commit
bb5a920b90
3 changed files with 26 additions and 37 deletions
|
|
@ -820,12 +820,6 @@ static void printout(struct perf_stat_config *config, struct outstate *os,
|
|||
}
|
||||
|
||||
if (run == 0 || ena == 0 || counter->counts->scaled == -1) {
|
||||
if (config->metric_only) {
|
||||
pm(config, os, METRIC_THRESHOLD_UNKNOWN, /*format=*/NULL,
|
||||
/*unit=*/NULL, /*val=*/0);
|
||||
return;
|
||||
}
|
||||
|
||||
ok = false;
|
||||
|
||||
if (counter->supported) {
|
||||
|
|
@ -848,33 +842,32 @@ static void printout(struct perf_stat_config *config, struct outstate *os,
|
|||
print_running(config, os, run, ena, /*before_metric=*/true);
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
if (!config->metric_only && counter->default_metricgroup && !counter->default_show_events) {
|
||||
void *from = NULL;
|
||||
if (!config->metric_only && counter->default_metricgroup &&
|
||||
!counter->default_show_events) {
|
||||
void *from = NULL;
|
||||
|
||||
aggr_printout(config, os, os->evsel, os->id, os->aggr_nr);
|
||||
/* Print out all the metricgroup with the same metric event. */
|
||||
do {
|
||||
int num = 0;
|
||||
aggr_printout(config, os, os->evsel, os->id, os->aggr_nr);
|
||||
/* Print out all the metricgroup with the same metric event. */
|
||||
do {
|
||||
int num = 0;
|
||||
|
||||
/* Print out the new line for the next new metricgroup. */
|
||||
if (from) {
|
||||
if (config->json_output)
|
||||
new_line_json(config, (void *)os);
|
||||
else
|
||||
__new_line_std_csv(config, os);
|
||||
}
|
||||
/* Print out the new line for the next new metricgroup. */
|
||||
if (from) {
|
||||
if (config->json_output)
|
||||
new_line_json(config, (void *)os);
|
||||
else
|
||||
__new_line_std_csv(config, os);
|
||||
}
|
||||
|
||||
print_noise(config, os, counter, noise, /*before_metric=*/true);
|
||||
print_running(config, os, run, ena, /*before_metric=*/true);
|
||||
from = perf_stat__print_shadow_stats_metricgroup(config, counter, aggr_idx,
|
||||
&num, from, &out);
|
||||
} while (from != NULL);
|
||||
} else {
|
||||
perf_stat__print_shadow_stats(config, counter, aggr_idx, &out);
|
||||
}
|
||||
print_noise(config, os, counter, noise,
|
||||
/*before_metric=*/true);
|
||||
print_running(config, os, run, ena,
|
||||
/*before_metric=*/true);
|
||||
from = perf_stat__print_shadow_stats_metricgroup(
|
||||
config, counter, aggr_idx, &num, from, &out);
|
||||
} while (from != NULL);
|
||||
} else {
|
||||
pm(config, os, METRIC_THRESHOLD_UNKNOWN, /*format=*/NULL, /*unit=*/NULL, /*val=*/0);
|
||||
perf_stat__print_shadow_stats(config, counter, aggr_idx, &out);
|
||||
}
|
||||
|
||||
if (!config->metric_only) {
|
||||
|
|
@ -987,7 +980,7 @@ static void print_counter_aggrdata(struct perf_stat_config *config,
|
|||
ena = aggr->counts.ena;
|
||||
run = aggr->counts.run;
|
||||
|
||||
if (perf_stat__skip_metric_event(counter, ena, run))
|
||||
if (perf_stat__skip_metric_event(counter))
|
||||
return;
|
||||
|
||||
if (val == 0 && should_skip_zero_counter(config, counter, &id))
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ static int prepare_metric(struct perf_stat_config *config,
|
|||
}
|
||||
/* Time events are always on CPU0, the first aggregation index. */
|
||||
aggr = &ps->aggr[is_tool_time ? tool_aggr_idx : aggr_idx];
|
||||
if (!aggr || !metric_events[i]->supported) {
|
||||
if (!aggr || !metric_events[i]->supported || aggr->counts.run == 0) {
|
||||
/*
|
||||
* Not supported events will have a count of 0, which
|
||||
* can be confusing in a metric. Explicitly set the
|
||||
|
|
@ -335,14 +335,10 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
|
|||
* perf_stat__skip_metric_event - Skip the evsel in the Default metricgroup,
|
||||
* if it's not running or not the metric event.
|
||||
*/
|
||||
bool perf_stat__skip_metric_event(struct evsel *evsel,
|
||||
u64 ena, u64 run)
|
||||
bool perf_stat__skip_metric_event(struct evsel *evsel)
|
||||
{
|
||||
if (!evsel->default_metricgroup)
|
||||
return false;
|
||||
|
||||
if (!ena || !run)
|
||||
return true;
|
||||
|
||||
return !metricgroup__lookup(&evsel->evlist->metric_events, evsel, false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config,
|
|||
struct evsel *evsel,
|
||||
int aggr_idx,
|
||||
struct perf_stat_output_ctx *out);
|
||||
bool perf_stat__skip_metric_event(struct evsel *evsel, u64 ena, u64 run);
|
||||
bool perf_stat__skip_metric_event(struct evsel *evsel);
|
||||
void *perf_stat__print_shadow_stats_metricgroup(struct perf_stat_config *config,
|
||||
struct evsel *evsel,
|
||||
int aggr_idx,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue