1#!/bin/sh
2# Check Arm CoreSight trace data recording and synthesized samples
3
4# Uses the 'perf record' to record trace data with Arm CoreSight sinks;
5# then verify if there have any branch samples and instruction samples
6# are generated by CoreSight with 'perf script' and 'perf report'
7# commands.
8
9# SPDX-License-Identifier: GPL-2.0
10# Leo Yan <leo.yan@linaro.org>, 2020
11
12perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
13file=$(mktemp /tmp/temporary_file.XXXXX)
14
15skip_if_no_cs_etm_event() {
16	perf list | grep -q 'cs_etm//' && return 0
17
18	# cs_etm event doesn't exist
19	return 2
20}
21
22skip_if_no_cs_etm_event || exit 2
23
24cleanup_files()
25{
26	rm -f ${perfdata}
27	rm -f ${file}
28}
29
30trap cleanup_files exit
31
32record_touch_file() {
33	echo "Recording trace (only user mode) with path: CPU$2 => $1"
34	rm -f $file
35	perf record -o ${perfdata} -e cs_etm/@$1/u --per-thread \
36		-- taskset -c $2 touch $file
37}
38
39perf_script_branch_samples() {
40	echo "Looking at perf.data file for dumping branch samples:"
41
42	# Below is an example of the branch samples dumping:
43	#   touch  6512          1         branches:u:      ffffb220824c strcmp+0xc (/lib/aarch64-linux-gnu/ld-2.27.so)
44	#   touch  6512          1         branches:u:      ffffb22082e0 strcmp+0xa0 (/lib/aarch64-linux-gnu/ld-2.27.so)
45	#   touch  6512          1         branches:u:      ffffb2208320 strcmp+0xe0 (/lib/aarch64-linux-gnu/ld-2.27.so)
46	perf script -F,-time -i ${perfdata} | \
47		egrep " +$1 +[0-9]+ .* +branches:(.*:)? +"
48}
49
50perf_report_branch_samples() {
51	echo "Looking at perf.data file for reporting branch samples:"
52
53	# Below is an example of the branch samples reporting:
54	#   73.04%    73.04%  touch    libc-2.27.so      [.] _dl_addr
55	#    7.71%     7.71%  touch    libc-2.27.so      [.] getenv
56	#    2.59%     2.59%  touch    ld-2.27.so        [.] strcmp
57	perf report --stdio -i ${perfdata} | \
58		egrep " +[0-9]+\.[0-9]+% +[0-9]+\.[0-9]+% +$1 "
59}
60
61perf_report_instruction_samples() {
62	echo "Looking at perf.data file for instruction samples:"
63
64	# Below is an example of the instruction samples reporting:
65	#   68.12%  touch    libc-2.27.so   [.] _dl_addr
66	#    5.80%  touch    libc-2.27.so   [.] getenv
67	#    4.35%  touch    ld-2.27.so     [.] _dl_fixup
68	perf report --itrace=i1000i --stdio -i ${perfdata} | \
69		egrep " +[0-9]+\.[0-9]+% +$1"
70}
71
72is_device_sink() {
73	# If the node of "enable_sink" is existed under the device path, this
74	# means the device is a sink device.  Need to exclude 'tpiu' since it
75	# cannot support perf PMU.
76	echo "$1" | egrep -q -v "tpiu"
77
78	if [ $? -eq 0 -a -e "$1/enable_sink" ]; then
79
80		pmu_dev="/sys/bus/event_source/devices/cs_etm/sinks/$2"
81
82		# Warn if the device is not supported by PMU
83		if ! [ -f $pmu_dev ]; then
84			echo "PMU doesn't support $pmu_dev"
85		fi
86
87		return 0
88	fi
89
90	# Otherwise, it's not a sink device
91	return 1
92}
93
94arm_cs_iterate_devices() {
95	for dev in $1/connections/out\:*; do
96
97		# Skip testing if it's not a directory
98		! [ -d $dev ] && continue;
99
100		# Read out its symbol link file name
101		path=`readlink -f $dev`
102
103		# Extract device name from path, e.g.
104		#   path = '/sys/devices/platform/20010000.etf/tmc_etf0'
105		#     `> device_name = 'tmc_etf0'
106		device_name=$(basename $path)
107
108		if is_device_sink $path $device_name; then
109
110			record_touch_file $device_name $2 &&
111			perf_script_branch_samples touch &&
112			perf_report_branch_samples touch &&
113			perf_report_instruction_samples touch
114
115			err=$?
116
117			# Exit when find failure
118			[ $err != 0 ] && exit $err
119		fi
120
121		arm_cs_iterate_devices $dev $2
122	done
123}
124
125arm_cs_etm_traverse_path_test() {
126	# Iterate for every ETM device
127	for dev in /sys/bus/coresight/devices/etm*; do
128
129		# Find the ETM device belonging to which CPU
130		cpu=`cat $dev/cpu`
131
132		echo $dev
133		echo $cpu
134
135		# Use depth-first search (DFS) to iterate outputs
136		arm_cs_iterate_devices $dev $cpu
137	done
138}
139
140arm_cs_etm_system_wide_test() {
141	echo "Recording trace with system wide mode"
142	perf record -o ${perfdata} -e cs_etm// -a -- ls
143
144	perf_script_branch_samples perf &&
145	perf_report_branch_samples perf &&
146	perf_report_instruction_samples perf
147
148	err=$?
149
150	# Exit when find failure
151	[ $err != 0 ] && exit $err
152}
153
154arm_cs_etm_snapshot_test() {
155	echo "Recording trace with snapshot mode"
156	perf record -o ${perfdata} -e cs_etm// -S \
157		-- dd if=/dev/zero of=/dev/null &
158	PERFPID=$!
159
160	# Wait for perf program
161	sleep 1
162
163	# Send signal to snapshot trace data
164	kill -USR2 $PERFPID
165
166	# Stop perf program
167	kill $PERFPID
168	wait $PERFPID
169
170	perf_script_branch_samples dd &&
171	perf_report_branch_samples dd &&
172	perf_report_instruction_samples dd
173
174	err=$?
175
176	# Exit when find failure
177	[ $err != 0 ] && exit $err
178}
179
180arm_cs_etm_traverse_path_test
181arm_cs_etm_system_wide_test
182arm_cs_etm_snapshot_test
183exit 0
184