Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf test: Add python JIT dump test

Add a test case for the python interpreter like below so that we can
make sure it won't break again. To validate the effect of build-ID
generation, it adds and removes the JIT'ed DSOs to/from the build-ID
cache for the test.

$ perf test -vv jitdump
84: python profiling with jitdump:
--- start ---
test child forked, pid 214316
Run python with -Xperf_jit
[ perf record: Woken up 5 times to write data ]
[ perf record: Captured and wrote 1.180 MB /tmp/__perf_test.perf.data.XbqZNm (140 samples) ]
Generate JIT-ed DSOs using perf inject
Add JIT-ed DSOs to the build-ID cache
Check the symbol containing the script name
Found 108 matching lines
Remove JIT-ed DSOs from the build-ID cache
---- end(0) ----
84: python profiling with jitdump : Ok

Cc: Pablo Galindo <pablogsal@gmail.com>
Link: https://docs.python.org/3/howto/perf_profiling.html#how-to-work-without-frame-pointers
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

+81
+81
tools/perf/tests/shell/jitdump-python.sh
··· 1 + #!/bin/bash 2 + # python profiling with jitdump 3 + # SPDX-License-Identifier: GPL-2.0 4 + 5 + SHELLDIR=$(dirname $0) 6 + # shellcheck source=lib/setup_python.sh 7 + . "${SHELLDIR}"/lib/setup_python.sh 8 + 9 + OUTPUT=$(${PYTHON} -Xperf_jit -c 'import os, sys; print(os.getpid(), sys.is_stack_trampoline_active())' 2> /dev/null) 10 + PID=${OUTPUT% *} 11 + HAS_PERF_JIT=${OUTPUT#* } 12 + 13 + rm -f /tmp/jit-${PID}.dump 2> /dev/null 14 + if [ "${HAS_PERF_JIT}" != "True" ]; then 15 + echo "SKIP: python JIT dump is not available" 16 + exit 2 17 + fi 18 + 19 + PERF_DATA=$(mktemp /tmp/__perf_test.perf.data.XXXXXX) 20 + 21 + cleanup() { 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 + 28 + trap_cleanup() { 29 + echo "Unexpected termination" 30 + cleanup 31 + exit 1 32 + } 33 + 34 + trap trap_cleanup EXIT TERM INT 35 + 36 + echo "Run python with -Xperf_jit" 37 + cat <<EOF | perf record -k 1 -g --call-graph dwarf -o "${PERF_DATA}" \ 38 + -- ${PYTHON} -Xperf_jit 39 + def foo(n): 40 + result = 0 41 + for _ in range(n): 42 + result += 1 43 + return result 44 + 45 + def bar(n): 46 + foo(n) 47 + 48 + def baz(n): 49 + bar(n) 50 + 51 + if __name__ == "__main__": 52 + baz(1000000) 53 + EOF 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) 57 + PID=$(echo -n $_PID) # remove newlines 58 + 59 + echo "Generate JIT-ed DSOs using perf inject" 60 + DEBUGINFOD_URLS='' perf inject -i "${PERF_DATA}" -j -o "${PERF_DATA}.jit" 61 + 62 + echo "Add JIT-ed DSOs to the build-ID cache" 63 + for F in /tmp/jitted-${PID}-*.so; do 64 + perf buildid-cache -a "${F}" 65 + done 66 + 67 + echo "Check the symbol containing the function/module name" 68 + NUM=$(perf report -i "${PERF_DATA}.jit" -s sym | grep -cE 'py::(foo|bar|baz):<stdin>') 69 + 70 + echo "Found ${NUM} matching lines" 71 + 72 + echo "Remove JIT-ed DSOs from the build-ID cache" 73 + for F in /tmp/jitted-${PID}-*.so; do 74 + perf buildid-cache -r "${F}" 75 + done 76 + 77 + cleanup 78 + 79 + if [ "${NUM}" -eq 0 ]; then 80 + exit 1 81 + fi