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
26stat_output=$(mktemp /tmp/__perf_test.stat_output.json.XXXXX)
27
28cleanup() {
29  rm -f "${stat_output}"
30
31  trap - EXIT TERM INT
32}
33
34trap_cleanup() {
35  cleanup
36  exit 1
37}
38trap trap_cleanup EXIT TERM INT
39
40# Return true if perf_event_paranoid is > $1 and not running as root.
41function ParanoidAndNotRoot()
42{
43	 [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ]
44}
45
46check_no_args()
47{
48	echo -n "Checking json output: no args "
49	perf stat -j -o "${stat_output}" true
50	$PYTHON $pythonchecker --no-args --file "${stat_output}"
51	echo "[Success]"
52}
53
54check_system_wide()
55{
56	echo -n "Checking json output: system wide "
57	if ParanoidAndNotRoot 0
58	then
59		echo "[Skip] paranoia and not root"
60		return
61	fi
62	perf stat -j -a -o "${stat_output}" true
63	$PYTHON $pythonchecker --system-wide --file "${stat_output}"
64	echo "[Success]"
65}
66
67check_system_wide_no_aggr()
68{
69	echo -n "Checking json output: system wide no aggregation "
70	if ParanoidAndNotRoot 0
71	then
72		echo "[Skip] paranoia and not root"
73		return
74	fi
75	perf stat -j -A -a --no-merge -o "${stat_output}" true
76	$PYTHON $pythonchecker --system-wide-no-aggr --file "${stat_output}"
77	echo "[Success]"
78}
79
80check_interval()
81{
82	echo -n "Checking json output: interval "
83	perf stat -j -I 1000 -o "${stat_output}" true
84	$PYTHON $pythonchecker --interval --file "${stat_output}"
85	echo "[Success]"
86}
87
88
89check_event()
90{
91	echo -n "Checking json output: event "
92	perf stat -j -e cpu-clock -o "${stat_output}" true
93	$PYTHON $pythonchecker --event --file "${stat_output}"
94	echo "[Success]"
95}
96
97check_per_core()
98{
99	echo -n "Checking json output: per core "
100	if ParanoidAndNotRoot 0
101	then
102		echo "[Skip] paranoia and not root"
103		return
104	fi
105	perf stat -j --per-core -a -o "${stat_output}" true
106	$PYTHON $pythonchecker --per-core --file "${stat_output}"
107	echo "[Success]"
108}
109
110check_per_thread()
111{
112	echo -n "Checking json output: per thread "
113	if ParanoidAndNotRoot 0
114	then
115		echo "[Skip] paranoia and not root"
116		return
117	fi
118	perf stat -j --per-thread -a -o "${stat_output}" true
119	$PYTHON $pythonchecker --per-thread --file "${stat_output}"
120	echo "[Success]"
121}
122
123check_per_cache_instance()
124{
125	echo -n "Checking json output: per cache_instance "
126	if ParanoidAndNotRoot 0
127	then
128		echo "[Skip] paranoia and not root"
129		return
130	fi
131	perf stat -j --per-cache -a true 2>&1 | $PYTHON $pythonchecker --per-cache
132	echo "[Success]"
133}
134
135check_per_die()
136{
137	echo -n "Checking json output: per die "
138	if ParanoidAndNotRoot 0
139	then
140		echo "[Skip] paranoia and not root"
141		return
142	fi
143	perf stat -j --per-die -a -o "${stat_output}" true
144	$PYTHON $pythonchecker --per-die --file "${stat_output}"
145	echo "[Success]"
146}
147
148check_per_node()
149{
150	echo -n "Checking json output: per node "
151	if ParanoidAndNotRoot 0
152	then
153		echo "[Skip] paranoia and not root"
154		return
155	fi
156	perf stat -j --per-node -a -o "${stat_output}" true
157	$PYTHON $pythonchecker --per-node --file "${stat_output}"
158	echo "[Success]"
159}
160
161check_per_socket()
162{
163	echo -n "Checking json output: per socket "
164	if ParanoidAndNotRoot 0
165	then
166		echo "[Skip] paranoia and not root"
167		return
168	fi
169	perf stat -j --per-socket -a -o "${stat_output}" true
170	$PYTHON $pythonchecker --per-socket --file "${stat_output}"
171	echo "[Success]"
172}
173
174# The perf stat options for per-socket, per-core, per-die
175# and -A ( no_aggr mode ) uses the info fetched from this
176# directory: "/sys/devices/system/cpu/cpu*/topology". For
177# example, socket value is fetched from "physical_package_id"
178# file in topology directory.
179# Reference: cpu__get_topology_int in util/cpumap.c
180# If the platform doesn't expose topology information, values
181# will be set to -1. For example, incase of pSeries platform
182# of powerpc, value for  "physical_package_id" is restricted
183# and set to -1. Check here validates the socket-id read from
184# topology file before proceeding further
185
186FILE_LOC="/sys/devices/system/cpu/cpu*/topology/"
187FILE_NAME="physical_package_id"
188
189check_for_topology()
190{
191	if ! ParanoidAndNotRoot 0
192	then
193		socket_file=`ls $FILE_LOC/$FILE_NAME | head -n 1`
194		[ -z $socket_file ] && return 0
195		socket_id=`cat $socket_file`
196		[ $socket_id == -1 ] && skip_test=1
197		return 0
198	fi
199}
200
201check_for_topology
202check_no_args
203check_system_wide
204check_interval
205check_event
206check_per_thread
207check_per_node
208if [ $skip_test -ne 1 ]
209then
210	check_system_wide_no_aggr
211	check_per_core
212	check_per_cache_instance
213	check_per_die
214	check_per_socket
215else
216	echo "[Skip] Skipping tests for system_wide_no_aggr, per_core, per_die and per_socket since socket id exposed via topology is invalid"
217fi
218cleanup
219exit 0
220