123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- // SPDX-License-Identifier: GPL-2.0
- #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);
- ui_browser__write_nstring(browser, sline->line, browser->width);
- }
- static int script_browser__run(struct perf_script_browser *browser)
- {
- int key;
- if (ui_browser__show(&browser->b, browser->script_name,
- "Press ESC to exit") < 0)
- return -1;
- while (1) {
- key = ui_browser__run(&browser->b, 0);
- /* We can add some special key handling here if needed */
- break;
- }
- ui_browser__hide(&browser->b);
- 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;
- free(line);
- 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;
- }
|