xref: /linux/tools/perf/tests/shell/jitdump-python.sh (revision 509a2b9a6e142697dd5f34cdd802e5b86eababa1)
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
109