projects/linux·blob master · refs

108 lines · 2.7 KiB

1#!/bin/bash
2# python profiling with jitdump
3# SPDX-License-Identifier: GPL-2.0
4
5SHELLDIR=$(dirname $0)
6# shellcheck source=lib/setup_python.sh
7. "${SHELLDIR}"/lib/setup_python.sh
8
9OUTPUT=$(${PYTHON} -Xperf_jit -c 'import os, sys; print(os.getpid(), sys.is_stack_trampoline_active())' 2> /dev/null)
10PID=${OUTPUT% *}
11HAS_PERF_JIT=${OUTPUT#* }
12
13rm -f /tmp/jit-${PID}.dump 2> /dev/null
14if [ "${HAS_PERF_JIT}" != "True" ]; then
15 echo "SKIP: python JIT dump is not available"
16 exit 2
17fi
18
19PERF_DATA_DIR=$(mktemp -d /tmp/__perf_test.perf.data.dir.XXXXXX)
20PERF_DATA="${PERF_DATA_DIR}/perf.data"
21
22cleanup() {
23 echo "Cleaning up files..."
24 rm -rf ${PERF_DATA_DIR} 2> /dev/null
25 for p in ${ALL_PIDS}; do
26 rm -f /tmp/jit-${p}.dump /tmp/jitted-${p}-*.so 2> /dev/null
27 done
28
29 trap - EXIT TERM INT
30}
31
32trap_cleanup() {
33 echo "Unexpected termination"
34 cleanup
35 exit 1
36}
37
38trap trap_cleanup EXIT TERM INT
39
40ALL_PIDS=""
41NUM=0
42for iterations in 1000000 10000000 50000000 100000000; do
43 echo "Running with $iterations iterations..."
44 rm -f "${PERF_DATA}.pid"
45 cat <<EOF | perf record -k 1 -g --call-graph dwarf -o "${PERF_DATA}" -- ${PYTHON} -Xperf_jit
46import os
47with open("${PERF_DATA}.pid", "w") as f:
48 f.write(str(os.getpid()))
49
50def foo(n):
51 result = 0
52 for _ in range(n):
53 result += 1
54 return result
55
56def bar(n):
57 foo(n)
58
59def baz(n):
60 bar(n)
61
62if __name__ == "__main__":
63 baz($iterations)
64EOF
65
66 if [ -f "${PERF_DATA}.pid" ]; then
67 REAL_PID=$(cat "${PERF_DATA}.pid")
68 ALL_PIDS="${ALL_PIDS} ${REAL_PID}"
69 fi
70
71 # extract PID of the target process from the data
72 PID=$(perf report -i "${PERF_DATA}" --stdio -F pid -q -g none | \
73 cut -d: -f1 -s | sort -u | head -n 1 | tr -d ' ')
74 if [ -z "${PID}" ]; then
75 echo "Failed to get PID, retrying..."
76 continue
77 fi
78 ALL_PIDS="${ALL_PIDS} ${PID}"
79
80 echo "Generate JIT-ed DSOs using perf inject"
81 DEBUGINFOD_URLS='' perf inject -i "${PERF_DATA}" -j -o "${PERF_DATA}.jit"
82
83 echo "Add JIT-ed DSOs to the build-ID cache"
84 for F in /tmp/jitted-${PID}-*.so; do
85 perf buildid-cache -a "${F}"
86 done
87
88 echo "Check the symbol containing the function/module name"
89 NUM=$(perf report -i "${PERF_DATA}.jit" -s sym --stdio | grep -cE 'py::(foo|bar|baz):<stdin>')
90
91 echo "Remove JIT-ed DSOs from the build-ID cache"
92 for F in /tmp/jitted-${PID}-*.so; do
93 perf buildid-cache -r "${F}"
94 done
95 rm -f /tmp/jitted-${PID}-*.so /tmp/jit-${PID}.dump 2>/dev/null
96
97 if [ "${NUM}" -gt 0 ]; then
98 echo "Success: found ${NUM} matching lines"
99 break
100 fi
101 echo "No matching lines found, retrying with more iterations..."
102done
103
104cleanup
105
106if [ "${NUM}" -eq 0 ]; then
107 exit 1
108fi