| 1 | |
| 2 | |
| 3 | |
| 4 |
|
| 5 | SHELLDIR=$(dirname $0)
|
| 6 | |
| 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_DIR=$(mktemp -d /tmp/__perf_test.perf.data.dir.XXXXXX)
|
| 20 | PERF_DATA="${PERF_DATA_DIR}/perf.data"
|
| 21 |
|
| 22 | cleanup() {
|
| 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 |
|
| 32 | trap_cleanup() {
|
| 33 | echo "Unexpected termination"
|
| 34 | cleanup
|
| 35 | exit 1
|
| 36 | }
|
| 37 |
|
| 38 | trap trap_cleanup EXIT TERM INT
|
| 39 |
|
| 40 | ALL_PIDS=""
|
| 41 | NUM=0
|
| 42 | for 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
|
| 46 | import os
|
| 47 | with open("${PERF_DATA}.pid", "w") as f:
|
| 48 | f.write(str(os.getpid()))
|
| 49 |
|
| 50 | def foo(n):
|
| 51 | result = 0
|
| 52 | for _ in range(n):
|
| 53 | result += 1
|
| 54 | return result
|
| 55 |
|
| 56 | def bar(n):
|
| 57 | foo(n)
|
| 58 |
|
| 59 | def baz(n):
|
| 60 | bar(n)
|
| 61 |
|
| 62 | if __name__ == "__main__":
|
| 63 | baz($iterations)
|
| 64 | EOF
|
| 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 | |
| 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..."
|
| 102 | done
|
| 103 |
|
| 104 | cleanup
|
| 105 |
|
| 106 | if [ "${NUM}" -eq 0 ]; then
|
| 107 | exit 1
|
| 108 | fi
|