1 // SPDX-License-Identifier: GPL-2.0
2 #include "../../util/sort.h"
3 #include "../../util/util.h"
4 #include "../../util/hist.h"
5 #include "../../util/debug.h"
6 #include "../../util/symbol.h"
7 #include "../browser.h"
8 #include "../libslang.h"
10 #define SCRIPT_NAMELEN 128
11 #define SCRIPT_MAX_NO 64
13 * Usually the full path for a script is:
14 * /home/username/libexec/perf-core/scripts/python/xxx.py
15 * /home/username/libexec/perf-core/scripts/perl/xxx.pl
16 * So 256 should be long enough to contain the full path.
18 #define SCRIPT_FULLPATH_LEN 256
20 struct script_config {
25 char extra_format[256];
28 void attr_to_script(char *extra_format, struct perf_event_attr *attr)
31 if (attr->read_format & PERF_FORMAT_GROUP)
32 strcat(extra_format, " -F +metric");
33 if (attr->sample_type & PERF_SAMPLE_BRANCH_STACK)
34 strcat(extra_format, " -F +brstackinsn --xed");
35 if (attr->sample_type & PERF_SAMPLE_REGS_INTR)
36 strcat(extra_format, " -F +iregs");
37 if (attr->sample_type & PERF_SAMPLE_REGS_USER)
38 strcat(extra_format, " -F +uregs");
39 if (attr->sample_type & PERF_SAMPLE_PHYS_ADDR)
40 strcat(extra_format, " -F +phys_addr");
43 static int add_script_option(const char *name, const char *opt,
44 struct script_config *c)
46 c->names[c->index] = name;
47 if (asprintf(&c->paths[c->index],
48 "%s script %s -F +metric %s %s",
49 c->perf, opt, symbol_conf.inline_name ? " --inline" : "",
57 * When success, will copy the full path of the selected script
58 * into the buffer pointed by script_name, and return 0.
59 * Return -1 on failure.
61 static int list_scripts(char *script_name, bool *custom,
62 struct perf_evsel *evsel)
64 char *buf, *paths[SCRIPT_MAX_NO], *names[SCRIPT_MAX_NO];
67 int max_std, custom_perf;
69 const char *perf = perf_exe(pbuf, sizeof pbuf);
70 struct script_config scriptc = {
71 .names = (const char **)names,
78 /* Preset the script name to SCRIPT_NAMELEN */
79 buf = malloc(SCRIPT_MAX_NO * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN));
84 attr_to_script(scriptc.extra_format, &evsel->attr);
85 add_script_option("Show individual samples", "", &scriptc);
86 add_script_option("Show individual samples with assembler", "-F +insn --xed",
88 add_script_option("Show individual samples with source", "-F +srcline,+srccode",
90 custom_perf = scriptc.index;
91 add_script_option("Show samples with custom perf script arguments", "", &scriptc);
95 for (; i < SCRIPT_MAX_NO; i++) {
96 names[i] = buf + (i - max_std) * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN);
97 paths[i] = names[i] + SCRIPT_NAMELEN;
100 num = find_scripts(names + max_std, paths + max_std);
103 choice = ui__popup_menu(num + max_std, (char * const *)names);
108 if (choice == custom_perf) {
109 char script_args[50];
110 int key = ui_browser__input_window("perf script command",
111 "Enter perf script command line (without perf script prefix)",
115 sprintf(script_name, "%s script %s", perf, script_args);
116 } else if (choice < num + max_std) {
117 strcpy(script_name, paths[choice]);
119 *custom = choice >= max_std;
123 for (i = 0; i < max_std; i++)
128 static void run_script(char *cmd)
130 pr_debug("Running %s\n", cmd);
133 pr_warning("Cannot run %s\n", cmd);
135 * SLang doesn't seem to reset the whole terminal, so be more
136 * forceful to get back to the original state.
138 printf("\033[c\033[H\033[J");
140 SLang_init_tty(0, 0, 0);
144 int script_browse(const char *script_opt, struct perf_evsel *evsel)
146 char *cmd, script_name[SCRIPT_FULLPATH_LEN];
149 memset(script_name, 0, SCRIPT_FULLPATH_LEN);
150 if (list_scripts(script_name, &custom, evsel))
153 if (asprintf(&cmd, "%s%s %s %s%s 2>&1 | less",
154 custom ? "perf script -s " : "",
156 script_opt ? script_opt : "",
157 input_name ? "-i " : "",
158 input_name ? input_name : "") < 0)