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 := \ 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= \ 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) -grep-libs = $(filter -l%,$(1)) -strip-libs = $(filter-out -l%,$(1)) - -PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null) -PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS)) -PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS)) -PERL_EMBED_CCOPTS = $(shell perl -MExtUtils::Embed -e ccopts 2>/dev/null) -FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) - -ifeq ($(CC_NO_CLANG), 0) - PERL_EMBED_LDOPTS := $(filter-out -specs=%,$(PERL_EMBED_LDOPTS)) - PERL_EMBED_CCOPTS := $(filter-out -flto=auto -ffat-lto-objects, $(PERL_EMBED_CCOPTS)) - PERL_EMBED_CCOPTS := $(filter-out -specs=%,$(PERL_EMBED_CCOPTS)) - FLAGS_PERL_EMBED += -Wno-compound-token-split-by-macro -endif - -$(OUTPUT)test-libperl.bin: - $(BUILD) $(FLAGS_PERL_EMBED) - $(OUTPUT)test-python-module.bin: $(BUILD) $(FLAGS_PYTHON_EMBED) 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 += arch/ perf-y += arch/ perf-test-y += arch/ perf-ui-y += ui/ -perf-util-y += scripts/ gtk-y += ui/gtk/ diff --git a/tools/perf/Documentation/perf-check.txt b/tools/perf/Documentation/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 6cb6b02fb0d2..8f46885d6df5 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -1296,7 +1296,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 106f8e21a9d4..5e89ff37d5b0 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. # @@ -483,11 +482,6 @@ OTHER_PROGRAMS = $(OUTPUT)perf ifndef SHELL_PATH SHELL_PATH = /bin/sh endif -ifndef PERL_PATH - PERL_PATH = /usr/bin/perl -endif - -export PERL_PATH LIBPERF_BENCH_IN := $(OUTPUT)perf-bench-in.o LIBPERF_BENCH := $(OUTPUT)libperf-bench.a @@ -892,14 +886,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/Perf-Trace-Util/lib/Perf/Trace'; \ - $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -m 644 -t '$(DESTDIR_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/bin'; \ - $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' -endif ifndef NO_PYTHON_MODULE $(call QUIET_INSTALL, python-scripts) \ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/python' && \ 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[] = { 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 LIBPERL=1 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 565ee8d55f80..b6691ebb1b4e 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1,8 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 #include #include +#include #include #include +#include +#include +#include #include #include @@ -18,6 +22,7 @@ #include #include #include +#include #include #include @@ -77,8 +82,7 @@ #include #endif -static char const *script_name; -static char const *generate_script_lang; +static char *script_name; static bool reltime; static bool deltatime; static u64 initial_time; @@ -88,7 +92,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 +99,7 @@ static int max_blocks; static struct dlfilter *dlfilter; static int dlargc; static char **dlargv; +static unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH; enum perf_output_field { PERF_OUTPUT_COMM = 1ULL << 0, @@ -1810,6 +1814,144 @@ static int perf_sample__fprintf_bts(struct perf_sample *sample, return printed; } +#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[] = { + {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} + }; + 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; +} + +static 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; +} + static int perf_sample__fprintf_flags(u32 flags, FILE *fp) { char str[SAMPLE_FLAGS_BUF_SIZE]; @@ -2654,8 +2796,6 @@ static void process_event(struct perf_script *script, fflush(fp); } -static struct scripting_ops *scripting_ops; - static void __process_stat(struct evsel *counter, u64 tstamp) { int nthreads = perf_thread_map__nr(counter->core.threads); @@ -2690,36 +2830,11 @@ static void __process_stat(struct evsel *counter, u64 tstamp) 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); + __process_stat(counter, tstamp); } -static void process_stat_interval(u64 tstamp) +static void process_stat_interval(u64 tstamp __maybe_unused) { - 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(); -} - -static int flush_scripting(void) -{ - return scripting_ops ? scripting_ops->flush_script() : 0; -} - -static int cleanup_scripting(void) -{ - pr_debug("\nperf script stopped\n"); - - return scripting_ops ? scripting_ops->stop_script() : 0; } static bool filter_cpu(struct perf_sample *sample) @@ -2794,20 +2909,7 @@ static int process_sample_event(const struct perf_tool *tool, goto out_put; } - if (scripting_ops) { - struct addr_location *addr_al_ptr = 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 = &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); @@ -3119,9 +3221,6 @@ static int process_switch_event(const struct perf_tool *tool, if (perf_event__process_switch(tool, event, sample, machine) < 0) return -1; - if (scripting_ops && scripting_ops->process_switch && !filter_cpu(sample)) - scripting_ops->process_switch(event, sample, machine); - if (!script->show_switch_events) return 0; @@ -3129,18 +3228,6 @@ static int process_switch_event(const struct perf_tool *tool, sample->tid); } -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; - } - - return perf_event__process_auxtrace_error(tool, session, event); -} - static int process_lost_event(const struct perf_tool *tool, union perf_event *event, @@ -3153,12 +3240,11 @@ process_lost_event(const struct perf_tool *tool, 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; } @@ -3301,10 +3387,9 @@ static int __cmd_script(struct perf_script *script) script->tool.mmap = process_mmap_event; script->tool.mmap2 = process_mmap2_event; } - if (script->show_switch_events || (scripting_ops && scripting_ops->process_switch)) + if (script->show_switch_events) script->tool.context_switch = process_switch_event; - if (scripting_ops && scripting_ops->process_auxtrace_error) - script->tool.auxtrace_error = process_auxtrace_error; + script->tool.auxtrace_error = perf_event__process_auxtrace_error; if (script->show_namespace_events) script->tool.namespaces = process_namespaces_event; if (script->show_cgroup_events) @@ -3341,96 +3426,48 @@ static int __cmd_script(struct perf_script *script) return ret; } -static int list_available_languages_cb(struct scripting_ops *ops, const char *spec) -{ - fprintf(stderr, " %-42s [%s]\n", spec, ops->name); - return 0; -} - -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"); -} - /* Find script file relative to current directory or exec path */ static char *find_script(const char *script) { char path[PATH_MAX]; + char *exec_path; - if (!scripting_ops) { - const char *ext = strrchr(script, '.'); + if (strchr(script, '/') && access(script, R_OK) == 0) + return strdup(script); - if (!ext) - return NULL; + exec_path = get_argv_exec_path(); + if (exec_path) { + snprintf(path, sizeof(path), "%s/python/%s", exec_path, script); + if (access(path, R_OK) == 0) { + free(exec_path); + return strdup(path); + } - scripting_ops = script_spec__lookup(++ext); - if (!scripting_ops) - return NULL; - } - - if (access(script, R_OK)) { - char *exec_path = get_argv_exec_path(); - - if (!exec_path) - return NULL; - snprintf(path, sizeof(path), "%s/scripts/%s/%s", - exec_path, scripting_ops->dirname, script); + snprintf(path, sizeof(path), "%s/python/%s.py", exec_path, script); free(exec_path); - script = path; - if (access(script, R_OK)) - return NULL; + if (access(path, R_OK) == 0) + return strdup(path); } - return strdup(script); + + if (access(script, R_OK) == 0) { + if (!strchr(script, '/')) { + snprintf(path, sizeof(path), "./%s", script); + return strdup(path); + } + return strdup(script); + } + + /* Failure to find script. */ + return NULL; } 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") == 0) { - list_available_languages(); - exit(0); - } - - script = strchr(str, ':'); - if (script) { - len = script - str; - if (len >= PATH_MAX) { - fprintf(stderr, "invalid language specifier"); - return -1; - } - strncpy(spec, str, len); - spec[len] = '\0'; - scripting_ops = script_spec__lookup(spec); - if (!scripting_ops) { - fprintf(stderr, "invalid language specifier"); - return -1; - } - script++; - } else { - script = str; - ext = strrchr(script, '.'); - if (!ext) { - fprintf(stderr, "invalid script extension"); - return -1; - } - scripting_ops = script_spec__lookup(++ext); - if (!scripting_ops) { - fprintf(stderr, "invalid script extension"); - return -1; - } - } - - script_name = find_script(script); + zfree(&script_name); + script_name = find_script(str); if (!script_name) - script_name = strdup(script); + script_name = strdup(str); return 0; } @@ -3618,7 +3655,6 @@ static int parse_output_fields(const struct option *opt __maybe_unused, (script_dirent->d_type != DT_UNKNOWN || \ !is_directory(lang_path, script_dirent))) - #define RECORD_SUFFIX "-record" #define REPORT_SUFFIX "-report" @@ -3626,7 +3662,6 @@ struct script_desc { struct list_head node; char *name; char *half_liner; - char *args; }; static LIST_HEAD(script_descs); @@ -3641,16 +3676,16 @@ static struct script_desc *script_desc__new(const char *name) return s; } -static void script_desc__delete(struct script_desc *s) -{ - zfree(&s->name); - zfree(&s->half_liner); - zfree(&s->args); - free(s); -} - 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); } @@ -3698,15 +3733,65 @@ static int read_script_info(struct script_desc *desc, const char *filename) { char line[BUFSIZ], *p; FILE *fp; + bool in_docstring = false; + bool found_description = false; fp = fopen(filename, "r"); if (!fp) return -1; while (fgets(line, sizeof(line), fp)) { + static const char * const triple_quote_str[] = { + "\"\"\"", + "'''", + "r\"\"\"", + }; p = skip_spaces(line); if (strlen(p) == 0) continue; + + if (in_docstring) { + if (strlen(p) && p[strlen(p) - 1] == '\n') + p[strlen(p) - 1] = '\0'; + zfree(&desc->half_liner); + desc->half_liner = strdup(skip_spaces(p)); + in_docstring = false; + found_description = true; + break; + } + + for (size_t i = 0; i < ARRAY_SIZE(triple_quote_str); i++) { + const char *quote = triple_quote_str[i]; + const char *close_quote = quote; + + if (quote[0] == 'r' || quote[0] == 'R') + close_quote++; + + if (!strstarts(p, quote)) + continue; + + p += strlen(quote); + p = skip_spaces(p); + if (strlen(p) > 0) { + if (p[strlen(p) - 1] == '\n') + p[strlen(p) - 1] = '\0'; + p = skip_spaces(p); + if (str_ends_with(p, close_quote)) + p[strlen(p) - strlen(close_quote)] = '\0'; + zfree(&desc->half_liner); + desc->half_liner = strdup(skip_spaces(p)); + found_description = true; + break; + } + in_docstring = true; + break; + } + if (found_description) + break; + + if (in_docstring) + continue; + if (*p != '#') continue; p++; @@ -3719,14 +3804,17 @@ static int read_script_info(struct script_desc *desc, const char *filename) if (!strncmp(p, "description:", strlen("description:"))) { p += strlen("description:"); + zfree(&desc->half_liner); desc->half_liner = strdup(skip_spaces(p)); - continue; + found_description = true; + break; } - if (!strncmp(p, "args:", strlen("args:"))) { - p += strlen("args:"); - desc->args = strdup(skip_spaces(p)); - continue; + if (!found_description && strlen(p) > 0 && + strncmp(p, "SPDX-License-Identifier", 23)) { + if (!desc->half_liner) + desc->half_liner = strdup(p); + // Don't set found_description, maybe we find a better "description:" later! } } @@ -3757,23 +3845,21 @@ static int list_available_scripts(const struct option *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; - buf = malloc(3 * MAXPATHLEN + BUFSIZ); + buf = malloc(2 * MAXPATHLEN + BUFSIZ); if (!buf) { pr_err("malloc failed\n"); exit(-1); } scripts_path = buf; script_path = buf + MAXPATHLEN; - lang_path = buf + 2 * MAXPATHLEN; - first_half = buf + 3 * MAXPATHLEN; - snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path()); + snprintf(scripts_path, MAXPATHLEN, "%s/python", get_argv_exec_path()); scripts_dir = opendir(scripts_path); if (!scripts_dir) { @@ -3785,30 +3871,26 @@ static int list_available_scripts(const struct option *opt __maybe_unused, exit(-1); } - for_each_lang(scripts_path, scripts_dir, lang_dirent) { - scnprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, - lang_dirent->d_name); - lang_dir = opendir(lang_path); - if (!lang_dir) - continue; + while ((script_dirent = readdir(scripts_dir)) != NULL) { + if (script_dirent->d_type != DT_DIR && + (script_dirent->d_type != DT_UNKNOWN || + !is_directory(scripts_path, script_dirent))) { - for_each_script(lang_path, lang_dir, script_dirent) { - script_root = get_script_root(script_dirent, REPORT_SUFFIX); + script_root = get_script_root(script_dirent, ".py"); if (script_root) { desc = 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); - 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 : ""); } @@ -3844,94 +3926,6 @@ static void free_dlarg(void) free(dlargv); } -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 = 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 = opendir(lang_path); - if (!lang_dir) - continue; - - for_each_script(lang_path, lang_dir, script_dirent) { - __script_root = 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") != NULL; -} - -static int has_required_arg(char *script_path) -{ - struct script_desc *desc; - int n_args = 0; - char *p; - - desc = script_desc__new(NULL); - - if (read_script_info(desc, script_path)) - goto out; - - if (!desc->args) - goto out; - - for (p = desc->args; *p; p++) - if (*p == '<') - n_args++; -out: - script_desc__delete(desc); - - return n_args; -} - -static int have_cmd(int argc, const char **argv) -{ - char **__argv = calloc(argc, sizeof(const char *)); - - if (!__argv) { - pr_err("malloc failed\n"); - return -1; - } - - memcpy(__argv, argv, sizeof(const char *) * argc); - argc = parse_options(argc, (const char **)__argv, record_options, - NULL, PARSE_OPT_STOP_AT_NON_OPTION); - free(__argv); - - system_wide = (argc == 0); - - return 0; -} - static void script__setup_sample_type(struct perf_script *script) { struct perf_session *session = script->session; @@ -4055,6 +4049,14 @@ static int perf_script__process_auxtrace_info(const struct perf_tool *tool, return ret; } +static const char *script_itrace_opts; + +static int parse_script_itrace(const struct option *opt, const char *str, int unset) +{ + script_itrace_opts = unset ? "" : (str && *str ? str : "cepwx"); + return itrace_parse_synth_opts(opt, str, unset); +} + static int parse_insn_trace(const struct option *opt __maybe_unused, const char *str, int unset __maybe_unused) { @@ -4074,6 +4076,7 @@ static int parse_insn_trace(const struct option *opt __maybe_unused, if (ret < 0) return ret; + script_itrace_opts = "i0nse"; itrace_parse_synth_opts(opt, "i0nse", 0); symbol_conf.nanosecs = true; return 0; @@ -4095,6 +4098,7 @@ static int parse_call_trace(const struct option *opt __maybe_unused, int unset __maybe_unused) { parse_output_fields(NULL, "-ip,-addr,-event,-period,+callindent", 0); + script_itrace_opts = "cewp"; itrace_parse_synth_opts(opt, "cewp", 0); symbol_conf.nanosecs = true; symbol_conf.pad_output_len_dso = 50; @@ -4106,27 +4110,102 @@ static int parse_callret_trace(const struct option *opt __maybe_unused, int unset __maybe_unused) { parse_output_fields(NULL, "-ip,-addr,-event,-period,+callindent,+flags", 0); + script_itrace_opts = "crewp"; itrace_parse_synth_opts(opt, "crewp", 0); symbol_conf.nanosecs = true; return 0; } +/* + * Detect scripts written for the removed legacy embedded Python scripting API. + * + * Without an embedded interpreter invoking trace_begin()/process_event()/trace_end(), + * executing a callback-only legacy script directly under `python3` would simply + * define top-level functions and silently exit with status 0 without processing + * any events. + * + * Note on ordering and heuristics: + * 1) "perf_trace_context" and "Perf-Trace-Util" must be checked BEFORE + * "import perf", because "import perf" is a substring prefix of + * "import perf_trace_context". + * 2) Defining `def process_event(`, `def trace_begin(`, or `def trace_end(` + * is only flagged as legacy when `!has_perf_import`, because standalone + * `import perf` scripts commonly define a helper named `def process_event(sample):` + * to pass as the `sample=` callback to `perf.session(...)`. + */ +static bool is_legacy_python_script(const char *path) +{ + struct stat st; + int fd; + FILE *fp; + char line[1024]; + bool has_legacy_cb = false; + bool has_perf_import = false; + + fd = open(path, O_RDONLY | O_NONBLOCK); + if (fd < 0) + return false; + + if (fstat(fd, &st) < 0 || !S_ISREG(st.st_mode)) { + close(fd); + return false; + } + + fp = fdopen(fd, "r"); + if (!fp) { + close(fd); + return false; + } + + while (fgets(line, sizeof(line), fp)) { + const char *p = skip_spaces(line); + + if (*p == '#') + continue; + if ((strstr(p, "import perf") && !strstr(p, "import perf_trace_context")) || + strstr(p, "from perf ") || + strstr(p, "__main__")) + has_perf_import = true; + if (strstr(p, "perf_trace_context") || + strstr(p, "Perf-Trace-Util") || + strstr(p, "def process_event(") || + strstr(p, "def trace_begin(") || + strstr(p, "def trace_end(")) + has_legacy_cb = true; + } + fclose(fp); + return has_legacy_cb && !has_perf_import; +} + +static volatile sig_atomic_t script_child_pid; + +static void forward_script_sig(int sig, siginfo_t *info, void *ucontext __maybe_unused) +{ + /* + * Terminal-generated signals (Ctrl-C / Ctrl-\) have si_code > 0 + * (SI_KERNEL) and are already delivered by the TTY driver to the + * entire foreground process group, including the child script. + * Signals sent directly to the perf process via kill(2) / sigqueue(3) + * have si_code <= 0 (SI_USER, SI_QUEUE, etc.) and must be forwarded + * to the child script so it can catch KeyboardInterrupt / SIGTERM + * and flush its output before exiting. + */ + if (script_child_pid > 0 && (sig == SIGTERM || !info || info->si_code <= 0)) + kill(script_child_pid, sig); +} + int cmd_script(int argc, const char **argv) { bool show_full_info = false; bool header = false; bool header_only = false; - bool script_started = false; bool unsorted_dump = false; bool merge_deferred_callchains = true; - char *rec_script_path = NULL; - char *rep_script_path = NULL; struct perf_session *session; struct itrace_synth_opts itrace_synth_opts = { .set = false, .default_no_sample = true, }; - char *script_path = NULL; const char *dlfilter_file = NULL; const char **__argv; int i, j, err = 0; @@ -4147,11 +4226,10 @@ int cmd_script(int argc, const char **argv) list_available_scripts), OPT_CALLBACK_NOOPT(0, "list-dlfilters", NULL, NULL, "list available dlfilters", 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 = OPTION_CALLBACK, .short_name = 's', .long_name = "script", + .value = NULL, .argh = "name", + .help = "script file name (lang:script name, script name, or *)", + .callback = parse_scriptname, .flags = PARSE_OPT_HIDDEN }, OPT_STRING(0, "dlfilter", &dlfilter_file, "file", "filter .so file name"), OPT_CALLBACK(0, "dlarg", NULL, "argument", "filter argument", add_dlarg), @@ -4180,8 +4258,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...]", @@ -4244,7 +4320,7 @@ int cmd_script(int argc, const char **argv) "Use 9 decimal places when displaying time"), OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts", "Instruction Tracing options\n" ITRACE_HELP, - itrace_parse_synth_opts), + parse_script_itrace), OPT_BOOLEAN(0, "full-source-path", &srcline_full_filename, "Show full source file name path for source lines"), OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, @@ -4278,22 +4354,16 @@ int cmd_script(int argc, const char **argv) OPTS_EVSWITCH(&script.evswitch), OPT_END() }; - const char * const script_subcommands[] = { "record", "report", NULL }; const char *script_usage[] = { "perf script []", - "perf script [] record 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