xref: /linux/tools/perf/ui/browsers/scripts.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2185bcb92SArnaldo Carvalho de Melo #include "../../builtin.h"
3c1a604dfSArnaldo Carvalho de Melo #include "../../perf.h"
4fb71c86cSArnaldo Carvalho de Melo #include "../../util/util.h" // perf_exe()
5b22bb139SArnaldo Carvalho de Melo #include "../util.h"
666517826SFeng Tang #include "../../util/hist.h"
766517826SFeng Tang #include "../../util/debug.h"
866517826SFeng Tang #include "../../util/symbol.h"
966517826SFeng Tang #include "../browser.h"
1066517826SFeng Tang #include "../libslang.h"
11e3b74de5SAndi Kleen #include "config.h"
128520a98dSArnaldo Carvalho de Melo #include <linux/string.h>
13d8f9da24SArnaldo Carvalho de Melo #include <linux/zalloc.h>
14f2a39fe8SArnaldo Carvalho de Melo #include <stdlib.h>
1566517826SFeng Tang 
1666517826SFeng Tang #define SCRIPT_NAMELEN	128
1766517826SFeng Tang #define SCRIPT_MAX_NO	64
1866517826SFeng Tang /*
1966517826SFeng Tang  * Usually the full path for a script is:
2066517826SFeng Tang  *	/home/username/libexec/perf-core/scripts/python/xxx.py
2166517826SFeng Tang  *	/home/username/libexec/perf-core/scripts/perl/xxx.pl
2266517826SFeng Tang  * So 256 should be long enough to contain the full path.
2366517826SFeng Tang  */
2466517826SFeng Tang #define SCRIPT_FULLPATH_LEN	256
2566517826SFeng Tang 
266f3da20eSAndi Kleen struct script_config {
276f3da20eSAndi Kleen 	const char **names;
286f3da20eSAndi Kleen 	char **paths;
296f3da20eSAndi Kleen 	int index;
306f3da20eSAndi Kleen 	const char *perf;
316f3da20eSAndi Kleen 	char extra_format[256];
326f3da20eSAndi Kleen };
336f3da20eSAndi Kleen 
attr_to_script(char * extra_format,struct perf_event_attr * attr)346f3da20eSAndi Kleen void attr_to_script(char *extra_format, struct perf_event_attr *attr)
356f3da20eSAndi Kleen {
366f3da20eSAndi Kleen 	extra_format[0] = 0;
376f3da20eSAndi Kleen 	if (attr->read_format & PERF_FORMAT_GROUP)
386f3da20eSAndi Kleen 		strcat(extra_format, " -F +metric");
396f3da20eSAndi Kleen 	if (attr->sample_type & PERF_SAMPLE_BRANCH_STACK)
406f3da20eSAndi Kleen 		strcat(extra_format, " -F +brstackinsn --xed");
416f3da20eSAndi Kleen 	if (attr->sample_type & PERF_SAMPLE_REGS_INTR)
426f3da20eSAndi Kleen 		strcat(extra_format, " -F +iregs");
436f3da20eSAndi Kleen 	if (attr->sample_type & PERF_SAMPLE_REGS_USER)
446f3da20eSAndi Kleen 		strcat(extra_format, " -F +uregs");
456f3da20eSAndi Kleen 	if (attr->sample_type & PERF_SAMPLE_PHYS_ADDR)
466f3da20eSAndi Kleen 		strcat(extra_format, " -F +phys_addr");
476f3da20eSAndi Kleen }
486f3da20eSAndi Kleen 
add_script_option(const char * name,const char * opt,struct script_config * c)496f3da20eSAndi Kleen static int add_script_option(const char *name, const char *opt,
506f3da20eSAndi Kleen 			     struct script_config *c)
516f3da20eSAndi Kleen {
526f3da20eSAndi Kleen 	c->names[c->index] = name;
536f3da20eSAndi Kleen 	if (asprintf(&c->paths[c->index],
546f3da20eSAndi Kleen 		     "%s script %s -F +metric %s %s",
556f3da20eSAndi Kleen 		     c->perf, opt, symbol_conf.inline_name ? " --inline" : "",
566f3da20eSAndi Kleen 		     c->extra_format) < 0)
576f3da20eSAndi Kleen 		return -1;
586f3da20eSAndi Kleen 	c->index++;
596f3da20eSAndi Kleen 	return 0;
606f3da20eSAndi Kleen }
616f3da20eSAndi Kleen 
scripts_config(const char * var,const char * value,void * data)62e3b74de5SAndi Kleen static int scripts_config(const char *var, const char *value, void *data)
63e3b74de5SAndi Kleen {
64e3b74de5SAndi Kleen 	struct script_config *c = data;
65e3b74de5SAndi Kleen 
66e3b74de5SAndi Kleen 	if (!strstarts(var, "scripts."))
67e3b74de5SAndi Kleen 		return -1;
68e3b74de5SAndi Kleen 	if (c->index >= SCRIPT_MAX_NO)
69e3b74de5SAndi Kleen 		return -1;
70e3b74de5SAndi Kleen 	c->names[c->index] = strdup(var + 7);
71e3b74de5SAndi Kleen 	if (!c->names[c->index])
72e3b74de5SAndi Kleen 		return -1;
73e3b74de5SAndi Kleen 	if (asprintf(&c->paths[c->index], "%s %s", value,
74e3b74de5SAndi Kleen 		     c->extra_format) < 0)
75e3b74de5SAndi Kleen 		return -1;
76e3b74de5SAndi Kleen 	c->index++;
77e3b74de5SAndi Kleen 	return 0;
78e3b74de5SAndi Kleen }
79e3b74de5SAndi Kleen 
8066517826SFeng Tang /*
8166517826SFeng Tang  * When success, will copy the full path of the selected script
8266517826SFeng Tang  * into  the buffer pointed by script_name, and return 0.
8366517826SFeng Tang  * Return -1 on failure.
8466517826SFeng Tang  */
list_scripts(char * script_name,bool * custom,struct evsel * evsel)856f3da20eSAndi Kleen static int list_scripts(char *script_name, bool *custom,
8632dcd021SJiri Olsa 			struct evsel *evsel)
8766517826SFeng Tang {
886f3da20eSAndi Kleen 	char *buf, *paths[SCRIPT_MAX_NO], *names[SCRIPT_MAX_NO];
896f3da20eSAndi Kleen 	int i, num, choice;
906f3da20eSAndi Kleen 	int ret = 0;
916f3da20eSAndi Kleen 	int max_std, custom_perf;
926f3da20eSAndi Kleen 	char pbuf[256];
936f3da20eSAndi Kleen 	const char *perf = perf_exe(pbuf, sizeof pbuf);
946f3da20eSAndi Kleen 	struct script_config scriptc = {
956f3da20eSAndi Kleen 		.names = (const char **)names,
966f3da20eSAndi Kleen 		.paths = paths,
976f3da20eSAndi Kleen 		.perf = perf
986f3da20eSAndi Kleen 	};
996f3da20eSAndi Kleen 
1006f3da20eSAndi Kleen 	script_name[0] = 0;
10166517826SFeng Tang 
10266517826SFeng Tang 	/* Preset the script name to SCRIPT_NAMELEN */
10366517826SFeng Tang 	buf = malloc(SCRIPT_MAX_NO * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN));
10466517826SFeng Tang 	if (!buf)
1056f3da20eSAndi Kleen 		return -1;
10666517826SFeng Tang 
1076f3da20eSAndi Kleen 	if (evsel)
1081fc632ceSJiri Olsa 		attr_to_script(scriptc.extra_format, &evsel->core.attr);
1096f3da20eSAndi Kleen 	add_script_option("Show individual samples", "", &scriptc);
110*659663f0SChangbin Du 	add_script_option("Show individual samples with assembler", "-F +disasm",
1116f3da20eSAndi Kleen 			  &scriptc);
1126f3da20eSAndi Kleen 	add_script_option("Show individual samples with source", "-F +srcline,+srccode",
1136f3da20eSAndi Kleen 			  &scriptc);
114e3b74de5SAndi Kleen 	perf_config(scripts_config, &scriptc);
1156f3da20eSAndi Kleen 	custom_perf = scriptc.index;
1166f3da20eSAndi Kleen 	add_script_option("Show samples with custom perf script arguments", "", &scriptc);
1176f3da20eSAndi Kleen 	i = scriptc.index;
1186f3da20eSAndi Kleen 	max_std = i;
1196f3da20eSAndi Kleen 
1206f3da20eSAndi Kleen 	for (; i < SCRIPT_MAX_NO; i++) {
1216f3da20eSAndi Kleen 		names[i] = buf + (i - max_std) * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN);
12266517826SFeng Tang 		paths[i] = names[i] + SCRIPT_NAMELEN;
12366517826SFeng Tang 	}
12466517826SFeng Tang 
125905e4affSAndi Kleen 	num = find_scripts(names + max_std, paths + max_std, SCRIPT_MAX_NO - max_std,
126905e4affSAndi Kleen 			SCRIPT_FULLPATH_LEN);
1276f3da20eSAndi Kleen 	if (num < 0)
1286f3da20eSAndi Kleen 		num = 0;
129d0712656SArnaldo Carvalho de Melo 	choice = ui__popup_menu(num + max_std, (char * const *)names, NULL);
1306f3da20eSAndi Kleen 	if (choice < 0) {
1316f3da20eSAndi Kleen 		ret = -1;
1326f3da20eSAndi Kleen 		goto out;
1336f3da20eSAndi Kleen 	}
1346f3da20eSAndi Kleen 	if (choice == custom_perf) {
1356f3da20eSAndi Kleen 		char script_args[50];
1366f3da20eSAndi Kleen 		int key = ui_browser__input_window("perf script command",
1376f3da20eSAndi Kleen 				"Enter perf script command line (without perf script prefix)",
1386f3da20eSAndi Kleen 				script_args, "", 0);
1393b4acbb9SGustavo A. R. Silva 		if (key != K_ENTER) {
1403b4acbb9SGustavo A. R. Silva 			ret = -1;
1413b4acbb9SGustavo A. R. Silva 			goto out;
1423b4acbb9SGustavo A. R. Silva 		}
1436f3da20eSAndi Kleen 		sprintf(script_name, "%s script %s", perf, script_args);
1446f3da20eSAndi Kleen 	} else if (choice < num + max_std) {
14566517826SFeng Tang 		strcpy(script_name, paths[choice]);
14666517826SFeng Tang 	}
1476f3da20eSAndi Kleen 	*custom = choice >= max_std;
14866517826SFeng Tang 
1496f3da20eSAndi Kleen out:
15066517826SFeng Tang 	free(buf);
1516f3da20eSAndi Kleen 	for (i = 0; i < max_std; i++)
152d8f9da24SArnaldo Carvalho de Melo 		zfree(&paths[i]);
15366517826SFeng Tang 	return ret;
15466517826SFeng Tang }
15566517826SFeng Tang 
run_script(char * cmd)1564968ac8fSAndi Kleen void run_script(char *cmd)
15766517826SFeng Tang {
15875065a85SAndi Kleen 	pr_debug("Running %s\n", cmd);
15975065a85SAndi Kleen 	SLang_reset_tty();
16075065a85SAndi Kleen 	if (system(cmd) < 0)
16175065a85SAndi Kleen 		pr_warning("Cannot run %s\n", cmd);
16275065a85SAndi Kleen 	/*
16375065a85SAndi Kleen 	 * SLang doesn't seem to reset the whole terminal, so be more
16475065a85SAndi Kleen 	 * forceful to get back to the original state.
16575065a85SAndi Kleen 	 */
16675065a85SAndi Kleen 	printf("\033[c\033[H\033[J");
16775065a85SAndi Kleen 	fflush(stdout);
16875065a85SAndi Kleen 	SLang_init_tty(0, 0, 0);
1696af6d224SAhelenia Ziemiańska 	SLtty_set_suspend_state(true);
17075065a85SAndi Kleen 	SLsmg_refresh();
17166517826SFeng Tang }
17266517826SFeng Tang 
script_browse(const char * script_opt,struct evsel * evsel)17332dcd021SJiri Olsa int script_browse(const char *script_opt, struct evsel *evsel)
17466517826SFeng Tang {
1756f3da20eSAndi Kleen 	char *cmd, script_name[SCRIPT_FULLPATH_LEN];
1766f3da20eSAndi Kleen 	bool custom = false;
17766517826SFeng Tang 
17866517826SFeng Tang 	memset(script_name, 0, SCRIPT_FULLPATH_LEN);
1796f3da20eSAndi Kleen 	if (list_scripts(script_name, &custom, evsel))
18075065a85SAndi Kleen 		return -1;
18166517826SFeng Tang 
1826f3da20eSAndi Kleen 	if (asprintf(&cmd, "%s%s %s %s%s 2>&1 | less",
1836f3da20eSAndi Kleen 			custom ? "perf script -s " : "",
1846f3da20eSAndi Kleen 			script_name,
1856f3da20eSAndi Kleen 			script_opt ? script_opt : "",
1866f3da20eSAndi Kleen 			input_name ? "-i " : "",
1876f3da20eSAndi Kleen 			input_name ? input_name : "") < 0)
1886f3da20eSAndi Kleen 		return -1;
18966517826SFeng Tang 
19075065a85SAndi Kleen 	run_script(cmd);
1916f3da20eSAndi Kleen 	free(cmd);
19266517826SFeng Tang 
19375065a85SAndi Kleen 	return 0;
19466517826SFeng Tang }
195