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=$(mktemp /tmp/__perf_test.perf.data.XXXXXX) 20 21cleanup() { 22 echo "Cleaning up files..." 23 rm -f ${PERF_DATA} ${PERF_DATA}.jit /tmp/jit-${PID}.dump /tmp/jitted-${PID}-*.so 2> /dev/null 24 25 trap - EXIT TERM INT 26} 27 28trap_cleanup() { 29 echo "Unexpected termination" 30 cleanup 31 exit 1 32} 33 34trap trap_cleanup EXIT TERM INT 35 36echo "Run python with -Xperf_jit" 37cat <<EOF | perf record -k 1 -g --call-graph dwarf -o "${PERF_DATA}" \ 38 -- ${PYTHON} -Xperf_jit 39def foo(n): 40 result = 0 41 for _ in range(n): 42 result += 1 43 return result 44 45def bar(n): 46 foo(n) 47 48def baz(n): 49 bar(n) 50 51if __name__ == "__main__": 52 baz(1000000) 53EOF 54 55# extract PID of the target process from the data 56_PID=$(perf report -i "${PERF_DATA}" -F pid -q -g none | cut -d: -f1 -s) 57PID=$(echo -n $_PID) # remove newlines 58 59echo "Generate JIT-ed DSOs using perf inject" 60DEBUGINFOD_URLS='' perf inject -i "${PERF_DATA}" -j -o "${PERF_DATA}.jit" 61 62echo "Add JIT-ed DSOs to the build-ID cache" 63for F in /tmp/jitted-${PID}-*.so; do 64 perf buildid-cache -a "${F}" 65done 66 67echo "Check the symbol containing the function/module name" 68NUM=$(perf report -i "${PERF_DATA}.jit" -s sym | grep -cE 'py::(foo|bar|baz):<stdin>') 69 70echo "Found ${NUM} matching lines" 71 72echo "Remove JIT-ed DSOs from the build-ID cache" 73for F in /tmp/jitted-${PID}-*.so; do 74 perf buildid-cache -r "${F}" 75done 76 77cleanup 78 79if [ "${NUM}" -eq 0 ]; then 80 exit 1 81fi 82