From b02aa1d1343f580e5a43789b392e0c813bc1cba9 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 25 Sep 2026 23:20:15 -0700 Subject: [PATCH] perf script: Support standalone scripts and remove embedded scripting Refactor 'perf script' to launch standalone scripts directly via fork() and execvp() and remove the legacy embedded Perl and Python scripting engines: - Remove the embedded Perl scripting engine (util/scripting-engines/trace-event-perl.c), Perl scripts, bin wrappers, and Trace-Util library (scripts/perl/Perf-Trace-Util/), and script_perl.sh test. - Remove libperl feature checks from Makefile.config, Makefile.perf, builtin-check.c, and Documentation/perf-check.txt. - Remove -g / --gen-script option and scripting_ops dispatch table from builtin-script.c and trace-event-scripting.c. - Hide the legacy -s / --script option and update script discovery in find_script() and list_available_scripts() to prioritize the system 'python' directory over bare filenames in the current directory. - Update the Python script shell tests (test_arm_coresight_disasm.sh, test_task_analyzer.sh, and test_*_python.sh) to invoke scripts via 'perf script EOF - if ! "$PYTHON" "$script_path" -i "${temp_data}" -f html --template "${temp_tpl}" \ + if ! perf script flamegraph -i "${temp_data}" -f html --template "${temp_tpl}" \ --colorscheme blue-green -o "${temp_html}" >/dev/null 2>&1; then echo "Custom template HTML test failed." err=1 diff --git a/tools/perf/tests/shell/test_futex_contention_python.sh b/tools/perf/tests/shell/test_futex_contention_python.sh index 26b13d263d20..a8846ed68ac2 100755 --- a/tools/perf/tests/shell/test_futex_contention_python.sh +++ b/tools/perf/tests/shell/test_futex_contention_python.sh @@ -101,7 +101,7 @@ test_file_mode() { return fi - if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then + if ! perf script futex-contention -i "${temp_data}" > "${temp_out}"; then echo "File mode test failed." err=1 else diff --git a/tools/perf/tests/shell/test_gecko_python.sh b/tools/perf/tests/shell/test_gecko_python.sh index eac9b2f8e3c7..de1d7fcf88b7 100755 --- a/tools/perf/tests/shell/test_gecko_python.sh +++ b/tools/perf/tests/shell/test_gecko_python.sh @@ -45,7 +45,7 @@ test_file_mode() { fi # Run the script in save-only mode with custom product and category colors - if ! "$PYTHON" "$script_path" -i "${temp_data}" \ + if ! perf script gecko -i "${temp_data}" \ --product "perf-test-product" --user-color blue --kernel-color red \ --save-only "${temp_json}" >/dev/null; then echo "File mode test failed." diff --git a/tools/perf/tests/shell/test_intel_pt_events_python.sh b/tools/perf/tests/shell/test_intel_pt_events_python.sh index 0d397792ced8..b5c3173fa2db 100755 --- a/tools/perf/tests/shell/test_intel_pt_events_python.sh +++ b/tools/perf/tests/shell/test_intel_pt_events_python.sh @@ -49,7 +49,7 @@ test_intel_pt() { fi # Run the script and check output - if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then + if ! perf script intel-pt-events -i "${temp_data}" > "${temp_out}"; then echo "intel-pt-events.py test failed." err=1 else diff --git a/tools/perf/tests/shell/test_mem_phys_addr_python.sh b/tools/perf/tests/shell/test_mem_phys_addr_python.sh index d094a0611a24..451692d5e089 100755 --- a/tools/perf/tests/shell/test_mem_phys_addr_python.sh +++ b/tools/perf/tests/shell/test_mem_phys_addr_python.sh @@ -87,7 +87,8 @@ test_file_mode() { fi # Run the script with custom --iomem - if ! "$PYTHON" "$script_path" -i "${temp_data}" --iomem "${temp_iomem}" > "${temp_out}" || \ + if ! perf script mem-phys-addr -i "${temp_data}" \ + --iomem "${temp_iomem}" > "${temp_out}" || \ [ ! -s "${temp_out}" ]; then echo "File mode test failed." err=1 diff --git a/tools/perf/tests/shell/test_net_dropmonitor_python.sh b/tools/perf/tests/shell/test_net_dropmonitor_python.sh index d00be255d259..05056a897bc9 100755 --- a/tools/perf/tests/shell/test_net_dropmonitor_python.sh +++ b/tools/perf/tests/shell/test_net_dropmonitor_python.sh @@ -59,7 +59,7 @@ if [ ! -s "${temp_data}" ]; then fi # Check that the script executes and outputs table header -if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then +if ! perf script net_dropmonitor -i "${temp_data}" > "${temp_out}"; then echo "net_dropmonitor.py test failed" err=1 else diff --git a/tools/perf/tests/shell/test_netdev_times_python.sh b/tools/perf/tests/shell/test_netdev_times_python.sh index bb0f8c30207f..393bf446efb2 100755 --- a/tools/perf/tests/shell/test_netdev_times_python.sh +++ b/tools/perf/tests/shell/test_netdev_times_python.sh @@ -93,7 +93,7 @@ if ! perf record -e skb:kfree_skb -a -o "${temp_data}" \ fi # Check that the script executes -if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then +if ! perf script netdev-times -i "${temp_data}" > "${temp_out}"; then echo "netdev-times.py test failed" err=1 else diff --git a/tools/perf/tests/shell/test_powerpc_hcalls_python.sh b/tools/perf/tests/shell/test_powerpc_hcalls_python.sh index 5316c28f243f..19569c6d3613 100755 --- a/tools/perf/tests/shell/test_powerpc_hcalls_python.sh +++ b/tools/perf/tests/shell/test_powerpc_hcalls_python.sh @@ -79,7 +79,7 @@ if [ ! -s "${temp_data}" ]; then fi # Check that the script executes on recorded perf.data -if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then +if ! perf script powerpc-hcalls -i "${temp_data}" > "${temp_out}"; then echo "powerpc-hcalls.py test failed" err=1 else diff --git a/tools/perf/tests/shell/test_rw_by_file_python.sh b/tools/perf/tests/shell/test_rw_by_file_python.sh index 98218bf8a39e..f121597f418f 100755 --- a/tools/perf/tests/shell/test_rw_by_file_python.sh +++ b/tools/perf/tests/shell/test_rw_by_file_python.sh @@ -52,7 +52,7 @@ if [ ! -s "${temp_data}" ]; then fi # Check that the script executes - filtering for "dd" since that's what we ran -if ! "$PYTHON" "$script_path" -i "${temp_data}" "dd" > "${temp_out}"; then +if ! perf script rw-by-file -i "${temp_data}" "dd" > "${temp_out}"; then echo "rw-by-file.py test failed" err=1 else diff --git a/tools/perf/tests/shell/test_rw_by_pid_python.sh b/tools/perf/tests/shell/test_rw_by_pid_python.sh index da8b065d43de..41eaa29097a2 100755 --- a/tools/perf/tests/shell/test_rw_by_pid_python.sh +++ b/tools/perf/tests/shell/test_rw_by_pid_python.sh @@ -58,7 +58,7 @@ if [ ! -s "${temp_data}" ]; then fi # Check that the script executes -if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then +if ! perf script rw-by-pid -i "${temp_data}" > "${temp_out}"; then echo "rw-by-pid.py test failed" err=1 else diff --git a/tools/perf/tests/shell/test_rwtop_python.sh b/tools/perf/tests/shell/test_rwtop_python.sh index 062fca2dad14..05897e384702 100755 --- a/tools/perf/tests/shell/test_rwtop_python.sh +++ b/tools/perf/tests/shell/test_rwtop_python.sh @@ -58,7 +58,7 @@ if [ ! -s "${temp_data}" ]; then fi # Check that the script executes -if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then +if ! perf script rwtop -i "${temp_data}" > "${temp_out}"; then echo "rwtop.py test failed" err=1 else diff --git a/tools/perf/tests/shell/test_sched_migration_python.sh b/tools/perf/tests/shell/test_sched_migration_python.sh index f243e86c6700..75465bcd3791 100755 --- a/tools/perf/tests/shell/test_sched_migration_python.sh +++ b/tools/perf/tests/shell/test_sched_migration_python.sh @@ -58,7 +58,7 @@ if [ ! -s "${temp_data}" ]; then fi # Check that the script executes -if ! "$PYTHON" "$script_path" -v --no-gui -i "${temp_data}" > "${temp_out}"; then +if ! perf script sched-migration -v --no-gui -i "${temp_data}" > "${temp_out}"; then echo "sched-migration.py test failed" err=1 elif [ "$has_sched" -eq 1 ] && ! grep -q "Timeslices:" "${temp_out}"; then diff --git a/tools/perf/tests/shell/test_sctop_python.sh b/tools/perf/tests/shell/test_sctop_python.sh index cd38cdd4794c..007f2584cce6 100755 --- a/tools/perf/tests/shell/test_sctop_python.sh +++ b/tools/perf/tests/shell/test_sctop_python.sh @@ -56,13 +56,13 @@ if [ ! -s "${temp_data}" ]; then fi # Check that the script executes -if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then +if ! perf script sctop -i "${temp_data}" > "${temp_out}"; then echo "sctop.py test failed" err=1 elif ! grep -E -q "[0-9]+$" "${temp_out}"; then echo "Failed to find metric data rows in default run" err=1 -elif ! "$PYTHON" "$script_path" -i "${temp_data}" sleep 1 > "${temp_out}"; then +elif ! perf script sctop -i "${temp_data}" sleep 1 > "${temp_out}"; then echo "sctop.py comm+interval test failed" err=1 else diff --git a/tools/perf/tests/shell/test_stackcollapse_python.sh b/tools/perf/tests/shell/test_stackcollapse_python.sh index a3b6c917e842..ce0f80407eec 100755 --- a/tools/perf/tests/shell/test_stackcollapse_python.sh +++ b/tools/perf/tests/shell/test_stackcollapse_python.sh @@ -47,7 +47,7 @@ if [ ! -s "${temp_data}" ]; then fi # Check that the script executes with default options -if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then +if ! perf script stackcollapse -i "${temp_data}" > "${temp_out}"; then echo "stackcollapse.py test failed" err=1 else @@ -61,12 +61,12 @@ else fi # Test CLI flags (--include-pid, --include-tid, --tidy-java, --kernel) and BrokenPipeError -if ! "$PYTHON" "$script_path" -i "${temp_data}" \ +if ! perf script stackcollapse -i "${temp_data}" \ --include-pid --include-tid --tidy-java --kernel | head -n 1 > "${temp_out}" || \ [ ! -s "${temp_out}" ]; then echo "stackcollapse.py options/pipe test failed" err=1 -elif ! "$PYTHON" "$script_path" -i "${temp_data}" --no-comm > "${temp_out}" || \ +elif ! perf script stackcollapse -i "${temp_data}" --no-comm > "${temp_out}" || \ [ ! -s "${temp_out}" ]; then echo "stackcollapse.py --no-comm test failed" err=1 diff --git a/tools/perf/tests/shell/test_stat_cpi_python.sh b/tools/perf/tests/shell/test_stat_cpi_python.sh index 0960afa4c797..fe7562307634 100755 --- a/tools/perf/tests/shell/test_stat_cpi_python.sh +++ b/tools/perf/tests/shell/test_stat_cpi_python.sh @@ -62,7 +62,7 @@ test_live_mode() { ran=1 # Run live mode for 1 interval in the background, give it a tiny sleep, then interrupt - "$PYTHON" "$script_path" -I 0.1 -p "$workload_pid" > "${temp_out}" & + perf script stat-cpi -I 0.1 -p "$workload_pid" > "${temp_out}" & pid=$! sleep 0.5 kill -INT "$pid" 2>/dev/null || true @@ -96,7 +96,7 @@ test_file_mode() { fi ran=1 - out=$("$PYTHON" "$script_path" -i "${temp_data}") + out=$(perf script stat-cpi -i "${temp_data}") if ! echo "$out" | grep -q "cpi"; then echo "File mode test failed." err=1 diff --git a/tools/perf/tests/shell/test_syscall_counts_by_pid_python.sh b/tools/perf/tests/shell/test_syscall_counts_by_pid_python.sh index 9f2ad27751a2..45bbdc554c8f 100755 --- a/tools/perf/tests/shell/test_syscall_counts_by_pid_python.sh +++ b/tools/perf/tests/shell/test_syscall_counts_by_pid_python.sh @@ -53,7 +53,7 @@ test_file_mode() { -- sleep 0.5 >/dev/null 2>&1 || \ { echo "Skipping test, perf record failed"; exit 2; } - if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then + if ! perf script syscall-counts-by-pid -i "${temp_data}" > "${temp_out}"; then echo "File mode test failed." err=1 elif ! grep -E -q "^ [a-zA-Z0-9_]+ +[0-9]+$" "${temp_out}"; then @@ -64,7 +64,7 @@ test_file_mode() { fi # Test with a comm argument - if ! "$PYTHON" "$script_path" -i "${temp_data}" "sleep" > "${temp_out}"; then + if ! perf script syscall-counts-by-pid -i "${temp_data}" "sleep" > "${temp_out}"; then echo "Comm filter test failed." err=1 elif ! grep -E -q "^ [a-zA-Z0-9_]+ +[0-9]+$" "${temp_out}"; then @@ -76,7 +76,8 @@ test_file_mode() { # Extract sleep PID from "sleep []" header and test with a numeric PID filter argument sleep_pid=$(sed -n 's/^sleep \[\([0-9]\+\)\]$/\1/p' "${temp_out}" | head -n 1) - if [ -z "${sleep_pid}" ] || ! "$PYTHON" "$script_path" -i "${temp_data}" "${sleep_pid}" > "${temp_out}"; then + if [ -z "${sleep_pid}" ] || \ + ! perf script syscall-counts-by-pid -i "${temp_data}" "${sleep_pid}" > "${temp_out}"; then echo "PID filter test failed." err=1 elif ! grep -E -q "^ [a-zA-Z0-9_]+ +[0-9]+$" "${temp_out}"; then diff --git a/tools/perf/tests/shell/test_syscall_counts_python.sh b/tools/perf/tests/shell/test_syscall_counts_python.sh index 0c4b75499209..310e05d399f9 100755 --- a/tools/perf/tests/shell/test_syscall_counts_python.sh +++ b/tools/perf/tests/shell/test_syscall_counts_python.sh @@ -54,7 +54,7 @@ test_file_mode() { exit 2 fi - if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then + if ! perf script syscall-counts -i "${temp_data}" > "${temp_out}"; then echo "File mode test failed." err=1 elif ! grep -E -q "^[a-zA-Z0-9_]+ +[0-9]+$" "${temp_out}"; then @@ -65,7 +65,7 @@ test_file_mode() { fi # Test with a comm argument - if ! "$PYTHON" "$script_path" -i "${temp_data}" "sleep" > "${temp_out}"; then + if ! perf script syscall-counts -i "${temp_data}" "sleep" > "${temp_out}"; then echo "Comm filter test failed." err=1 elif ! grep -E -q "^[a-zA-Z0-9_]+ +[0-9]+$" "${temp_out}"; then diff --git a/tools/perf/tests/shell/test_task_analyzer.sh b/tools/perf/tests/shell/test_task_analyzer.sh index 3a97d58eec74..f99a637a6099 100755 --- a/tools/perf/tests/shell/test_task_analyzer.sh +++ b/tools/perf/tests/shell/test_task_analyzer.sh @@ -11,16 +11,6 @@ csv="$tmpdir/csv" csvsummary="$tmpdir/csvsummary" err=0 -# Set up perfdir and PERF_EXEC_PATH -if [ "x$PERF_EXEC_PATH" = "x" ]; then - perfdir="$(dirname "$0")/../.." - if [ -f "$perfdir/python/task-analyzer.py" ]; then - export PERF_EXEC_PATH="$perfdir" - fi -else - perfdir="$PERF_EXEC_PATH" -fi - # Disable lsan to avoid warnings about python memory leaks. export ASAN_OPTIONS=detect_leaks=0 @@ -81,17 +71,17 @@ prepare_perf_data() { # check standard inkvokation with no arguments test_basic() { out="$tmpdir/perf.out" - $PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" > "$out" - check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata}" + perf script -i "${perfdata}" task-analyzer > "$out" + check_exec_0 "perf script -i ${perfdata} task-analyzer" find_str_or_fail "Comm" "$out" "${FUNCNAME[0]}" } test_ns_rename(){ out="$tmpdir/perf.out" - $PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" \ + perf script -i "${perfdata}" task-analyzer \ --ns \ --rename-comms-by-tids 0:random > "$out" - check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} \ + check_exec_0 "perf script -i ${perfdata} task-analyzer \ --ns \ --rename-comms-by-tids 0:random" find_str_or_fail "Comm" "$out" "${FUNCNAME[0]}" @@ -99,20 +89,20 @@ test_ns_rename(){ test_ms_filtertasks_highlight(){ out="$tmpdir/perf.out" - $PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" \ + perf script -i "${perfdata}" task-analyzer \ --ms --filter-tasks perf --highlight-tasks perf \ > "$out" - check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} \ + check_exec_0 "perf script -i ${perfdata} task-analyzer \ --ms --filter-tasks perf --highlight-tasks perf" find_str_or_fail "Comm" "$out" "${FUNCNAME[0]}" } test_extended_times_timelimit_limittasks() { out="$tmpdir/perf.out" - $PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" --extended-times \ + perf script -i "${perfdata}" task-analyzer --extended-times \ --time-limit :99999 \ --limit-to-tasks perf > "$out" - check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} \ + check_exec_0 "perf script -i ${perfdata} task-analyzer \ --extended-times \ --time-limit :99999 --limit-to-tasks perf" find_str_or_fail "Out-Out" "$out" "${FUNCNAME[0]}" @@ -120,30 +110,30 @@ test_extended_times_timelimit_limittasks() { test_summary() { out="$tmpdir/perf.out" - $PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" --summary > "$out" - check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} --summary" + perf script -i "${perfdata}" task-analyzer --summary > "$out" + check_exec_0 "perf script -i ${perfdata} task-analyzer --summary" find_str_or_fail "Summary" "$out" "${FUNCNAME[0]}" } test_summaryextended() { out="$tmpdir/perf.out" - $PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" --summary-extended > "$out" - check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} --summary-extended" + perf script -i "${perfdata}" task-analyzer --summary-extended > "$out" + check_exec_0 "perf script -i ${perfdata} task-analyzer --summary-extended" find_str_or_fail "Inter Task Times" "$out" "${FUNCNAME[0]}" } test_summaryonly() { out="$tmpdir/perf.out" - $PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" --summary-only > "$out" - check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} --summary-only" + perf script -i "${perfdata}" task-analyzer --summary-only > "$out" + check_exec_0 "perf script -i ${perfdata} task-analyzer --summary-only" find_str_or_fail "Summary" "$out" "${FUNCNAME[0]}" } test_extended_times_summary_ns() { out="$tmpdir/perf.out" - $PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" --extended-times \ + perf script -i "${perfdata}" task-analyzer --extended-times \ --summary --ns > "$out" - check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} \ + check_exec_0 "perf script -i ${perfdata} task-analyzer \ --extended-times \ --summary \ --ns" @@ -152,34 +142,34 @@ test_extended_times_summary_ns() { } test_csv() { - $PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" --csv "${csv}" > /dev/null - check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} --csv ${csv}" + perf script -i "${perfdata}" task-analyzer --csv "${csv}" > /dev/null + check_exec_0 "perf script -i ${perfdata} task-analyzer --csv ${csv}" find_str_or_fail "Comm;" "${csv}" "${FUNCNAME[0]}" } test_csv_extended_times() { - $PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" \ + perf script -i "${perfdata}" task-analyzer \ --csv "${csv}" \ --extended-times > /dev/null - check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} \ + check_exec_0 "perf script -i ${perfdata} task-analyzer \ --csv ${csv} \ --extended-times" find_str_or_fail "Out-Out;" "${csv}" "${FUNCNAME[0]}" } test_csvsummary() { - $PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" \ + perf script -i "${perfdata}" task-analyzer \ --csv-summary "${csvsummary}" > /dev/null - check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} \ + check_exec_0 "perf script -i ${perfdata} task-analyzer \ --csv-summary ${csvsummary}" find_str_or_fail "Comm;" "${csvsummary}" "${FUNCNAME[0]}" } test_csvsummary_extended() { - $PYTHON $perfdir/python/task-analyzer.py -i "${perfdata}" \ + perf script -i "${perfdata}" task-analyzer \ --csv-summary "${csvsummary}" --summary-extended \ >/dev/null - check_exec_0 "$PYTHON $perfdir/python/task-analyzer.py -i ${perfdata} \ + check_exec_0 "perf script -i ${perfdata} task-analyzer \ --csv-summary ${csvsummary} --summary-extended" find_str_or_fail "Out-Out;" "${csvsummary}" "${FUNCNAME[0]}" } diff --git a/tools/perf/tests/shell/test_wakeup_latency_python.sh b/tools/perf/tests/shell/test_wakeup_latency_python.sh index fc39ac117609..cb2571449168 100755 --- a/tools/perf/tests/shell/test_wakeup_latency_python.sh +++ b/tools/perf/tests/shell/test_wakeup_latency_python.sh @@ -57,7 +57,7 @@ if [ ! -s "${temp_data}" ]; then fi # Check that the script executes -if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}"; then +if ! perf script wakeup-latency -i "${temp_data}" > "${temp_out}"; then echo "wakeup-latency.py test failed" err=1 else @@ -71,7 +71,7 @@ fi # Also test zero-wakeups / unhandled events path to verify division-by-zero protection if perf record -e cycles -o "${temp_data}" -- perf test -w noploop >/dev/null 2>&1; then - if ! "$PYTHON" "$script_path" -i "${temp_data}" > "${temp_out}" || \ + if ! perf script wakeup-latency -i "${temp_data}" > "${temp_out}" || \ ! grep -q "avg_wakeup_latency (ns): N/A" "${temp_out}"; then echo "wakeup-latency zero-wakeups guard test failed" err=1 diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c index b8a3383ec02a..d6d09b4a348c 100644 --- a/tools/perf/ui/browsers/scripts.c +++ b/tools/perf/ui/browsers/scripts.c @@ -86,75 +86,6 @@ static int scripts_config(const char *var, const char *value, void *data) return 0; } -/* - * Some scripts specify the required events in their "xxx-record" file, - * this function will check if the events in perf.data match those - * mentioned in the "xxx-record". - * - * Fixme: All existing "xxx-record" are all in good formats "-e event ", - * which is covered well now. And new parsing code should be added to - * cover the future complex formats like event groups etc. - */ -static int check_ev_match(int dir_fd, const char *scriptname, struct perf_session *session) -{ - char line[BUFSIZ]; - FILE *fp; - - { - char filename[NAME_MAX + 5]; - int fd; - - scnprintf(filename, sizeof(filename), "bin/%s-record", scriptname); - fd = openat(dir_fd, filename, O_RDONLY); - if (fd == -1) - return -1; - fp = fdopen(fd, "r"); - if (!fp) - return -1; - } - - while (fgets(line, sizeof(line), fp)) { - char *p = skip_spaces(line); - - if (*p == '#') - continue; - - while (strlen(p)) { - int match, len; - struct evsel *pos; - char evname[128]; - - p = strstr(p, "-e"); - if (!p) - break; - - p += 2; - p = skip_spaces(p); - len = strcspn(p, " \t"); - if (!len) - break; - - snprintf(evname, sizeof(evname), "%.*s", (int)len, p); - - match = 0; - evlist__for_each_entry(session->evlist, pos) { - if (evsel__name_is(pos, evname)) { - match = 1; - break; - } - } - - if (!match) { - fclose(fp); - return -1; - } - } - } - - fclose(fp); - return 0; -} - /* * Return -1 if none is found, otherwise the actual scripts number. * @@ -162,95 +93,18 @@ static int check_ev_match(int dir_fd, const char *scriptname, struct perf_sessio * will list all statically runnable scripts, select one, execute it and * show the output in a perf browser. */ -static int find_scripts(char **scripts_array, char **scripts_path_array, int num, - int pathlen) +static int find_scripts(char **scripts_array __maybe_unused, + char **scripts_path_array __maybe_unused, int num __maybe_unused, + int pathlen __maybe_unused) { - int namelen; - struct dirent *script_dirent, *lang_dirent; - int scripts_dir_fd, lang_dir_fd; - DIR *scripts_dir, *lang_dir; - struct perf_session *session; - struct perf_data data = { - .path = input_name, - .mode = PERF_DATA_MODE_READ, - }; - char *temp; int i = 0; - const char *exec_path = get_argv_exec_path(); - - session = perf_session__new(&data, NULL); - if (IS_ERR(session)) - return PTR_ERR(session); - - { - char scripts_path[PATH_MAX]; - - snprintf(scripts_path, sizeof(scripts_path), "%s/scripts", exec_path); - scripts_dir_fd = open(scripts_path, O_DIRECTORY); - } - if (scripts_dir_fd != -1) { - scripts_dir = fdopendir(scripts_dir_fd); - if (scripts_dir) { - while ((lang_dirent = readdir(scripts_dir)) != NULL) { - if (lang_dirent->d_type != DT_DIR && - (lang_dirent->d_type == DT_UNKNOWN && - !is_directory_at(scripts_dir_fd, lang_dirent->d_name))) - continue; - if (!strcmp(lang_dirent->d_name, ".") || - !strcmp(lang_dirent->d_name, "..")) - continue; - - if (strstr(lang_dirent->d_name, "python")) - continue; - - lang_dir_fd = openat(scripts_dir_fd, lang_dirent->d_name, - O_DIRECTORY); - if (lang_dir_fd == -1) - continue; - lang_dir = fdopendir(lang_dir_fd); - if (!lang_dir) { - close(lang_dir_fd); - continue; - } - while ((script_dirent = readdir(lang_dir)) != NULL) { - if (script_dirent->d_type == DT_DIR) - continue; - if (script_dirent->d_type == DT_UNKNOWN && - is_directory_at(lang_dir_fd, script_dirent->d_name)) - continue; - /* Skip those real time scripts: xxxtop.p[yl] */ - if (strstr(script_dirent->d_name, "top.")) - continue; - if (i >= num) - break; - scnprintf(scripts_path_array[i], pathlen, - "%s/scripts/%s/%s", exec_path, - lang_dirent->d_name, - script_dirent->d_name); - temp = strrchr(script_dirent->d_name, '.'); - namelen = temp ? (int)(temp - script_dirent->d_name) - : (int)strlen(script_dirent->d_name); - - if (namelen >= SCRIPT_NAMELEN) - namelen = SCRIPT_NAMELEN - 1; - snprintf(scripts_array[i], namelen + 1, "%s", - script_dirent->d_name); - - if (check_ev_match(lang_dir_fd, scripts_array[i], session)) - continue; - - i++; - } - closedir(lang_dir); - } - closedir(scripts_dir); - } else { - close(scripts_dir_fd); - } - } #ifdef HAVE_PYTHON_MODULE_SUPPORT { + int namelen; + struct dirent *script_dirent; + char *temp; + const char *exec_path = get_argv_exec_path(); char py_scripts_path[PATH_MAX]; int py_scripts_dir_fd; DIR *py_scripts_dir; @@ -299,7 +153,6 @@ static int find_scripts(char **scripts_array, char **scripts_path_array, int num } } #endif - perf_session__delete(session); return i; } diff --git a/tools/perf/util/Build b/tools/perf/util/Build index afcf98dc5006..512f2ca0cd1a 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -95,7 +95,6 @@ perf-util-y += tool_pmu.o perf-util-y += tp_pmu.o perf-util-y += svghelper.o perf-util-y += trace-event-info.o -perf-util-y += trace-event-scripting.o perf-util-$(CONFIG_LIBTRACEEVENT) += trace-event.o perf-util-$(CONFIG_LIBTRACEEVENT) += trace-event-parse.o perf-util-$(CONFIG_LIBTRACEEVENT) += trace-event-read.o @@ -236,8 +235,6 @@ endif perf-util-y += data-convert-json.o -perf-util-y += scripting-engines/ - perf-util-$(CONFIG_ZLIB) += zlib.o perf-util-$(CONFIG_LZMA) += lzma.o perf-util-$(CONFIG_ZSTD) += zstd.o diff --git a/tools/perf/util/scripting-engines/Build b/tools/perf/util/scripting-engines/Build deleted file mode 100644 index 3f1dc10526f8..000000000000 --- a/tools/perf/util/scripting-engines/Build +++ /dev/null @@ -1,5 +0,0 @@ -ifeq ($(CONFIG_LIBTRACEEVENT),y) - perf-util-$(CONFIG_LIBPERL) += trace-event-perl.o -endif - -CFLAGS_trace-event-perl.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-nested-externs -Wno-undef -Wno-switch-default -Wno-bad-function-cast -Wno-declaration-after-statement -Wno-switch-enum -Wno-thread-safety-analysis diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c deleted file mode 100644 index 410dc4cd0600..000000000000 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ /dev/null @@ -1,770 +0,0 @@ -/* - * trace-event-perl. Feed perf script events to an embedded Perl interpreter. - * - * Copyright (C) 2009 Tom Zanussi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -/* perl needs the following define, right after including stdbool.h */ -#define HAS_BOOL -#include -#include - -#include "../callchain.h" -#include "../dso.h" -#include "../machine.h" -#include "../map.h" -#include "../symbol.h" -#include "../thread.h" -#include "../event.h" -#include "../trace-event.h" -#include "../evsel.h" -#include "../debug.h" - -void boot_Perf__Trace__Context(pTHX_ CV *cv); -void boot_DynaLoader(pTHX_ CV *cv); -typedef PerlInterpreter * INTERP; - -void xs_init(pTHX); - -void xs_init(pTHX) -{ - const char *file = __FILE__; - dXSUB_SYS; - - newXS("Perf::Trace::Context::bootstrap", boot_Perf__Trace__Context, - file); - newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file); -} - -INTERP my_perl; - -#define TRACE_EVENT_TYPE_MAX \ - ((1 << (sizeof(unsigned short) * 8)) - 1) - -extern struct scripting_context *scripting_context; - -static char *cur_field_name; -static int zero_flag_atom; - -static void define_symbolic_value(const char *ev_name, - const char *field_name, - const char *field_value, - const char *field_str) -{ - unsigned long long value; - dSP; - - value = eval_flag(field_value); - - ENTER; - SAVETMPS; - PUSHMARK(SP); - - XPUSHs(sv_2mortal(newSVpv(ev_name, 0))); - XPUSHs(sv_2mortal(newSVpv(field_name, 0))); - XPUSHs(sv_2mortal(newSVuv(value))); - XPUSHs(sv_2mortal(newSVpv(field_str, 0))); - - PUTBACK; - if (get_cv("main::define_symbolic_value", 0)) - call_pv("main::define_symbolic_value", G_SCALAR); - SPAGAIN; - PUTBACK; - FREETMPS; - LEAVE; -} - -static void define_symbolic_values(struct tep_print_flag_sym *field, - const char *ev_name, - const char *field_name) -{ - define_symbolic_value(ev_name, field_name, field->value, field->str); - if (field->next) - define_symbolic_values(field->next, ev_name, field_name); -} - -static void define_symbolic_field(const char *ev_name, - const char *field_name) -{ - dSP; - - ENTER; - SAVETMPS; - PUSHMARK(SP); - - XPUSHs(sv_2mortal(newSVpv(ev_name, 0))); - XPUSHs(sv_2mortal(newSVpv(field_name, 0))); - - PUTBACK; - if (get_cv("main::define_symbolic_field", 0)) - call_pv("main::define_symbolic_field", G_SCALAR); - SPAGAIN; - PUTBACK; - FREETMPS; - LEAVE; -} - -static void define_flag_value(const char *ev_name, - const char *field_name, - const char *field_value, - const char *field_str) -{ - unsigned long long value; - dSP; - - value = eval_flag(field_value); - - ENTER; - SAVETMPS; - PUSHMARK(SP); - - XPUSHs(sv_2mortal(newSVpv(ev_name, 0))); - XPUSHs(sv_2mortal(newSVpv(field_name, 0))); - XPUSHs(sv_2mortal(newSVuv(value))); - XPUSHs(sv_2mortal(newSVpv(field_str, 0))); - - PUTBACK; - if (get_cv("main::define_flag_value", 0)) - call_pv("main::define_flag_value", G_SCALAR); - SPAGAIN; - PUTBACK; - FREETMPS; - LEAVE; -} - -static void define_flag_values(struct tep_print_flag_sym *field, - const char *ev_name, - const char *field_name) -{ - define_flag_value(ev_name, field_name, field->value, field->str); - if (field->next) - define_flag_values(field->next, ev_name, field_name); -} - -static void define_flag_field(const char *ev_name, - const char *field_name, - const char *delim) -{ - dSP; - - ENTER; - SAVETMPS; - PUSHMARK(SP); - - XPUSHs(sv_2mortal(newSVpv(ev_name, 0))); - XPUSHs(sv_2mortal(newSVpv(field_name, 0))); - XPUSHs(sv_2mortal(newSVpv(delim, 0))); - - PUTBACK; - if (get_cv("main::define_flag_field", 0)) - call_pv("main::define_flag_field", G_SCALAR); - SPAGAIN; - PUTBACK; - FREETMPS; - LEAVE; -} - -static void define_event_symbols(struct tep_event *event, - const char *ev_name, - struct tep_print_arg *args) -{ - if (args == NULL) - return; - - switch (args->type) { - case TEP_PRINT_NULL: - break; - case TEP_PRINT_ATOM: - define_flag_value(ev_name, cur_field_name, "0", - args->atom.atom); - zero_flag_atom = 0; - break; - case TEP_PRINT_FIELD: - free(cur_field_name); - cur_field_name = strdup(args->field.name); - break; - case TEP_PRINT_FLAGS: - define_event_symbols(event, ev_name, args->flags.field); - define_flag_field(ev_name, cur_field_name, args->flags.delim); - define_flag_values(args->flags.flags, ev_name, cur_field_name); - break; - case TEP_PRINT_SYMBOL: - define_event_symbols(event, ev_name, args->symbol.field); - define_symbolic_field(ev_name, cur_field_name); - define_symbolic_values(args->symbol.symbols, ev_name, - cur_field_name); - break; - case TEP_PRINT_HEX: - case TEP_PRINT_HEX_STR: - define_event_symbols(event, ev_name, args->hex.field); - define_event_symbols(event, ev_name, args->hex.size); - break; - case TEP_PRINT_INT_ARRAY: - define_event_symbols(event, ev_name, args->int_array.field); - define_event_symbols(event, ev_name, args->int_array.count); - define_event_symbols(event, ev_name, args->int_array.el_size); - break; - case TEP_PRINT_BSTRING: - case TEP_PRINT_DYNAMIC_ARRAY: - case TEP_PRINT_DYNAMIC_ARRAY_LEN: - case TEP_PRINT_STRING: - case TEP_PRINT_BITMASK: - break; - case TEP_PRINT_TYPE: - define_event_symbols(event, ev_name, args->typecast.item); - break; - case TEP_PRINT_OP: - if (strcmp(args->op.op, ":") == 0) - zero_flag_atom = 1; - define_event_symbols(event, ev_name, args->op.left); - define_event_symbols(event, ev_name, args->op.right); - break; - case TEP_PRINT_FUNC: - default: - pr_err("Unsupported print arg type\n"); - /* we should warn... */ - return; - } - - if (args->next) - define_event_symbols(event, ev_name, args->next); -} - -static SV *perl_process_callchain(struct perf_sample *sample, - struct addr_location *al) -{ - struct callchain_cursor *cursor; - AV *list; - - list = newAV(); - if (!list) - goto exit; - - if (!symbol_conf.use_callchain || !sample->callchain) - goto exit; - - cursor = get_tls_callchain_cursor(); - - if (thread__resolve_callchain(al->thread, cursor, - sample, NULL, NULL, scripting_max_stack) != 0) { - pr_err("Failed to resolve callchain. Skipping\n"); - goto exit; - } - callchain_cursor_commit(cursor); - - - while (1) { - HV *elem; - struct callchain_cursor_node *node; - node = callchain_cursor_current(cursor); - if (!node) - break; - - elem = newHV(); - if (!elem) - goto exit; - - if (!hv_stores(elem, "ip", newSVuv(node->ip))) { - hv_undef(elem); - goto exit; - } - - if (node->ms.sym) { - HV *sym = newHV(); - if (!sym) { - hv_undef(elem); - goto exit; - } - if (!hv_stores(sym, "start", newSVuv(node->ms.sym->start)) || - !hv_stores(sym, "end", newSVuv(node->ms.sym->end)) || - !hv_stores(sym, "binding", newSVuv(symbol__binding(node->ms.sym))) || - !hv_stores(sym, "name", newSVpvn(node->ms.sym->name, - node->ms.sym->namelen)) || - !hv_stores(elem, "sym", newRV_noinc((SV*)sym))) { - hv_undef(sym); - hv_undef(elem); - goto exit; - } - } - - if (node->ms.map) { - struct map *map = node->ms.map; - struct dso *dso = map ? map__dso(map) : NULL; - const char *dsoname = "[unknown]"; - - if (dso) { - if (symbol_conf.show_kernel_path && dso__long_name(dso)) - dsoname = dso__long_name(dso); - else - dsoname = dso__name(dso); - } - if (!hv_stores(elem, "dso", newSVpv(dsoname,0))) { - hv_undef(elem); - goto exit; - } - } - - callchain_cursor_advance(cursor); - av_push(list, newRV_noinc((SV*)elem)); - } - -exit: - return newRV_noinc((SV*)list); -} - -static void perl_process_tracepoint(struct perf_sample *sample, - struct addr_location *al) -{ - struct thread *thread = al->thread; - struct tep_event *event; - struct tep_format_field *field; - static char handler[256]; - unsigned long long val; - unsigned long s, ns; - int pid; - int cpu = sample->cpu; - void *data = sample->raw_data; - unsigned long long nsecs = sample->time; - const char *comm = thread__comm_str(thread); - DECLARE_BITMAP(events_defined, TRACE_EVENT_TYPE_MAX); - struct evsel *evsel = sample->evsel; - - bitmap_zero(events_defined, TRACE_EVENT_TYPE_MAX); - dSP; - - if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) - return; - - event = evsel__tp_format(evsel); - if (!event) { - pr_debug("ug! no event found for type %" PRIu64, (u64)evsel->core.attr.config); - return; - } - - pid = raw_field_value(event, "common_pid", data); - - sprintf(handler, "%s::%s", event->system, event->name); - - if (!__test_and_set_bit(event->id, events_defined)) - define_event_symbols(event, handler, event->print_fmt.args); - - s = nsecs / NSEC_PER_SEC; - ns = nsecs - s * NSEC_PER_SEC; - - ENTER; - SAVETMPS; - PUSHMARK(SP); - - XPUSHs(sv_2mortal(newSVpv(handler, 0))); - XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context)))); - XPUSHs(sv_2mortal(newSVuv(cpu))); - XPUSHs(sv_2mortal(newSVuv(s))); - XPUSHs(sv_2mortal(newSVuv(ns))); - XPUSHs(sv_2mortal(newSViv(pid))); - XPUSHs(sv_2mortal(newSVpv(comm, 0))); - XPUSHs(sv_2mortal(perl_process_callchain(sample, al))); - - /* common fields other than pid can be accessed via xsub fns */ - - for (field = event->format.fields; field; field = field->next) { - if (field->flags & TEP_FIELD_IS_STRING) { - int offset; - if (field->flags & TEP_FIELD_IS_DYNAMIC) { - offset = *(int *)(data + field->offset); - offset &= 0xffff; - if (tep_field_is_relative(field->flags)) - offset += field->offset + field->size; - } else - offset = field->offset; - XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0))); - } else { /* FIELD_IS_NUMERIC */ - val = read_size(event, data + field->offset, - field->size); - if (field->flags & TEP_FIELD_IS_SIGNED) { - XPUSHs(sv_2mortal(newSViv(val))); - } else { - XPUSHs(sv_2mortal(newSVuv(val))); - } - } - } - - PUTBACK; - - if (get_cv(handler, 0)) - call_pv(handler, G_SCALAR); - else if (get_cv("main::trace_unhandled", 0)) { - XPUSHs(sv_2mortal(newSVpv(handler, 0))); - XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context)))); - XPUSHs(sv_2mortal(newSVuv(cpu))); - XPUSHs(sv_2mortal(newSVuv(nsecs))); - XPUSHs(sv_2mortal(newSViv(pid))); - XPUSHs(sv_2mortal(newSVpv(comm, 0))); - XPUSHs(sv_2mortal(perl_process_callchain(sample, al))); - call_pv("main::trace_unhandled", G_SCALAR); - } - SPAGAIN; - PUTBACK; - FREETMPS; - LEAVE; -} - -static void perl_process_event_generic(union perf_event *event, struct perf_sample *sample) -{ - dSP; - - if (!get_cv("process_event", 0)) - return; - - ENTER; - SAVETMPS; - PUSHMARK(SP); - XPUSHs(sv_2mortal(newSVpvn((const char *)event, event->header.size))); - XPUSHs(sv_2mortal(newSVpvn((const char *)&sample->evsel->core.attr, - sizeof(sample->evsel->core.attr)))); - XPUSHs(sv_2mortal(newSVpvn((const char *)sample, sizeof(*sample)))); - XPUSHs(sv_2mortal(newSVpvn((const char *)sample->raw_data, sample->raw_size))); - PUTBACK; - call_pv("process_event", G_SCALAR); - SPAGAIN; - PUTBACK; - FREETMPS; - LEAVE; -} - -static void perl_process_event(union perf_event *event, - struct perf_sample *sample, - struct addr_location *al, - struct addr_location *addr_al) -{ - scripting_context__update(scripting_context, event, sample, al, addr_al); - perl_process_tracepoint(sample, al); - perl_process_event_generic(event, sample); -} - -static void run_start_sub(void) -{ - dSP; /* access to Perl stack */ - PUSHMARK(SP); - - if (get_cv("main::trace_begin", 0)) - call_pv("main::trace_begin", G_DISCARD | G_NOARGS); -} - -/* - * Start trace script - */ -static int perl_start_script(const char *script, int argc, const char **argv, - struct perf_session *session) -{ - const char **command_line; - int i, err = 0; - - scripting_context->session = session; - - command_line = malloc((argc + 2) * sizeof(const char *)); - if (!command_line) - return -ENOMEM; - - command_line[0] = ""; - command_line[1] = script; - for (i = 2; i < argc + 2; i++) - command_line[i] = argv[i - 2]; - - my_perl = perl_alloc(); - perl_construct(my_perl); - - if (perl_parse(my_perl, xs_init, argc + 2, (char **)command_line, - (char **)NULL)) { - err = -1; - goto error; - } - - if (perl_run(my_perl)) { - err = -1; - goto error; - } - - if (SvTRUE(ERRSV)) { - err = -1; - goto error; - } - - run_start_sub(); - - free(command_line); - return 0; -error: - perl_free(my_perl); - free(command_line); - - return err; -} - -static int perl_flush_script(void) -{ - return 0; -} - -/* - * Stop trace script - */ -static int perl_stop_script(void) -{ - dSP; /* access to Perl stack */ - PUSHMARK(SP); - - if (get_cv("main::trace_end", 0)) - call_pv("main::trace_end", G_DISCARD | G_NOARGS); - - perl_destruct(my_perl); - perl_free(my_perl); - - return 0; -} - -static int perl_generate_script(struct tep_handle *pevent, const char *outfile) -{ - int i, not_first, count, nr_events; - struct tep_event **all_events; - struct tep_event *event = NULL; - struct tep_format_field *f; - char fname[PATH_MAX]; - FILE *ofp; - - sprintf(fname, "%s.pl", outfile); - ofp = fopen(fname, "w"); - if (ofp == NULL) { - fprintf(stderr, "couldn't open %s\n", fname); - return -1; - } - - fprintf(ofp, "# perf script event handlers, " - "generated by perf script -g perl\n"); - - fprintf(ofp, "# Licensed under the terms of the GNU GPL" - " License version 2\n\n"); - - fprintf(ofp, "# The common_* event handler fields are the most useful " - "fields common to\n"); - - fprintf(ofp, "# all events. They don't necessarily correspond to " - "the 'common_*' fields\n"); - - fprintf(ofp, "# in the format files. Those fields not available as " - "handler params can\n"); - - fprintf(ofp, "# be retrieved using Perl functions of the form " - "common_*($context).\n"); - - fprintf(ofp, "# See Context.pm for the list of available " - "functions.\n\n"); - - fprintf(ofp, "use lib \"$ENV{'PERF_EXEC_PATH'}/scripts/perl/" - "Perf-Trace-Util/lib\";\n"); - - fprintf(ofp, "use lib \"./Perf-Trace-Util/lib\";\n"); - fprintf(ofp, "use Perf::Trace::Core;\n"); - fprintf(ofp, "use Perf::Trace::Context;\n"); - fprintf(ofp, "use Perf::Trace::Util;\n\n"); - - fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n"); - fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n"); - - - fprintf(ofp, "\n\ -sub print_backtrace\n\ -{\n\ - my $callchain = shift;\n\ - for my $node (@$callchain)\n\ - {\n\ - if(exists $node->{sym})\n\ - {\n\ - printf( \"\\t[\\%%x] \\%%s\\n\", $node->{ip}, $node->{sym}{name});\n\ - }\n\ - else\n\ - {\n\ - printf( \"\\t[\\%%x]\\n\", $node{ip});\n\ - }\n\ - }\n\ -}\n\n\ -"); - - nr_events = tep_get_events_count(pevent); - all_events = tep_list_events(pevent, TEP_EVENT_SORT_ID); - - for (i = 0; all_events && i < nr_events; i++) { - event = all_events[i]; - fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name); - fprintf(ofp, "\tmy ("); - - fprintf(ofp, "$event_name, "); - fprintf(ofp, "$context, "); - fprintf(ofp, "$common_cpu, "); - fprintf(ofp, "$common_secs, "); - fprintf(ofp, "$common_nsecs,\n"); - fprintf(ofp, "\t $common_pid, "); - fprintf(ofp, "$common_comm, "); - fprintf(ofp, "$common_callchain,\n\t "); - - not_first = 0; - count = 0; - - for (f = event->format.fields; f; f = f->next) { - if (not_first++) - fprintf(ofp, ", "); - if (++count % 5 == 0) - fprintf(ofp, "\n\t "); - - fprintf(ofp, "$%s", f->name); - } - fprintf(ofp, ") = @_;\n\n"); - - fprintf(ofp, "\tprint_header($event_name, $common_cpu, " - "$common_secs, $common_nsecs,\n\t " - "$common_pid, $common_comm, $common_callchain);\n\n"); - - fprintf(ofp, "\tprintf(\""); - - not_first = 0; - count = 0; - - for (f = event->format.fields; f; f = f->next) { - if (not_first++) - fprintf(ofp, ", "); - if (count && count % 4 == 0) { - fprintf(ofp, "\".\n\t \""); - } - count++; - - fprintf(ofp, "%s=", f->name); - if (f->flags & TEP_FIELD_IS_STRING || - f->flags & TEP_FIELD_IS_FLAG || - f->flags & TEP_FIELD_IS_SYMBOLIC) - fprintf(ofp, "%%s"); - else if (f->flags & TEP_FIELD_IS_SIGNED) - fprintf(ofp, "%%d"); - else - fprintf(ofp, "%%u"); - } - - fprintf(ofp, "\\n\",\n\t "); - - not_first = 0; - count = 0; - - for (f = event->format.fields; f; f = f->next) { - if (not_first++) - fprintf(ofp, ", "); - - if (++count % 5 == 0) - fprintf(ofp, "\n\t "); - - if (f->flags & TEP_FIELD_IS_FLAG) { - if ((count - 1) % 5 != 0) { - fprintf(ofp, "\n\t "); - count = 4; - } - fprintf(ofp, "flag_str(\""); - fprintf(ofp, "%s::%s\", ", event->system, - event->name); - fprintf(ofp, "\"%s\", $%s)", f->name, - f->name); - } else if (f->flags & TEP_FIELD_IS_SYMBOLIC) { - if ((count - 1) % 5 != 0) { - fprintf(ofp, "\n\t "); - count = 4; - } - fprintf(ofp, "symbol_str(\""); - fprintf(ofp, "%s::%s\", ", event->system, - event->name); - fprintf(ofp, "\"%s\", $%s)", f->name, - f->name); - } else - fprintf(ofp, "$%s", f->name); - } - - fprintf(ofp, ");\n\n"); - - fprintf(ofp, "\tprint_backtrace($common_callchain);\n"); - - fprintf(ofp, "}\n\n"); - } - - fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, " - "$common_cpu, $common_secs, $common_nsecs,\n\t " - "$common_pid, $common_comm, $common_callchain) = @_;\n\n"); - - fprintf(ofp, "\tprint_header($event_name, $common_cpu, " - "$common_secs, $common_nsecs,\n\t $common_pid, " - "$common_comm, $common_callchain);\n"); - fprintf(ofp, "\tprint_backtrace($common_callchain);\n"); - fprintf(ofp, "}\n\n"); - - fprintf(ofp, "sub print_header\n{\n" - "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n" - "\tprintf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \",\n\t " - "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}\n"); - - fprintf(ofp, - "\n# Packed byte string args of process_event():\n" - "#\n" - "# $event:\tunion perf_event\tutil/event.h\n" - "# $attr:\tstruct perf_event_attr\tlinux/perf_event.h\n" - "# $sample:\tstruct perf_sample\tutil/event.h\n" - "# $raw_data:\tperf_sample->raw_data\tutil/event.h\n" - "\n" - "sub process_event\n" - "{\n" - "\tmy ($event, $attr, $sample, $raw_data) = @_;\n" - "\n" - "\tmy @event\t= unpack(\"LSS\", $event);\n" - "\tmy @attr\t= unpack(\"LLQQQQQLLQQ\", $attr);\n" - "\tmy @sample\t= unpack(\"QLLQQQQQLL\", $sample);\n" - "\tmy @raw_data\t= unpack(\"C*\", $raw_data);\n" - "\n" - "\tuse Data::Dumper;\n" - "\tprint Dumper \\@event, \\@attr, \\@sample, \\@raw_data;\n" - "}\n"); - - fclose(ofp); - - fprintf(stderr, "generated Perl script: %s\n", fname); - - return 0; -} - -struct scripting_ops perl_scripting_ops = { - .name = "Perl", - .dirname = "perl", - .start_script = perl_start_script, - .flush_script = perl_flush_script, - .stop_script = perl_stop_script, - .process_event = perl_process_event, - .generate_script = perl_generate_script, -}; diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 9c015fc2bcfb..374cf82fd86e 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -14,71 +14,6 @@ #include #include -static int get_common_field(struct scripting_context *context, - int *offset, int *size, const char *type) -{ - struct tep_handle *pevent = context->pevent; - struct tep_event *event; - struct tep_format_field *field; - - if (!*size) { - - event = tep_get_first_event(pevent); - if (!event) - return 0; - - field = tep_find_common_field(event, type); - if (!field) - return 0; - *offset = field->offset; - *size = field->size; - } - - return tep_read_number(pevent, context->event_data + *offset, *size); -} - -int common_lock_depth(struct scripting_context *context) -{ - static int offset; - static int size; - int ret; - - ret = get_common_field(context, &size, &offset, - "common_lock_depth"); - if (ret < 0) - return -1; - - return ret; -} - -int common_flags(struct scripting_context *context) -{ - static int offset; - static int size; - int ret; - - ret = get_common_field(context, &size, &offset, - "common_flags"); - if (ret < 0) - return -1; - - return ret; -} - -int common_pc(struct scripting_context *context) -{ - static int offset; - static int size; - int ret; - - ret = get_common_field(context, &size, &offset, - "common_preempt_count"); - if (ret < 0) - return -1; - - return ret; -} - unsigned long long raw_field_value(struct tep_event *event, const char *name, void *data) { diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c deleted file mode 100644 index c78b317978dd..000000000000 --- a/tools/perf/util/trace-event-scripting.c +++ /dev/null @@ -1,398 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * trace-event-scripting. Scripting engine common and initialization code. - * - * Copyright (C) 2009-2010 Tom Zanussi - */ - -#include -#include -#include -#include -#ifdef HAVE_LIBTRACEEVENT -#include -#endif - -#include "debug.h" -#include "event.h" -#include "trace-event.h" -#include "evsel.h" -#include -#include -#include "util/sample.h" - -unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH; - -struct scripting_context *scripting_context; - -struct script_spec { - struct list_head node; - struct scripting_ops *ops; - char spec[]; -}; - -static LIST_HEAD(script_specs); - -static struct script_spec *script_spec__new(const char *spec, - struct scripting_ops *ops) -{ - struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1); - - if (s != NULL) { - strcpy(s->spec, spec); - s->ops = ops; - } - - return s; -} - -static void script_spec__add(struct script_spec *s) -{ - list_add_tail(&s->node, &script_specs); -} - -static struct script_spec *script_spec__find(const char *spec) -{ - struct script_spec *s; - - list_for_each_entry(s, &script_specs, node) - if (strcasecmp(s->spec, spec) == 0) - return s; - return NULL; -} - -static int script_spec_register(const char *spec, struct scripting_ops *ops) -{ - struct script_spec *s; - - s = script_spec__find(spec); - if (s) - return -1; - - s = script_spec__new(spec, ops); - if (!s) - return -1; - - script_spec__add(s); - return 0; -} - -struct scripting_ops *script_spec__lookup(const char *spec) -{ - struct script_spec *s = script_spec__find(spec); - - if (!s) - return NULL; - - return s->ops; -} - -int script_spec__for_each(int (*cb)(struct scripting_ops *ops, const char *spec)) -{ - struct script_spec *s; - int ret = 0; - - list_for_each_entry(s, &script_specs, node) { - ret = cb(s->ops, s->spec); - if (ret) - break; - } - return ret; -} - -void scripting_context__update(struct scripting_context *c, - union perf_event *event, - struct perf_sample *sample, - struct addr_location *al, - struct addr_location *addr_al) -{ -#ifdef HAVE_LIBTRACEEVENT - const struct tep_event *tp_format = evsel__tp_format(sample->evsel); - - c->pevent = tp_format ? tp_format->tep : NULL; -#else - c->pevent = NULL; -#endif - c->event_data = sample->raw_data; - c->event = event; - c->sample = sample; - c->al = al; - c->addr_al = addr_al; -} - -static int flush_script_unsupported(void) -{ - return 0; -} - -static int stop_script_unsupported(void) -{ - return 0; -} - -static void process_event_unsupported(union perf_event *event __maybe_unused, - struct perf_sample *sample __maybe_unused, - struct addr_location *al __maybe_unused, - struct addr_location *addr_al __maybe_unused) -{ -} - -static void print_python_unsupported_msg(void) -{ - fprintf(stderr, "Python scripting not supported." - " Install libpython and rebuild perf to enable it.\n" - "For example:\n # apt-get install python-dev (ubuntu)" - "\n # yum install python-devel (Fedora)" - "\n etc.\n"); -} - -static int python_start_script_unsupported(const char *script __maybe_unused, - int argc __maybe_unused, - const char **argv __maybe_unused, - struct perf_session *session __maybe_unused) -{ - print_python_unsupported_msg(); - - return -1; -} - -static int python_generate_script_unsupported(struct tep_handle *pevent - __maybe_unused, - const char *outfile - __maybe_unused) -{ - print_python_unsupported_msg(); - - return -1; -} - -struct scripting_ops python_scripting_unsupported_ops = { - .name = "Python", - .dirname = "python", - .start_script = python_start_script_unsupported, - .flush_script = flush_script_unsupported, - .stop_script = stop_script_unsupported, - .process_event = process_event_unsupported, - .generate_script = python_generate_script_unsupported, -}; - -static void register_python_scripting(struct scripting_ops *scripting_ops) -{ - if (scripting_context == NULL) - scripting_context = malloc(sizeof(*scripting_context)); - - if (scripting_context == NULL || - script_spec_register("Python", scripting_ops) || - script_spec_register("py", scripting_ops)) { - pr_err("Error registering Python script extension: disabling it\n"); - zfree(&scripting_context); - } -} - -void setup_python_scripting(void) -{ - register_python_scripting(&python_scripting_unsupported_ops); -} - -#ifdef HAVE_LIBTRACEEVENT -static void print_perl_unsupported_msg(void) -{ - fprintf(stderr, "Perl scripting not supported." - " Install libperl and rebuild perf to enable it.\n" - "For example:\n # apt-get install libperl-dev (ubuntu)" - "\n # yum install 'perl(ExtUtils::Embed)' (Fedora)" - "\n etc.\n"); -} - -static int perl_start_script_unsupported(const char *script __maybe_unused, - int argc __maybe_unused, - const char **argv __maybe_unused, - struct perf_session *session __maybe_unused) -{ - print_perl_unsupported_msg(); - - return -1; -} - -static int perl_generate_script_unsupported(struct tep_handle *pevent - __maybe_unused, - const char *outfile __maybe_unused) -{ - print_perl_unsupported_msg(); - - return -1; -} - -struct scripting_ops perl_scripting_unsupported_ops = { - .name = "Perl", - .dirname = "perl", - .start_script = perl_start_script_unsupported, - .flush_script = flush_script_unsupported, - .stop_script = stop_script_unsupported, - .process_event = process_event_unsupported, - .generate_script = perl_generate_script_unsupported, -}; - -static void register_perl_scripting(struct scripting_ops *scripting_ops) -{ - if (scripting_context == NULL) - scripting_context = malloc(sizeof(*scripting_context)); - - if (scripting_context == NULL || - script_spec_register("Perl", scripting_ops) || - script_spec_register("pl", scripting_ops)) { - pr_err("Error registering Perl script extension: disabling it\n"); - zfree(&scripting_context); - } -} - -#ifndef HAVE_LIBPERL_SUPPORT -void setup_perl_scripting(void) -{ - register_perl_scripting(&perl_scripting_unsupported_ops); -} -#else -extern struct scripting_ops perl_scripting_ops; - -void setup_perl_scripting(void) -{ - register_perl_scripting(&perl_scripting_ops); -} -#endif -#endif - -static const struct { - u32 flags; - const char *name; -} sample_flags[] = { - {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"}, - {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"}, - {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "jcc"}, - {PERF_IP_FLAG_BRANCH, "jmp"}, - {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT, "int"}, - {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT, "iret"}, - {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET, "syscall"}, - {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET, "sysret"}, - {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "async"}, - {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC | PERF_IP_FLAG_INTERRUPT, - "hw int"}, - {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "tx abrt"}, - {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "tr strt"}, - {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "tr end"}, - {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMENTRY, "vmentry"}, - {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMEXIT, "vmexit"}, - {0, NULL} -}; - -static const struct { - u32 flags; - const char *name; -} branch_events[] = { - {PERF_IP_FLAG_BRANCH_MISS, "miss"}, - {PERF_IP_FLAG_NOT_TAKEN, "not_taken"}, - {0, NULL} -}; - -static int sample_flags_to_name(u32 flags, char *str, size_t size) -{ - int i; - const char *prefix; - int pos = 0, ret, ev_idx = 0; - u32 xf = flags & PERF_ADDITIONAL_STATE_MASK; - u32 types, events; - char xs[16] = { 0 }; - - /* Clear additional state bits */ - flags &= ~PERF_ADDITIONAL_STATE_MASK; - - if (flags & PERF_IP_FLAG_TRACE_BEGIN) - prefix = "tr strt "; - else if (flags & PERF_IP_FLAG_TRACE_END) - prefix = "tr end "; - else - prefix = ""; - - ret = snprintf(str + pos, size - pos, "%s", prefix); - if (ret < 0) - return ret; - pos += ret; - - flags &= ~(PERF_IP_FLAG_TRACE_BEGIN | PERF_IP_FLAG_TRACE_END); - - types = flags & ~PERF_IP_FLAG_BRANCH_EVENT_MASK; - for (i = 0; sample_flags[i].name; i++) { - if (sample_flags[i].flags != types) - continue; - - ret = snprintf(str + pos, size - pos, "%s", sample_flags[i].name); - if (ret < 0) - return ret; - pos += ret; - break; - } - - events = flags & PERF_IP_FLAG_BRANCH_EVENT_MASK; - for (i = 0; branch_events[i].name; i++) { - if (!(branch_events[i].flags & events)) - continue; - - ret = snprintf(str + pos, size - pos, !ev_idx ? "/%s" : ",%s", - branch_events[i].name); - if (ret < 0) - return ret; - pos += ret; - ev_idx++; - } - - /* Add an end character '/' for events */ - if (ev_idx) { - ret = snprintf(str + pos, size - pos, "/"); - if (ret < 0) - return ret; - pos += ret; - } - - if (!xf) - return pos; - - snprintf(xs, sizeof(xs), "(%s%s%s)", - flags & PERF_IP_FLAG_IN_TX ? "x" : "", - flags & PERF_IP_FLAG_INTR_DISABLE ? "D" : "", - flags & PERF_IP_FLAG_INTR_TOGGLE ? "t" : ""); - - /* Right align the string if its length is less than the limit */ - if ((pos + strlen(xs)) < SAMPLE_FLAGS_STR_ALIGNED_SIZE) - ret = snprintf(str + pos, size - pos, "%*s", - (int)(SAMPLE_FLAGS_STR_ALIGNED_SIZE - ret), xs); - else - ret = snprintf(str + pos, size - pos, " %s", xs); - if (ret < 0) - return ret; - - return pos + ret; -} - -int perf_sample__sprintf_flags(u32 flags, char *str, size_t sz) -{ - const char *chars = PERF_IP_FLAG_CHARS; - const size_t n = strlen(PERF_IP_FLAG_CHARS); - size_t i, pos = 0; - int ret; - - ret = sample_flags_to_name(flags, str, sz); - if (ret > 0) - return ret; - - for (i = 0; i < n; i++, flags >>= 1) { - if ((flags & 1) && pos < sz) - str[pos++] = chars[i]; - } - for (; i < 32; i++, flags >>= 1) { - if ((flags & 1) && pos < sz) - str[pos++] = '?'; - } - if (pos < sz) - str[pos] = 0; - - return pos; -} diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 1c342fce36bb..fa3824cf39fa 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -7,15 +7,9 @@ #include #include -struct evlist; struct machine; -struct perf_sample; -union perf_event; -struct perf_tool; -struct thread; -struct tep_plugin_list; -struct evsel; struct tep_format_field; +struct tep_plugin_list; struct trace_event { struct tep_handle *pevent; @@ -80,70 +74,6 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs, int fd, bool temp); int tracing_data_put(struct tracing_data *tdata); - -struct addr_location; - -struct perf_session; -struct perf_stat_config; - -struct scripting_ops { - const char *name; - const char *dirname; /* For script path .../scripts//... */ - int (*start_script)(const char *script, int argc, const char **argv, - struct perf_session *session); - int (*flush_script) (void); - int (*stop_script) (void); - void (*process_event) (union perf_event *event, - struct perf_sample *sample, - struct addr_location *al, - struct addr_location *addr_al); - void (*process_switch)(union perf_event *event, - struct perf_sample *sample, - struct machine *machine); - void (*process_auxtrace_error)(struct perf_session *session, - union perf_event *event); - void (*process_stat)(struct perf_stat_config *config, - struct evsel *evsel, u64 tstamp); - void (*process_stat_interval)(u64 tstamp); - void (*process_throttle)(union perf_event *event, - struct perf_sample *sample, - struct machine *machine); - int (*generate_script) (struct tep_handle *pevent, const char *outfile); -}; - -extern unsigned int scripting_max_stack; - -struct scripting_ops *script_spec__lookup(const char *spec); -int script_spec__for_each(int (*cb)(struct scripting_ops *ops, const char *spec)); - -void setup_perl_scripting(void); -void setup_python_scripting(void); - -struct scripting_context { - struct tep_handle *pevent; - void *event_data; - union perf_event *event; - struct perf_sample *sample; - struct addr_location *al; - struct addr_location *addr_al; - struct perf_session *session; -}; - -void scripting_context__update(struct scripting_context *scripting_context, - union perf_event *event, - struct perf_sample *sample, - struct addr_location *al, - struct addr_location *addr_al); - -int common_pc(struct scripting_context *context); -int common_flags(struct scripting_context *context); -int common_lock_depth(struct scripting_context *context); - -#define SAMPLE_FLAGS_BUF_SIZE 64 -#define SAMPLE_FLAGS_STR_ALIGNED_SIZE 21 - -int perf_sample__sprintf_flags(u32 flags, char *str, size_t sz); - #if defined(LIBTRACEEVENT_VERSION) && LIBTRACEEVENT_VERSION >= MAKE_LIBTRACEEVENT_VERSION(1, 5, 0) #include