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