1#!/bin/bash
2# perf stat JSON output linter
3# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
4# Checks various perf stat JSON output commands for the
5# correct number of fields.
6
7set -e
8
9skip_test=0
10
11pythonchecker=$(dirname $0)/lib/perf_json_output_lint.py
12if [ "x$PYTHON" == "x" ]
13then
14	if which python3 > /dev/null
15	then
16		PYTHON=python3
17	elif which python > /dev/null
18	then
19		PYTHON=python
20	else
21		echo Skipping test, python not detected please set environment variable PYTHON.
22		exit 2
23	fi
24fi
25
26# Return true if perf_event_paranoid is > $1 and not running as root.
27function ParanoidAndNotRoot()
28{
29	 [ $(id -u) != 0 ] && [ $(cat /proc/sys/kernel/perf_event_paranoid) -gt $1 ]
30}
31
32check_no_args()
33{
34	echo -n "Checking json output: no args "
35	perf stat -j true 2>&1 | $PYTHON $pythonchecker --no-args
36	echo "[Success]"
37}
38
39check_system_wide()
40{
41	echo -n "Checking json output: system wide "
42	if ParanoidAndNotRoot 0
43	then
44		echo "[Skip] paranoia and not root"
45		return
46	fi
47	perf stat -j -a true 2>&1 | $PYTHON $pythonchecker --system-wide
48	echo "[Success]"
49}
50
51check_system_wide_no_aggr()
52{
53	echo -n "Checking json output: system wide "
54	if ParanoidAndNotRoot 0
55	then
56		echo "[Skip] paranoia and not root"
57		return
58	fi
59	echo -n "Checking json output: system wide no aggregation "
60	perf stat -j -A -a --no-merge true 2>&1 | $PYTHON $pythonchecker --system-wide-no-aggr
61	echo "[Success]"
62}
63
64check_interval()
65{
66	echo -n "Checking json output: interval "
67	perf stat -j -I 1000 true 2>&1 | $PYTHON $pythonchecker --interval
68	echo "[Success]"
69}
70
71
72check_event()
73{
74	echo -n "Checking json output: event "
75	perf stat -j -e cpu-clock true 2>&1 | $PYTHON $pythonchecker --event
76	echo "[Success]"
77}
78
79check_per_core()
80{
81	echo -n "Checking json output: per core "
82	if ParanoidAndNotRoot 0
83	then
84		echo "[Skip] paranoia and not root"
85		return
86	fi
87	perf stat -j --per-core -a true 2>&1 | $PYTHON $pythonchecker --per-core
88	echo "[Success]"
89}
90
91check_per_thread()
92{
93	echo -n "Checking json output: per thread "
94	if ParanoidAndNotRoot 0
95	then
96		echo "[Skip] paranoia and not root"
97		return
98	fi
99	perf stat -j --per-thread -a true 2>&1 | $PYTHON $pythonchecker --per-thread
100	echo "[Success]"
101}
102
103check_per_die()
104{
105	echo -n "Checking json output: per die "
106	if ParanoidAndNotRoot 0
107	then
108		echo "[Skip] paranoia and not root"
109		return
110	fi
111	perf stat -j --per-die -a true 2>&1 | $PYTHON $pythonchecker --per-die
112	echo "[Success]"
113}
114
115check_per_node()
116{
117	echo -n "Checking json output: per node "
118	if ParanoidAndNotRoot 0
119	then
120		echo "[Skip] paranoia and not root"
121		return
122	fi
123	perf stat -j --per-node -a true 2>&1 | $PYTHON $pythonchecker --per-node
124	echo "[Success]"
125}
126
127check_per_socket()
128{
129	echo -n "Checking json output: per socket "
130	if ParanoidAndNotRoot 0
131	then
132		echo "[Skip] paranoia and not root"
133		return
134	fi
135	perf stat -j --per-socket -a true 2>&1 | $PYTHON $pythonchecker --per-socket
136	echo "[Success]"
137}
138
139# The perf stat options for per-socket, per-core, per-die
140# and -A ( no_aggr mode ) uses the info fetched from this
141# directory: "/sys/devices/system/cpu/cpu*/topology". For
142# example, socket value is fetched from "physical_package_id"
143# file in topology directory.
144# Reference: cpu__get_topology_int in util/cpumap.c
145# If the platform doesn't expose topology information, values
146# will be set to -1. For example, incase of pSeries platform
147# of powerpc, value for  "physical_package_id" is restricted
148# and set to -1. Check here validates the socket-id read from
149# topology file before proceeding further
150
151FILE_LOC="/sys/devices/system/cpu/cpu*/topology/"
152FILE_NAME="physical_package_id"
153
154check_for_topology()
155{
156	if ! ParanoidAndNotRoot 0
157	then
158		socket_file=`ls $FILE_LOC/$FILE_NAME | head -n 1`
159		[ -z $socket_file ] && return 0
160		socket_id=`cat $socket_file`
161		[ $socket_id == -1 ] && skip_test=1
162		return 0
163	fi
164}
165
166check_for_topology
167check_no_args
168check_system_wide
169check_interval
170check_event
171check_per_thread
172check_per_node
173if [ $skip_test -ne 1 ]
174then
175	check_system_wide_no_aggr
176	check_per_core
177	check_per_die
178	check_per_socket
179else
180	echo "[Skip] Skipping tests for system_wide_no_aggr, per_core, per_die and per_socket since socket id exposed via topology is invalid"
181fi
182exit 0
183