From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pg1-f200.google.com (mail-pg1-f200.google.com [209.85.215.200]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 97F9F3D75BE for ; Sun, 20 Sep 2026 05:24:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.200 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789881859; cv=none; b=p08QdI9PzaqTRF8na8dSyoUq9uXMmS9g0d1HvTcGqf/8VBReH+x2EFEkNcPrWMC+4tT87KjHn1xT01a54WFfMmu0Y9PB8ZQAaKR5QhODez5WuycD5g1y/DWqxxdGdH3AR/P+C6QHc1xiSUPcOkMBmSa1c0hCSOWWbuFFULkzfCk= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789881859; c=relaxed/simple; bh=5GQ2sFCmg2XLkG6D6url3VqS5gxpuDba28b8CrQHH6I=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=dOUfBXOu6Ro3sy8Ga2BOgHpjo/TFRjY7M48U3BAPW0MhBneiJI5GBH0Xvn6NrRO1kpD/AxJwAdpB1pG9D0lgImSrE8eeBA39oAcXsH1auI+9jNSazc7ptNs4BD58quFOdopNzR7EjpphfftWA4PTfZRbFgNusfswwVDdHo+fGMk= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=DnUgaA7/; arc=none smtp.client-ip=209.85.215.200 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="DnUgaA7/" Received: by mail-pg1-f200.google.com with SMTP id 41be03b00d2f7-cc1bbd7d6e6so1921571a12.3 for ; Sat, 19 Sep 2026 22:24:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1789881848; x=1790486648; darn=vger.kernel.org; h=content-transfer-encoding:content-type:cc:to:from:subject :message-id:references:mime-version:in-reply-to:date:from:to:cc :subject:date:message-id:reply-to:content-type; bh=Mi6A+Qkjfed8SjFR/Aqix0JxzU2dqP4hf/6nil8DarQ=; b=DnUgaA7/4wwwE4L7foYpQgSK7Iagp4ri3ylbyBidKBxnEaqNv5i9mxa01hsHSMRq3/ cH1Yv9TcKVIhe7BSeYRHbqTkVMOWRi6JDpVa7dfPuL9U980UOFx9mtiCW3t1xYDdmKbD fqxKIn30MYQX0D6hQSG1F66QkJ2mqZ9GkCNoQDhqZe2nmdLuk9tvLtEs2LtNemwAUXQt lHzJ0ukAqHRXtfL/TyKHbNsx+++B9gNM872JVyRIdAB+WuFPKiJMJExKi9aGS/3PfFz3 owJ7RjNa2fhw+4hBHClLZ7Y4gSg6Ky2EALJdoY8jnLTOWiwwGBt42EmMmPqVbBLoKj/v UNEQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1789881848; x=1790486648; h=content-transfer-encoding:content-type:cc:to:from:subject :message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=Mi6A+Qkjfed8SjFR/Aqix0JxzU2dqP4hf/6nil8DarQ=; b=ob7cZc97ry7a5PxoxHeXbnBWZl2ubPmYYo7ATkSFJZA1SJf9J1yLyYN7aiPhBWfrGo ZRHZ9+zTm4Jm353GoCvBb9nRjPkv0O1VV/04aM0rteiawe4AV6AaMJNyCadB43xcCZ+F sM4qYxTUJdE+9D27ClE/oBOuYGzOD174BUJ6iKcpUCCyTLTkP0oIgV2WGLLC9Q/vR2B0 yVNu0D7WkWQIACObxmRwXp92WutrJNGCbPw+AsP7VWqnag6gy9lkUHkCr1j6jZ6VTnq7 xLzhUrRUnOmaAS93B1sYV6ZXv8VPNlhb8siR5UupxDW23g+Hq49KWJ9fM9630NrlTa8n MAwQ== X-Forwarded-Encrypted: i=1; AKwUvBzgA3pr2voCSzN39fjNfsPZvjJ9WakINTFv1JR1KT0057WltU8iwb9tDd3muMuDEmS/Mf1xiLrHHvoP2fM=@vger.kernel.org X-Gm-Message-State: AFuF++nKCLVQuEd80+vVCvV/CwqNH7Nn0nq8Rae8C86YUQ8EN+NdofDk lF6BLErnc7r4XNTT+T8NscMLG+cd5ZnQS5DGvoCczfWgVjtgYdU8sA1FXCVu1WswM5+mVy525e4 1t5eD7cu+XQ== X-Received: from dycao20.prod.google.com ([2002:a05:7301:7d14:b0:33b:ece2:d254]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a21:e58d:b0:3dd:85aa:d26a with SMTP id adf61e73a8af0-3dd8c57caf6mr12017257637.34.1789881846934; Sat, 19 Sep 2026 22:24:06 -0700 (PDT) Date: Sat, 19 Sep 2026 22:21:40 -0700 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.55.0.1082.g2b9226bbc0-goog Message-ID: <5f68cc9d70610c56ffd66bdee04202a51e99aff3.1789880842.git.irogers@google.com> Subject: [PATCH v1 48/49] perf script: Support standalone scripts and remove embedded scripting From: Ian Rogers To: irogers@google.com, acme@kernel.org, adrian.hunter@intel.com, alice.mei.rogers@gmail.com, james.clark@linaro.org, linux-perf-users@vger.kernel.org, namhyung@kernel.org Cc: dapeng1.mi@linux.intel.com, leo.yan@linux.dev, linux-kernel@vger.kernel.org, mingo@redhat.com, peterz@infradead.org, tmricht@linux.ibm.com Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable 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. Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers --- tools/build/Makefile.feature | 1 - tools/build/feature/Makefile | 20 - tools/build/feature/test-libperl.c | 10 - tools/perf/Build | 1 - tools/perf/Documentation/perf-check.txt | 1 - tools/perf/Makefile.config | 1 - tools/perf/Makefile.perf | 14 - tools/perf/builtin-check.c | 1 - tools/perf/builtin-script.c | 824 ++++++++---------- tools/perf/scripts/Build | 3 - tools/perf/scripts/perl/Perf-Trace-Util/Build | 9 - .../scripts/perl/Perf-Trace-Util/Context.c | 122 --- .../scripts/perl/Perf-Trace-Util/Context.xs | 42 - .../scripts/perl/Perf-Trace-Util/Makefile.PL | 18 - .../perf/scripts/perl/Perf-Trace-Util/README | 59 -- .../Perf-Trace-Util/lib/Perf/Trace/Context.pm | 55 -- .../Perf-Trace-Util/lib/Perf/Trace/Core.pm | 192 ---- .../Perf-Trace-Util/lib/Perf/Trace/Util.pm | 94 -- .../perf/scripts/perl/Perf-Trace-Util/typemap | 1 - .../scripts/perl/bin/check-perf-trace-record | 2 - .../scripts/perl/bin/failed-syscalls-record | 3 - .../scripts/perl/bin/failed-syscalls-report | 10 - tools/perf/scripts/perl/bin/rw-by-file-record | 3 - tools/perf/scripts/perl/bin/rw-by-file-report | 10 - tools/perf/scripts/perl/bin/rw-by-pid-record | 2 - tools/perf/scripts/perl/bin/rw-by-pid-report | 3 - tools/perf/scripts/perl/bin/rwtop-record | 2 - tools/perf/scripts/perl/bin/rwtop-report | 20 - .../scripts/perl/bin/wakeup-latency-record | 6 - .../scripts/perl/bin/wakeup-latency-report | 3 - tools/perf/scripts/perl/check-perf-trace.pl | 106 --- tools/perf/scripts/perl/failed-syscalls.pl | 47 - tools/perf/scripts/perl/rw-by-file.pl | 106 --- tools/perf/scripts/perl/rw-by-pid.pl | 184 ---- tools/perf/scripts/perl/rwtop.pl | 203 ----- tools/perf/scripts/perl/wakeup-latency.pl | 107 --- tools/perf/tests/make | 2 - tools/perf/tests/shell/script_perl.sh | 102 --- tools/perf/ui/browsers/scripts.c | 161 +--- tools/perf/util/Build | 2 - tools/perf/util/scripting-engines/Build | 5 - .../util/scripting-engines/trace-event-perl.c | 770 ---------------- tools/perf/util/trace-event-parse.c | 65 -- tools/perf/util/trace-event-scripting.c | 398 --------- tools/perf/util/trace-event.h | 72 +- 45 files changed, 355 insertions(+), 3507 deletions(-) delete mode 100644 tools/build/feature/test-libperl.c delete mode 100644 tools/perf/scripts/Build delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/Build delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/Context.c delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/Context.xs delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/Makefile.PL delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/README delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/= Context.pm delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/= Core.pm delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/= Util.pm delete mode 100644 tools/perf/scripts/perl/Perf-Trace-Util/typemap delete mode 100644 tools/perf/scripts/perl/bin/check-perf-trace-record delete mode 100644 tools/perf/scripts/perl/bin/failed-syscalls-record delete mode 100644 tools/perf/scripts/perl/bin/failed-syscalls-report delete mode 100644 tools/perf/scripts/perl/bin/rw-by-file-record delete mode 100644 tools/perf/scripts/perl/bin/rw-by-file-report delete mode 100644 tools/perf/scripts/perl/bin/rw-by-pid-record delete mode 100644 tools/perf/scripts/perl/bin/rw-by-pid-report delete mode 100644 tools/perf/scripts/perl/bin/rwtop-record delete mode 100644 tools/perf/scripts/perl/bin/rwtop-report delete mode 100644 tools/perf/scripts/perl/bin/wakeup-latency-record delete mode 100644 tools/perf/scripts/perl/bin/wakeup-latency-report delete mode 100644 tools/perf/scripts/perl/check-perf-trace.pl delete mode 100644 tools/perf/scripts/perl/failed-syscalls.pl delete mode 100644 tools/perf/scripts/perl/rw-by-file.pl delete mode 100644 tools/perf/scripts/perl/rw-by-pid.pl delete mode 100644 tools/perf/scripts/perl/rwtop.pl delete mode 100644 tools/perf/scripts/perl/wakeup-latency.pl delete mode 100755 tools/perf/tests/shell/script_perl.sh delete mode 100644 tools/perf/util/scripting-engines/Build delete mode 100644 tools/perf/util/scripting-engines/trace-event-perl.c delete mode 100644 tools/perf/util/trace-event-scripting.c diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 3ca7a4f5c7fd..dbef5b6c4e43 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -121,7 +121,6 @@ FEATURE_TESTS_EXTRA :=3D \ libbfd-liberty \ libbfd-liberty-z \ libopencsd \ - libperl \ llvm \ libbpf \ libpfm4 \ diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index 269af8e8f5cf..62f9cbf3dee9 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -31,7 +31,6 @@ FILES=3D \ test-libdebuginfod.bin \ test-libnuma.bin \ test-numa_num_possible_cpus.bin \ - test-libperl.bin \ test-python-module.bin \ test-libslang.bin \ test-libtraceevent.bin \ @@ -242,25 +241,6 @@ $(OUTPUT)test-libtracefs.bin: $(OUTPUT)test-gtk4.bin: $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk4 2>/dev/null) =20 -grep-libs =3D $(filter -l%,$(1)) -strip-libs =3D $(filter-out -l%,$(1)) - -PERL_EMBED_LDOPTS =3D $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null= ) -PERL_EMBED_LDFLAGS =3D $(call strip-libs,$(PERL_EMBED_LDOPTS)) -PERL_EMBED_LIBADD =3D $(call grep-libs,$(PERL_EMBED_LDOPTS)) -PERL_EMBED_CCOPTS =3D $(shell perl -MExtUtils::Embed -e ccopts 2>/dev/null= ) -FLAGS_PERL_EMBED=3D$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) - -ifeq ($(CC_NO_CLANG), 0) - PERL_EMBED_LDOPTS :=3D $(filter-out -specs=3D%,$(PERL_EMBED_LDOPTS)) - PERL_EMBED_CCOPTS :=3D $(filter-out -flto=3Dauto -ffat-lto-objects, $(PE= RL_EMBED_CCOPTS)) - PERL_EMBED_CCOPTS :=3D $(filter-out -specs=3D%,$(PERL_EMBED_CCOPTS)) - FLAGS_PERL_EMBED +=3D -Wno-compound-token-split-by-macro -endif - -$(OUTPUT)test-libperl.bin: - $(BUILD) $(FLAGS_PERL_EMBED) - $(OUTPUT)test-python-module.bin: $(BUILD) $(FLAGS_PYTHON_EMBED) =20 diff --git a/tools/build/feature/test-libperl.c b/tools/build/feature/test-= libperl.c deleted file mode 100644 index 0415f437eb31..000000000000 --- a/tools/build/feature/test-libperl.c +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -int main(void) -{ - perl_alloc(); - - return 0; -} diff --git a/tools/perf/Build b/tools/perf/Build index 5bd0e58d7cb0..8a0b5592a973 100644 --- a/tools/perf/Build +++ b/tools/perf/Build @@ -61,7 +61,6 @@ perf-util-y +=3D arch/ perf-y +=3D arch/ perf-test-y +=3D arch/ perf-ui-y +=3D ui/ -perf-util-y +=3D scripts/ =20 gtk-y +=3D ui/gtk/ =20 diff --git a/tools/perf/Documentation/perf-check.txt b/tools/perf/Documenta= tion/perf-check.txt index a80913794eb6..1406a41c5d09 100644 --- a/tools/perf/Documentation/perf-check.txt +++ b/tools/perf/Documentation/perf-check.txt @@ -58,7 +58,6 @@ feature:: libLLVM / HAVE_LIBLLVM_SUPPORT libnuma / HAVE_LIBNUMA_SUPPORT libopencsd / HAVE_CSTRACE_SUPPORT - libperl / HAVE_LIBPERL_SUPPORT libpfm4 / HAVE_LIBPFM libslang / HAVE_SLANG_SUPPORT libtraceevent / HAVE_LIBTRACEEVENT diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 7e05b7943b3b..5c404289780b 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -1275,7 +1275,6 @@ $(call detected_var,tipdir_SQ) $(call detected_var,srcdir_SQ) $(call detected_var,LIBDIR) $(call detected_var,GTK_CFLAGS) -$(call detected_var,PERL_EMBED_CCOPTS) $(call detected_var,PYTHON_EMBED_CCOPTS) ifneq ($(BISON_FILE_PREFIX_MAP),) $(call detected_var,BISON_FILE_PREFIX_MAP) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 6bcea56f1f90..57e1a1a04e8a 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -17,7 +17,6 @@ include ../scripts/utilities.mak # # Define CROSS_COMPILE as prefix name of compiler if you want cross-builds= . # -# Define LIBPERL to enable perl script extension. # # Define NO_PYTHON_MODULE to disable python script extension. # @@ -481,11 +480,6 @@ OTHER_PROGRAMS =3D $(OUTPUT)perf ifndef SHELL_PATH SHELL_PATH =3D /bin/sh endif -ifndef PERL_PATH - PERL_PATH =3D /usr/bin/perl -endif - -export PERL_PATH =20 LIBPERF_BENCH_IN :=3D $(OUTPUT)perf-bench-in.o LIBPERF_BENCH :=3D $(OUTPUT)libperf-bench.a @@ -890,14 +884,6 @@ endif $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)= ' $(call QUIET_INSTALL, perf-iostat) \ $(INSTALL) $(OUTPUT)perf-iostat -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' -ifdef LIBPERL - $(call QUIET_INSTALL, perl-scripts) \ - $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/P= erf-Trace-Util/lib/Perf/Trace'; \ - $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -m 644 -t '$(DE= STDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace= '; \ - $(INSTALL) scripts/perl/*.pl -m 644 -t '$(DESTDIR_SQ)$(perfexec_instdir_= SQ)/scripts/perl'; \ - $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/b= in'; \ - $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/sc= ripts/perl/bin' -endif =20 ifndef NO_PYTHON_MODULE $(call QUIET_INSTALL, python-scripts) \ diff --git a/tools/perf/builtin-check.c b/tools/perf/builtin-check.c index 06711362d37f..1e43e097e7a7 100644 --- a/tools/perf/builtin-check.c +++ b/tools/perf/builtin-check.c @@ -51,7 +51,6 @@ struct feature_status supported_features[] =3D { FEATURE_STATUS("libLLVM", HAVE_LIBLLVM_SUPPORT), FEATURE_STATUS("libnuma", HAVE_LIBNUMA_SUPPORT), FEATURE_STATUS("libopencsd", HAVE_CSTRACE_SUPPORT), - FEATURE_STATUS_TIP("libperl", HAVE_LIBPERL_SUPPORT, "Deprecated, use LIBP= ERL=3D1 and install perl-ExtUtils-Embed/libperl-dev to build with it"), FEATURE_STATUS("python-module", HAVE_PYTHON_MODULE_SUPPORT), FEATURE_STATUS("libpfm4", HAVE_LIBPFM), FEATURE_STATUS("libslang", HAVE_SLANG_SUPPORT), diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 0174489d1c0f..c9e1b5ac5c8f 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -3,6 +3,9 @@ #include #include #include +#include +#include +#include =20 #include #include @@ -18,6 +21,7 @@ #include #include #include +#include #include #include =20 @@ -78,7 +82,6 @@ #endif =20 static char const *script_name; -static char const *generate_script_lang; static bool reltime; static bool deltatime; static u64 initial_time; @@ -88,7 +91,6 @@ static u64 last_timestamp; static u64 nr_unordered; static bool no_callchain; static bool latency_format; -static bool system_wide; static bool print_flags; static const char *cpu_list; static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); @@ -96,6 +98,7 @@ static int max_blocks; static struct dlfilter *dlfilter; static int dlargc; static char **dlargv; +static unsigned int scripting_max_stack =3D PERF_MAX_STACK_DEPTH; =20 enum perf_output_field { PERF_OUTPUT_COMM =3D 1ULL << 0, @@ -1810,6 +1813,144 @@ static int perf_sample__fprintf_bts(struct perf_sam= ple *sample, return printed; } =20 +#define SAMPLE_FLAGS_BUF_SIZE 64 +#define SAMPLE_FLAGS_STR_ALIGNED_SIZE 21 + +static int sample_flags_to_name(u32 flags, char *str, size_t size) +{ + static const struct { + u32 flags; + const char *name; + } sample_flags[] =3D { + {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, "ir= et"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET, "sys= call"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET, "s= ysret"}, + {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, "vmentr= y"}, + {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[] =3D { + {PERF_IP_FLAG_BRANCH_MISS, "miss"}, + {PERF_IP_FLAG_NOT_TAKEN, "not_taken"}, + {0, NULL} + }; + int i; + const char *prefix; + int pos =3D 0, ret, ev_idx =3D 0; + u32 xf =3D flags & PERF_ADDITIONAL_STATE_MASK; + u32 types, events; + char xs[16] =3D { 0 }; + + /* Clear additional state bits */ + flags &=3D ~PERF_ADDITIONAL_STATE_MASK; + + if (flags & PERF_IP_FLAG_TRACE_BEGIN) + prefix =3D "tr strt "; + else if (flags & PERF_IP_FLAG_TRACE_END) + prefix =3D "tr end "; + else + prefix =3D ""; + + ret =3D snprintf(str + pos, size - pos, "%s", prefix); + if (ret < 0) + return ret; + pos +=3D ret; + + flags &=3D ~(PERF_IP_FLAG_TRACE_BEGIN | PERF_IP_FLAG_TRACE_END); + + types =3D flags & ~PERF_IP_FLAG_BRANCH_EVENT_MASK; + for (i =3D 0; sample_flags[i].name; i++) { + if (sample_flags[i].flags !=3D types) + continue; + + ret =3D snprintf(str + pos, size - pos, "%s", sample_flags[i].name); + if (ret < 0) + return ret; + pos +=3D ret; + break; + } + + events =3D flags & PERF_IP_FLAG_BRANCH_EVENT_MASK; + for (i =3D 0; branch_events[i].name; i++) { + if (!(branch_events[i].flags & events)) + continue; + + ret =3D snprintf(str + pos, size - pos, !ev_idx ? "/%s" : ",%s", + branch_events[i].name); + if (ret < 0) + return ret; + pos +=3D ret; + ev_idx++; + } + + /* Add an end character '/' for events */ + if (ev_idx) { + ret =3D snprintf(str + pos, size - pos, "/"); + if (ret < 0) + return ret; + pos +=3D 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 =3D snprintf(str + pos, size - pos, "%*s", + (int)(SAMPLE_FLAGS_STR_ALIGNED_SIZE - ret), xs); + else + ret =3D snprintf(str + pos, size - pos, " %s", xs); + if (ret < 0) + return ret; + + return pos + ret; +} + +static int perf_sample__sprintf_flags(u32 flags, char *str, size_t sz) +{ + const char *chars =3D PERF_IP_FLAG_CHARS; + const size_t n =3D strlen(PERF_IP_FLAG_CHARS); + size_t i, pos =3D 0; + int ret; + + ret =3D sample_flags_to_name(flags, str, sz); + if (ret > 0) + return ret; + + for (i =3D 0; i < n; i++, flags >>=3D 1) { + if ((flags & 1) && pos < sz) + str[pos++] =3D chars[i]; + } + for (; i < 32; i++, flags >>=3D 1) { + if ((flags & 1) && pos < sz) + str[pos++] =3D '?'; + } + if (pos < sz) + str[pos] =3D 0; + + return pos; +} + static int perf_sample__fprintf_flags(u32 flags, FILE *fp) { char str[SAMPLE_FLAGS_BUF_SIZE]; @@ -2653,8 +2794,6 @@ static void process_event(struct perf_script *script, fflush(fp); } =20 -static struct scripting_ops *scripting_ops; - static void __process_stat(struct evsel *counter, u64 tstamp) { int nthreads =3D perf_thread_map__nr(counter->core.threads); @@ -2689,37 +2828,14 @@ static void __process_stat(struct evsel *counter, u= 64 tstamp) =20 static void process_stat(struct evsel *counter, u64 tstamp) { - if (scripting_ops && scripting_ops->process_stat) - scripting_ops->process_stat(&stat_config, counter, tstamp); - else - __process_stat(counter, tstamp); -} - -static void process_stat_interval(u64 tstamp) -{ - if (scripting_ops && scripting_ops->process_stat_interval) - scripting_ops->process_stat_interval(tstamp); -} - -static void setup_scripting(void) -{ -#ifdef HAVE_LIBTRACEEVENT - setup_perl_scripting(); -#endif - setup_python_scripting(); + __process_stat(counter, tstamp); } =20 -static int flush_scripting(void) +static void process_stat_interval(u64 tstamp __maybe_unused) { - return scripting_ops ? scripting_ops->flush_script() : 0; } =20 -static int cleanup_scripting(void) -{ - pr_debug("\nperf script stopped\n"); =20 - return scripting_ops ? scripting_ops->stop_script() : 0; -} =20 static bool filter_cpu(struct perf_sample *sample) { @@ -2793,20 +2909,7 @@ static int process_sample_event(const struct perf_to= ol *tool, goto out_put; } =20 - if (scripting_ops) { - struct addr_location *addr_al_ptr =3D NULL; - - if ((evsel->core.attr.sample_type & PERF_SAMPLE_ADDR) && - sample_addr_correlates_sym(&evsel->core.attr)) { - if (!addr_al.thread) - thread__resolve(al.thread, &addr_al, sample); - addr_al_ptr =3D &addr_al; - } - scripting_ops->process_event(event, sample, &al, addr_al_ptr); - } else { - process_event(scr, sample, &al, &addr_al, machine); - } - + process_event(scr, sample, &al, &addr_al, machine); out_put: addr_location__exit(&addr_al); addr_location__exit(&al); @@ -3118,8 +3221,7 @@ static int process_switch_event(const struct perf_too= l *tool, if (perf_event__process_switch(tool, event, sample, machine) < 0) return -1; =20 - if (scripting_ops && scripting_ops->process_switch && !filter_cpu(sample)= ) - scripting_ops->process_switch(event, sample, machine); + =20 if (!script->show_switch_events) return 0; @@ -3128,17 +3230,7 @@ static int process_switch_event(const struct perf_to= ol *tool, sample->tid); } =20 -static int process_auxtrace_error(const struct perf_tool *tool, - struct perf_session *session, - union perf_event *event) -{ - if (scripting_ops && scripting_ops->process_auxtrace_error) { - scripting_ops->process_auxtrace_error(session, event); - return 0; - } =20 - return perf_event__process_auxtrace_error(tool, session, event); -} =20 static int process_lost_event(const struct perf_tool *tool, @@ -3152,12 +3244,11 @@ process_lost_event(const struct perf_tool *tool, =20 static int process_throttle_event(const struct perf_tool *tool __maybe_unused, - union perf_event *event, - struct perf_sample *sample, - struct machine *machine) + union perf_event *event __maybe_unused, + struct perf_sample *sample __maybe_unused, + struct machine *machine __maybe_unused) { - if (scripting_ops && scripting_ops->process_throttle) - scripting_ops->process_throttle(event, sample, machine); + return 0; } =20 @@ -3300,10 +3391,9 @@ static int __cmd_script(struct perf_script *script) script->tool.mmap =3D process_mmap_event; script->tool.mmap2 =3D process_mmap2_event; } - if (script->show_switch_events || (scripting_ops && scripting_ops->proces= s_switch)) + if (script->show_switch_events) script->tool.context_switch =3D process_switch_event; - if (scripting_ops && scripting_ops->process_auxtrace_error) - script->tool.auxtrace_error =3D process_auxtrace_error; + script->tool.auxtrace_error =3D perf_event__process_auxtrace_error; if (script->show_namespace_events) script->tool.namespaces =3D process_namespaces_event; if (script->show_cgroup_events) @@ -3340,96 +3430,49 @@ static int __cmd_script(struct perf_script *script) return ret; } =20 -static int list_available_languages_cb(struct scripting_ops *ops, const ch= ar *spec) -{ - fprintf(stderr, " %-42s [%s]\n", spec, ops->name); - return 0; -} =20 -static void list_available_languages(void) -{ - fprintf(stderr, "\n"); - fprintf(stderr, "Scripting language extensions (used in " - "perf script -s [spec:]script.[spec]):\n\n"); - script_spec__for_each(&list_available_languages_cb); - fprintf(stderr, "\n"); -} =20 /* Find script file relative to current directory or exec path */ static char *find_script(const char *script) { char path[PATH_MAX]; + char *exec_path; =20 - if (!scripting_ops) { - const char *ext =3D strrchr(script, '.'); + if (strchr(script, '/') && access(script, R_OK) =3D=3D 0) + return strdup(script); =20 - if (!ext) - return NULL; + exec_path =3D get_argv_exec_path(); + if (exec_path) { + snprintf(path, sizeof(path), "%s/python/%s", exec_path, script); + if (access(path, R_OK) =3D=3D 0) { + free(exec_path); + return strdup(path); + } =20 - scripting_ops =3D script_spec__lookup(++ext); - if (!scripting_ops) - return NULL; + snprintf(path, sizeof(path), "%s/python/%s.py", exec_path, script); + free(exec_path); + if (access(path, R_OK) =3D=3D 0) + return strdup(path); } =20 - if (access(script, R_OK)) { - char *exec_path =3D get_argv_exec_path(); - - if (!exec_path) - return NULL; - snprintf(path, sizeof(path), "%s/scripts/%s/%s", - exec_path, scripting_ops->dirname, script); - free(exec_path); - script =3D path; - if (access(script, R_OK)) - return NULL; + if (access(script, R_OK) =3D=3D 0) { + if (!strchr(script, '/')) { + snprintf(path, sizeof(path), "./%s", script); + return strdup(path); + } + return strdup(script); } - return strdup(script); + + /* Failure to find script. */ + return NULL; } =20 static int parse_scriptname(const struct option *opt __maybe_unused, const char *str, int unset __maybe_unused) { - char spec[PATH_MAX]; - const char *script, *ext; - int len; - - if (strcmp(str, "lang") =3D=3D 0) { - list_available_languages(); - exit(0); - } - - script =3D strchr(str, ':'); - if (script) { - len =3D script - str; - if (len >=3D PATH_MAX) { - fprintf(stderr, "invalid language specifier"); - return -1; - } - strncpy(spec, str, len); - spec[len] =3D '\0'; - scripting_ops =3D script_spec__lookup(spec); - if (!scripting_ops) { - fprintf(stderr, "invalid language specifier"); - return -1; - } - script++; - } else { - script =3D str; - ext =3D strrchr(script, '.'); - if (!ext) { - fprintf(stderr, "invalid script extension"); - return -1; - } - scripting_ops =3D script_spec__lookup(++ext); - if (!scripting_ops) { - fprintf(stderr, "invalid script extension"); - return -1; - } - } - - script_name =3D find_script(script); + script_name =3D find_script(str); if (!script_name) - script_name =3D strdup(script); + script_name =3D strdup(str); =20 return 0; } @@ -3625,7 +3668,6 @@ struct script_desc { struct list_head node; char *name; char *half_liner; - char *args; }; =20 static LIST_HEAD(script_descs); @@ -3640,16 +3682,18 @@ static struct script_desc *script_desc__new(const c= har *name) return s; } =20 -static void script_desc__delete(struct script_desc *s) -{ - zfree(&s->name); - zfree(&s->half_liner); - zfree(&s->args); - free(s); -} + =20 static void script_desc__add(struct script_desc *s) { + struct script_desc *pos; + + list_for_each_entry(pos, &script_descs, node) { + if (s->name && pos->name && strcasecmp(s->name, pos->name) < 0) { + list_add_tail(&s->node, &pos->node); + return; + } + } list_add_tail(&s->node, &script_descs); } =20 @@ -3697,15 +3741,66 @@ static int read_script_info(struct script_desc *des= c, const char *filename) { char line[BUFSIZ], *p; FILE *fp; + bool in_docstring =3D false; + bool found_description =3D false; =20 fp =3D fopen(filename, "r"); if (!fp) return -1; =20 while (fgets(line, sizeof(line), fp)) { + static const char * const triple_quote_str[] =3D { + "\"\"\"", + "'''", + "r\"\"\"", + }; p =3D skip_spaces(line); if (strlen(p) =3D=3D 0) continue; + + if (in_docstring) { + if (strlen(p) && p[strlen(p) - 1] =3D=3D '\n') + p[strlen(p) - 1] =3D '\0'; + zfree(&desc->half_liner); + desc->half_liner =3D strdup(skip_spaces(p)); + in_docstring =3D false; + found_description =3D true; + break; + } + + + for (size_t i =3D 0; i < ARRAY_SIZE(triple_quote_str); i++) { + const char *quote =3D triple_quote_str[i]; + const char *close_quote =3D quote; + + if (quote[0] =3D=3D 'r' || quote[0] =3D=3D 'R') + close_quote++; + + if (!strstarts(p, quote)) + continue; + + p +=3D strlen(quote); + p =3D skip_spaces(p); + if (strlen(p) > 0) { + if (p[strlen(p) - 1] =3D=3D '\n') + p[strlen(p) - 1] =3D '\0'; + p =3D skip_spaces(p); + if (str_ends_with(p, close_quote)) + p[strlen(p) - strlen(close_quote)] =3D '\0'; + zfree(&desc->half_liner); + desc->half_liner =3D strdup(skip_spaces(p)); + found_description =3D true; + break; + } + in_docstring =3D true; + break; + } + if (found_description) + break; + + if (in_docstring) + continue; + if (*p !=3D '#') continue; p++; @@ -3718,14 +3813,17 @@ static int read_script_info(struct script_desc *des= c, const char *filename) =20 if (!strncmp(p, "description:", strlen("description:"))) { p +=3D strlen("description:"); + zfree(&desc->half_liner); desc->half_liner =3D strdup(skip_spaces(p)); - continue; + found_description =3D true; + break; } =20 - if (!strncmp(p, "args:", strlen("args:"))) { - p +=3D strlen("args:"); - desc->args =3D strdup(skip_spaces(p)); - continue; + if (!found_description && strlen(p) > 0 && + strncmp(p, "SPDX-License-Identifier", 23)) { + if (!desc->half_liner) + desc->half_liner =3D strdup(p); + // Don't set found_description, maybe we find a better "description:" l= ater! } } =20 @@ -3756,23 +3854,21 @@ static int list_available_scripts(const struct opti= on *opt __maybe_unused, const char *s __maybe_unused, int unset __maybe_unused) { - struct dirent *script_dirent, *lang_dirent; - char *buf, *scripts_path, *script_path, *lang_path, *first_half; - DIR *scripts_dir, *lang_dir; + struct dirent *script_dirent; + char *buf, *scripts_path, *script_path; + DIR *scripts_dir; struct script_desc *desc; char *script_root; =20 - buf =3D malloc(3 * MAXPATHLEN + BUFSIZ); + buf =3D malloc(2 * MAXPATHLEN + BUFSIZ); if (!buf) { pr_err("malloc failed\n"); exit(-1); } scripts_path =3D buf; script_path =3D buf + MAXPATHLEN; - lang_path =3D buf + 2 * MAXPATHLEN; - first_half =3D buf + 3 * MAXPATHLEN; =20 - snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path()); + snprintf(scripts_path, MAXPATHLEN, "%s/python", get_argv_exec_path()); =20 scripts_dir =3D opendir(scripts_path); if (!scripts_dir) { @@ -3784,30 +3880,26 @@ static int list_available_scripts(const struct opti= on *opt __maybe_unused, exit(-1); } =20 - for_each_lang(scripts_path, scripts_dir, lang_dirent) { - scnprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, - lang_dirent->d_name); - lang_dir =3D opendir(lang_path); - if (!lang_dir) - continue; + while ((script_dirent =3D readdir(scripts_dir)) !=3D NULL) { + if (script_dirent->d_type !=3D DT_DIR && + (script_dirent->d_type !=3D DT_UNKNOWN || + !is_directory(scripts_path, script_dirent))) { =20 - for_each_script(lang_path, lang_dir, script_dirent) { - script_root =3D get_script_root(script_dirent, REPORT_SUFFIX); + script_root =3D get_script_root(script_dirent, ".py"); if (script_root) { desc =3D script_desc__findnew(script_root); scnprintf(script_path, MAXPATHLEN, "%s/%s", - lang_path, script_dirent->d_name); + scripts_path, script_dirent->d_name); read_script_info(desc, script_path); free(script_root); } } } + closedir(scripts_dir); =20 - fprintf(stdout, "List of available trace scripts:\n"); + fprintf(stdout, "List of available scripts:\n"); list_for_each_entry(desc, &script_descs, node) { - sprintf(first_half, "%s %s", desc->name, - desc->args ? desc->args : ""); - fprintf(stdout, " %-36s %s\n", first_half, + fprintf(stdout, " %-36s %s\n", desc->name, desc->half_liner ? desc->half_liner : ""); } =20 @@ -3843,93 +3935,7 @@ static void free_dlarg(void) free(dlargv); } =20 -static char *get_script_path(const char *script_root, const char *suffix) -{ - struct dirent *script_dirent, *lang_dirent; - char scripts_path[MAXPATHLEN]; - char script_path[MAXPATHLEN]; - DIR *scripts_dir, *lang_dir; - char lang_path[MAXPATHLEN]; - char *__script_root; - - snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path()); - - scripts_dir =3D opendir(scripts_path); - if (!scripts_dir) - return NULL; - - for_each_lang(scripts_path, scripts_dir, lang_dirent) { - scnprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, - lang_dirent->d_name); - lang_dir =3D opendir(lang_path); - if (!lang_dir) - continue; - - for_each_script(lang_path, lang_dir, script_dirent) { - __script_root =3D get_script_root(script_dirent, suffix); - if (__script_root && !strcmp(script_root, __script_root)) { - free(__script_root); - closedir(scripts_dir); - scnprintf(script_path, MAXPATHLEN, "%s/%s", - lang_path, script_dirent->d_name); - closedir(lang_dir); - return strdup(script_path); - } - free(__script_root); - } - closedir(lang_dir); - } - closedir(scripts_dir); - - return NULL; -} - -static bool is_top_script(const char *script_path) -{ - return ends_with(script_path, "top") !=3D NULL; -} =20 -static int has_required_arg(char *script_path) -{ - struct script_desc *desc; - int n_args =3D 0; - char *p; - - desc =3D script_desc__new(NULL); - - if (read_script_info(desc, script_path)) - goto out; - - if (!desc->args) - goto out; - - for (p =3D desc->args; *p; p++) - if (*p =3D=3D '<') - n_args++; -out: - script_desc__delete(desc); - - return n_args; -} - -static int have_cmd(int argc, const char **argv) -{ - char **__argv =3D calloc(argc, sizeof(const char *)); - - if (!__argv) { - pr_err("malloc failed\n"); - return -1; - } - - memcpy(__argv, argv, sizeof(const char *) * argc); - argc =3D parse_options(argc, (const char **)__argv, record_options, - NULL, PARSE_OPT_STOP_AT_NON_OPTION); - free(__argv); - - system_wide =3D (argc =3D=3D 0); - - return 0; -} =20 static void script__setup_sample_type(struct perf_script *script) { @@ -4115,17 +4121,13 @@ int cmd_script(int argc, const char **argv) bool show_full_info =3D false; bool header =3D false; bool header_only =3D false; - bool script_started =3D false; bool unsorted_dump =3D false; bool merge_deferred_callchains =3D true; - char *rec_script_path =3D NULL; - char *rep_script_path =3D NULL; struct perf_session *session; struct itrace_synth_opts itrace_synth_opts =3D { .set =3D false, .default_no_sample =3D true, }; - char *script_path =3D NULL; const char *dlfilter_file =3D NULL; const char **__argv; int i, j, err =3D 0; @@ -4146,11 +4148,10 @@ int cmd_script(int argc, const char **argv) list_available_scripts), OPT_CALLBACK_NOOPT(0, "list-dlfilters", NULL, NULL, "list available dlfil= ters", list_available_dlfilters), - OPT_CALLBACK('s', "script", NULL, "name", - "script file name (lang:script name, script name, or *)", - parse_scriptname), - OPT_STRING('g', "gen-script", &generate_script_lang, "lang", - "generate perf-script.xx script in specified language"), + { .type =3D OPTION_CALLBACK, .short_name =3D 's', .long_name =3D "script"= , + .value =3D NULL, .argh =3D "name", + .help =3D "script file name (lang:script name, script name, or *)", + .callback =3D parse_scriptname, .flags =3D PARSE_OPT_HIDDEN }, OPT_STRING(0, "dlfilter", &dlfilter_file, "file", "filter .so file name")= , OPT_CALLBACK(0, "dlarg", NULL, "argument", "filter argument", add_dlarg), @@ -4179,8 +4180,6 @@ int cmd_script(int argc, const char **argv) "code_page_size,ins_lat,machine_pid,vcpu,cgroup,retire_lat," "brcntr", parse_output_fields), - OPT_BOOLEAN('a', "all-cpus", &system_wide, - "system-wide collection from all CPUs"), OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", "only consider symbols in these DSOs"), OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]= ", @@ -4277,22 +4276,17 @@ int cmd_script(int argc, const char **argv) OPTS_EVSWITCH(&script.evswitch), OPT_END() }; - const char * const script_subcommands[] =3D { "record", "report", NULL }; const char *script_usage[] =3D { "perf script []", - "perf script [] record