Home | History | Annotate | Download | only in browsers
      1 #include <elf.h>
      2 #include <inttypes.h>
      3 #include <sys/ttydefaults.h>
      4 #include <string.h>
      5 #include "../../util/sort.h"
      6 #include "../../util/util.h"
      7 #include "../../util/hist.h"
      8 #include "../../util/debug.h"
      9 #include "../../util/symbol.h"
     10 #include "../browser.h"
     11 #include "../helpline.h"
     12 #include "../libslang.h"
     13 
     14 /* 2048 lines should be enough for a script output */
     15 #define MAX_LINES		2048
     16 
     17 /* 160 bytes for one output line */
     18 #define AVERAGE_LINE_LEN	160
     19 
     20 struct script_line {
     21 	struct list_head node;
     22 	char line[AVERAGE_LINE_LEN];
     23 };
     24 
     25 struct perf_script_browser {
     26 	struct ui_browser b;
     27 	struct list_head entries;
     28 	const char *script_name;
     29 	int nr_lines;
     30 };
     31 
     32 #define SCRIPT_NAMELEN	128
     33 #define SCRIPT_MAX_NO	64
     34 /*
     35  * Usually the full path for a script is:
     36  *	/home/username/libexec/perf-core/scripts/python/xxx.py
     37  *	/home/username/libexec/perf-core/scripts/perl/xxx.pl
     38  * So 256 should be long enough to contain the full path.
     39  */
     40 #define SCRIPT_FULLPATH_LEN	256
     41 
     42 /*
     43  * When success, will copy the full path of the selected script
     44  * into  the buffer pointed by script_name, and return 0.
     45  * Return -1 on failure.
     46  */
     47 static int list_scripts(char *script_name)
     48 {
     49 	char *buf, *names[SCRIPT_MAX_NO], *paths[SCRIPT_MAX_NO];
     50 	int i, num, choice, ret = -1;
     51 
     52 	/* Preset the script name to SCRIPT_NAMELEN */
     53 	buf = malloc(SCRIPT_MAX_NO * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN));
     54 	if (!buf)
     55 		return ret;
     56 
     57 	for (i = 0; i < SCRIPT_MAX_NO; i++) {
     58 		names[i] = buf + i * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN);
     59 		paths[i] = names[i] + SCRIPT_NAMELEN;
     60 	}
     61 
     62 	num = find_scripts(names, paths);
     63 	if (num > 0) {
     64 		choice = ui__popup_menu(num, names);
     65 		if (choice < num && choice >= 0) {
     66 			strcpy(script_name, paths[choice]);
     67 			ret = 0;
     68 		}
     69 	}
     70 
     71 	free(buf);
     72 	return ret;
     73 }
     74 
     75 static void script_browser__write(struct ui_browser *browser,
     76 				   void *entry, int row)
     77 {
     78 	struct script_line *sline = list_entry(entry, struct script_line, node);
     79 	bool current_entry = ui_browser__is_current_entry(browser, row);
     80 
     81 	ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
     82 						       HE_COLORSET_NORMAL);
     83 
     84 	slsmg_write_nstring(sline->line, browser->width);
     85 }
     86 
     87 static int script_browser__run(struct perf_script_browser *self)
     88 {
     89 	int key;
     90 
     91 	if (ui_browser__show(&self->b, self->script_name,
     92 			     "Press <- or ESC to exit") < 0)
     93 		return -1;
     94 
     95 	while (1) {
     96 		key = ui_browser__run(&self->b, 0);
     97 
     98 		/* We can add some special key handling here if needed */
     99 		break;
    100 	}
    101 
    102 	ui_browser__hide(&self->b);
    103 	return key;
    104 }
    105 
    106 
    107 int script_browse(const char *script_opt)
    108 {
    109 	char cmd[SCRIPT_FULLPATH_LEN*2], script_name[SCRIPT_FULLPATH_LEN];
    110 	char *line = NULL;
    111 	size_t len = 0;
    112 	ssize_t retlen;
    113 	int ret = -1, nr_entries = 0;
    114 	FILE *fp;
    115 	void *buf;
    116 	struct script_line *sline;
    117 
    118 	struct perf_script_browser script = {
    119 		.b = {
    120 			.refresh    = ui_browser__list_head_refresh,
    121 			.seek	    = ui_browser__list_head_seek,
    122 			.write	    = script_browser__write,
    123 		},
    124 		.script_name = script_name,
    125 	};
    126 
    127 	INIT_LIST_HEAD(&script.entries);
    128 
    129 	/* Save each line of the output in one struct script_line object. */
    130 	buf = zalloc((sizeof(*sline)) * MAX_LINES);
    131 	if (!buf)
    132 		return -1;
    133 	sline = buf;
    134 
    135 	memset(script_name, 0, SCRIPT_FULLPATH_LEN);
    136 	if (list_scripts(script_name))
    137 		goto exit;
    138 
    139 	sprintf(cmd, "perf script -s %s ", script_name);
    140 
    141 	if (script_opt)
    142 		strcat(cmd, script_opt);
    143 
    144 	if (input_name) {
    145 		strcat(cmd, " -i ");
    146 		strcat(cmd, input_name);
    147 	}
    148 
    149 	strcat(cmd, " 2>&1");
    150 
    151 	fp = popen(cmd, "r");
    152 	if (!fp)
    153 		goto exit;
    154 
    155 	while ((retlen = getline(&line, &len, fp)) != -1) {
    156 		strncpy(sline->line, line, AVERAGE_LINE_LEN);
    157 
    158 		/* If one output line is very large, just cut it short */
    159 		if (retlen >= AVERAGE_LINE_LEN) {
    160 			sline->line[AVERAGE_LINE_LEN - 1] = '\0';
    161 			sline->line[AVERAGE_LINE_LEN - 2] = '\n';
    162 		}
    163 		list_add_tail(&sline->node, &script.entries);
    164 
    165 		if (script.b.width < retlen)
    166 			script.b.width = retlen;
    167 
    168 		if (nr_entries++ >= MAX_LINES - 1)
    169 			break;
    170 		sline++;
    171 	}
    172 
    173 	if (script.b.width > AVERAGE_LINE_LEN)
    174 		script.b.width = AVERAGE_LINE_LEN;
    175 
    176 	if (line)
    177 		free(line);
    178 	pclose(fp);
    179 
    180 	script.nr_lines = nr_entries;
    181 	script.b.nr_entries = nr_entries;
    182 	script.b.entries = &script.entries;
    183 
    184 	ret = script_browser__run(&script);
    185 exit:
    186 	free(buf);
    187 	return ret;
    188 }
    189