| 
									
										
										
										
											2012-10-30 11:56:04 +08:00
										 |  |  | #include <elf.h>
 | 
					
						
							|  |  |  | #include <inttypes.h>
 | 
					
						
							|  |  |  | #include <sys/ttydefaults.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include "../../util/sort.h"
 | 
					
						
							|  |  |  | #include "../../util/util.h"
 | 
					
						
							|  |  |  | #include "../../util/hist.h"
 | 
					
						
							|  |  |  | #include "../../util/debug.h"
 | 
					
						
							|  |  |  | #include "../../util/symbol.h"
 | 
					
						
							|  |  |  | #include "../browser.h"
 | 
					
						
							|  |  |  | #include "../helpline.h"
 | 
					
						
							|  |  |  | #include "../libslang.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* 2048 lines should be enough for a script output */ | 
					
						
							|  |  |  | #define MAX_LINES		2048
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* 160 bytes for one output line */ | 
					
						
							|  |  |  | #define AVERAGE_LINE_LEN	160
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct script_line { | 
					
						
							|  |  |  | 	struct list_head node; | 
					
						
							|  |  |  | 	char line[AVERAGE_LINE_LEN]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct perf_script_browser { | 
					
						
							|  |  |  | 	struct ui_browser b; | 
					
						
							|  |  |  | 	struct list_head entries; | 
					
						
							|  |  |  | 	const char *script_name; | 
					
						
							|  |  |  | 	int nr_lines; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define SCRIPT_NAMELEN	128
 | 
					
						
							|  |  |  | #define SCRIPT_MAX_NO	64
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Usually the full path for a script is: | 
					
						
							|  |  |  |  *	/home/username/libexec/perf-core/scripts/python/xxx.py | 
					
						
							|  |  |  |  *	/home/username/libexec/perf-core/scripts/perl/xxx.pl | 
					
						
							|  |  |  |  * So 256 should be long enough to contain the full path. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #define SCRIPT_FULLPATH_LEN	256
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * When success, will copy the full path of the selected script | 
					
						
							|  |  |  |  * into  the buffer pointed by script_name, and return 0. | 
					
						
							|  |  |  |  * Return -1 on failure. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int list_scripts(char *script_name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char *buf, *names[SCRIPT_MAX_NO], *paths[SCRIPT_MAX_NO]; | 
					
						
							|  |  |  | 	int i, num, choice, ret = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Preset the script name to SCRIPT_NAMELEN */ | 
					
						
							|  |  |  | 	buf = malloc(SCRIPT_MAX_NO * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN)); | 
					
						
							|  |  |  | 	if (!buf) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < SCRIPT_MAX_NO; i++) { | 
					
						
							|  |  |  | 		names[i] = buf + i * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN); | 
					
						
							|  |  |  | 		paths[i] = names[i] + SCRIPT_NAMELEN; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	num = find_scripts(names, paths); | 
					
						
							|  |  |  | 	if (num > 0) { | 
					
						
							|  |  |  | 		choice = ui__popup_menu(num, names); | 
					
						
							|  |  |  | 		if (choice < num && choice >= 0) { | 
					
						
							|  |  |  | 			strcpy(script_name, paths[choice]); | 
					
						
							|  |  |  | 			ret = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	free(buf); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void script_browser__write(struct ui_browser *browser, | 
					
						
							|  |  |  | 				   void *entry, int row) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct script_line *sline = list_entry(entry, struct script_line, node); | 
					
						
							|  |  |  | 	bool current_entry = ui_browser__is_current_entry(browser, row); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : | 
					
						
							|  |  |  | 						       HE_COLORSET_NORMAL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	slsmg_write_nstring(sline->line, browser->width); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-05 15:32:36 -03:00
										 |  |  | static int script_browser__run(struct perf_script_browser *browser) | 
					
						
							| 
									
										
										
										
											2012-10-30 11:56:04 +08:00
										 |  |  | { | 
					
						
							|  |  |  | 	int key; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-05 15:32:36 -03:00
										 |  |  | 	if (ui_browser__show(&browser->b, browser->script_name, | 
					
						
							| 
									
										
										
										
											2012-10-30 11:56:04 +08:00
										 |  |  | 			     "Press <- or ESC to exit") < 0) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (1) { | 
					
						
							| 
									
										
										
										
											2013-11-05 15:32:36 -03:00
										 |  |  | 		key = ui_browser__run(&browser->b, 0); | 
					
						
							| 
									
										
										
										
											2012-10-30 11:56:04 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* We can add some special key handling here if needed */ | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-05 15:32:36 -03:00
										 |  |  | 	ui_browser__hide(&browser->b); | 
					
						
							| 
									
										
										
										
											2012-10-30 11:56:04 +08:00
										 |  |  | 	return key; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int script_browse(const char *script_opt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char cmd[SCRIPT_FULLPATH_LEN*2], script_name[SCRIPT_FULLPATH_LEN]; | 
					
						
							|  |  |  | 	char *line = NULL; | 
					
						
							|  |  |  | 	size_t len = 0; | 
					
						
							|  |  |  | 	ssize_t retlen; | 
					
						
							|  |  |  | 	int ret = -1, nr_entries = 0; | 
					
						
							|  |  |  | 	FILE *fp; | 
					
						
							|  |  |  | 	void *buf; | 
					
						
							|  |  |  | 	struct script_line *sline; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	struct perf_script_browser script = { | 
					
						
							|  |  |  | 		.b = { | 
					
						
							|  |  |  | 			.refresh    = ui_browser__list_head_refresh, | 
					
						
							|  |  |  | 			.seek	    = ui_browser__list_head_seek, | 
					
						
							|  |  |  | 			.write	    = script_browser__write, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		.script_name = script_name, | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	INIT_LIST_HEAD(&script.entries); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Save each line of the output in one struct script_line object. */ | 
					
						
							|  |  |  | 	buf = zalloc((sizeof(*sline)) * MAX_LINES); | 
					
						
							|  |  |  | 	if (!buf) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	sline = buf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memset(script_name, 0, SCRIPT_FULLPATH_LEN); | 
					
						
							|  |  |  | 	if (list_scripts(script_name)) | 
					
						
							|  |  |  | 		goto exit; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sprintf(cmd, "perf script -s %s ", script_name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (script_opt) | 
					
						
							|  |  |  | 		strcat(cmd, script_opt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (input_name) { | 
					
						
							|  |  |  | 		strcat(cmd, " -i "); | 
					
						
							|  |  |  | 		strcat(cmd, input_name); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	strcat(cmd, " 2>&1"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fp = popen(cmd, "r"); | 
					
						
							|  |  |  | 	if (!fp) | 
					
						
							|  |  |  | 		goto exit; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while ((retlen = getline(&line, &len, fp)) != -1) { | 
					
						
							|  |  |  | 		strncpy(sline->line, line, AVERAGE_LINE_LEN); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* If one output line is very large, just cut it short */ | 
					
						
							|  |  |  | 		if (retlen >= AVERAGE_LINE_LEN) { | 
					
						
							|  |  |  | 			sline->line[AVERAGE_LINE_LEN - 1] = '\0'; | 
					
						
							|  |  |  | 			sline->line[AVERAGE_LINE_LEN - 2] = '\n'; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		list_add_tail(&sline->node, &script.entries); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (script.b.width < retlen) | 
					
						
							|  |  |  | 			script.b.width = retlen; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (nr_entries++ >= MAX_LINES - 1) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		sline++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (script.b.width > AVERAGE_LINE_LEN) | 
					
						
							|  |  |  | 		script.b.width = AVERAGE_LINE_LEN; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-26 15:54:57 -03:00
										 |  |  | 	free(line); | 
					
						
							| 
									
										
										
										
											2012-10-30 11:56:04 +08:00
										 |  |  | 	pclose(fp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	script.nr_lines = nr_entries; | 
					
						
							|  |  |  | 	script.b.nr_entries = nr_entries; | 
					
						
							|  |  |  | 	script.b.entries = &script.entries; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = script_browser__run(&script); | 
					
						
							|  |  |  | exit: | 
					
						
							|  |  |  | 	free(buf); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } |