[PATCH v4 05/13] perf tests: Skip metrics validation if system-wide recording lacks permission

From: Ian Rogers

Date: Mon Jun 22 2026 - 21:30:55 EST


The metrics value validation test requires system-wide recording (`-a`),
which can fail on systems without root permissions or where paranoid
levels restrict tracing. Add a check to skip the test if `-a` is not
supported.

Also fix false negatives during validation by updating parse error string
patterns and resolving issues in metric list generation.

Fixes: 3ad7092f5145 ("perf test: Add metric value validation test")
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Ian Rogers <irogers@xxxxxxxxxx>
---
.../tests/shell/lib/perf_metric_validation.py | 11 ++-
tools/perf/tests/shell/stat_all_metrics.sh | 75 ++++++++++++-------
tools/perf/tests/shell/stat_metrics_values.sh | 7 ++
3 files changed, 60 insertions(+), 33 deletions(-)

diff --git a/tools/perf/tests/shell/lib/perf_metric_validation.py b/tools/perf/tests/shell/lib/perf_metric_validation.py
index dea8ef1977bf..3d52f94f22b9 100644
--- a/tools/perf/tests/shell/lib/perf_metric_validation.py
+++ b/tools/perf/tests/shell/lib/perf_metric_validation.py
@@ -383,10 +383,13 @@ class Validator:
wl = workload.split()
command.extend(wl)
print(" ".join(command))
- cmd = subprocess.run(command, stderr=subprocess.PIPE, encoding='utf-8')
- data = [x+'}' for x in cmd.stderr.split('}\n') if x]
- if data[0][0] != '{':
- data[0] = data[0][data[0].find('{'):]
+ cmd = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8')
+ lines = cmd.stderr.splitlines() + cmd.stdout.splitlines()
+ data = []
+ for line in lines:
+ line = line.strip()
+ if line.startswith('{') and line.endswith('}'):
+ data.append(line)
return data

def collect_perf(self, workload: str):
diff --git a/tools/perf/tests/shell/stat_all_metrics.sh b/tools/perf/tests/shell/stat_all_metrics.sh
index b582d23f28c9..feeb34c6fa6d 100755
--- a/tools/perf/tests/shell/stat_all_metrics.sh
+++ b/tools/perf/tests/shell/stat_all_metrics.sh
@@ -12,38 +12,65 @@ system_wide_flag="-a"
if ParanoidAndNotRoot 0
then
system_wide_flag=""
- test_prog="perf test -w noploop"
+ test_prog="perf test -w noploop 0.01"
fi

+check_metric() {
+ local output="$1"
+ local status="$2"
+ local metric="$3"
+
+ if [[ $status -ne 0 || ! "$output" =~ ${metric:0:50} ]]; then
+ return 1
+ fi
+
+ if [[ "$output" =~ "<not counted>" || "$output" =~ "<not supported>" ]]; then
+ return 1
+ fi
+
+ return 0
+}
+
skip=0
err=3
for m in $(perf list --raw-dump metrics); do
echo "Testing $m"
result=$(perf stat -M "$m" $system_wide_flag -- $test_prog 2>&1)
result_err=$?
- if [[ $result_err -eq 0 && "$result" =~ ${m:0:50} ]]
- then
- # No error result and metric shown.
+
+ if check_metric "$result" $result_err "$m"; then
if [[ "$err" -ne 1 ]]
then
err=0
fi
continue
fi
- if [[ "$result" =~ "Cannot resolve IDs for" || "$result" =~ "No supported events found" ]]
+
+ if [[ "$result" =~ "Access to performance monitoring and observability operations is limited" || \
+ "$result" =~ "in per-thread mode, enable system wide" || \
+ "$result" =~ "<not supported>" || \
+ "$result" =~ "Cannot resolve IDs for" || \
+ "$result" =~ "No supported events found" || \
+ "$result" =~ "FP_ARITH" || \
+ "$result" =~ "AMX" || \
+ "$result" =~ "PMM" ]]
then
- if [[ $(perf list --raw-dump $m) == "Default"* ]]
- then
- echo "[Ignored $m] failed but as a Default metric this can be expected"
- echo $result
+ true
+ else
+ result=$(perf stat -M "$m" $system_wide_flag -- perf test -w noploop 0.1 2>&1)
+ result_err=$?
+
+ if check_metric "$result" $result_err "$m"; then
+ if [[ "$err" -ne 1 ]]
+ then
+ err=0
+ fi
continue
fi
- echo "[Failed $m] Metric contains missing events"
- echo $result
- err=1 # Fail
- continue
- elif [[ "$result" =~ \
- "Access to performance monitoring and observability operations is limited" ]]
+ fi
+
+ # If retry also failed, determine if we skip, ignore, or fail
+ if [[ "$result" =~ "Access to performance monitoring and observability operations is limited" ]]
then
echo "[Skipped $m] Permission failure"
echo $result
@@ -61,7 +88,9 @@ for m in $(perf list --raw-dump metrics); do
skip=1
fi
continue
- elif [[ "$result" =~ "<not supported>" ]]
+ elif [[ "$result" =~ "<not supported>" || \
+ "$result" =~ "Cannot resolve IDs for" || \
+ "$result" =~ "No supported events found" ]]
then
if [[ $(perf list --raw-dump $m) == "Default"* ]]
then
@@ -105,19 +134,7 @@ for m in $(perf list --raw-dump metrics); do
continue
fi

- # Failed, possibly the workload was too small so retry with something longer.
- result=$(perf stat -M "$m" $system_wide_flag -- perf bench internals synthesize 2>&1)
- result_err=$?
- if [[ $result_err -eq 0 && "$result" =~ ${m:0:50} ]]
- then
- # No error result and metric shown.
- if [[ "$err" -ne 1 ]]
- then
- err=0
- fi
- continue
- fi
- echo "[Failed $m] has non-zero error '$result_err' or not printed in:"
+ echo "[Failed $m] has non-zero error '$result_err' or not printed/counted in:"
echo "$result"
err=1
done
diff --git a/tools/perf/tests/shell/stat_metrics_values.sh b/tools/perf/tests/shell/stat_metrics_values.sh
index 30566f0b5427..76f1e99d1273 100755
--- a/tools/perf/tests/shell/stat_metrics_values.sh
+++ b/tools/perf/tests/shell/stat_metrics_values.sh
@@ -8,6 +8,13 @@ shelldir=$(dirname "$0")

grep -q GenuineIntel /proc/cpuinfo || { echo Skipping non-Intel; exit 2; }

+# Skip if no permission to record system-wide events
+if ! perf stat -a -e instructions sleep 0.01 >/dev/null 2>&1; then
+ echo "Skipping: no permission to record system-wide events (-a)"
+ exit 2
+fi
+
+
pythonvalidator=$(dirname $0)/lib/perf_metric_validation.py
rulefile=$(dirname $0)/lib/perf_metric_validation_rules.json
tmpdir=$(mktemp -d /tmp/__perf_test.program.XXXXX)
--
2.55.0.rc0.786.g65d90a0328-goog