forked from luck/tmp_suning_uos_patched
d07126560c
With this patch if an optional pointer is passed to ui__popup_menu() then when any key that is not being handled (ENTER, ESC, etc) is typed, it'll record that key in the pointer and return, allowing for hotkey processing on the caller. If NULL is passed, no change in logic, unhandled keys continue to be ignored. Reviewed-by: Jiri Olsa <jolsa@kernel.org> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Jin Yao <yao.jin@linux.intel.com> Cc: Kan Liang <kan.liang@intel.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Namhyung Kim <namhyung@kernel.org> Link: https://lkml.kernel.org/n/tip-6ojn19mqzgmrdm8kdoigic0m@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
194 lines
4.9 KiB
C
194 lines
4.9 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include "../../builtin.h"
|
|
#include "../../perf.h"
|
|
#include "../../util/util.h" // perf_exe()
|
|
#include "../util.h"
|
|
#include "../../util/hist.h"
|
|
#include "../../util/debug.h"
|
|
#include "../../util/symbol.h"
|
|
#include "../browser.h"
|
|
#include "../libslang.h"
|
|
#include "config.h"
|
|
#include <linux/string.h>
|
|
#include <linux/zalloc.h>
|
|
#include <stdlib.h>
|
|
|
|
#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
|
|
|
|
struct script_config {
|
|
const char **names;
|
|
char **paths;
|
|
int index;
|
|
const char *perf;
|
|
char extra_format[256];
|
|
};
|
|
|
|
void attr_to_script(char *extra_format, struct perf_event_attr *attr)
|
|
{
|
|
extra_format[0] = 0;
|
|
if (attr->read_format & PERF_FORMAT_GROUP)
|
|
strcat(extra_format, " -F +metric");
|
|
if (attr->sample_type & PERF_SAMPLE_BRANCH_STACK)
|
|
strcat(extra_format, " -F +brstackinsn --xed");
|
|
if (attr->sample_type & PERF_SAMPLE_REGS_INTR)
|
|
strcat(extra_format, " -F +iregs");
|
|
if (attr->sample_type & PERF_SAMPLE_REGS_USER)
|
|
strcat(extra_format, " -F +uregs");
|
|
if (attr->sample_type & PERF_SAMPLE_PHYS_ADDR)
|
|
strcat(extra_format, " -F +phys_addr");
|
|
}
|
|
|
|
static int add_script_option(const char *name, const char *opt,
|
|
struct script_config *c)
|
|
{
|
|
c->names[c->index] = name;
|
|
if (asprintf(&c->paths[c->index],
|
|
"%s script %s -F +metric %s %s",
|
|
c->perf, opt, symbol_conf.inline_name ? " --inline" : "",
|
|
c->extra_format) < 0)
|
|
return -1;
|
|
c->index++;
|
|
return 0;
|
|
}
|
|
|
|
static int scripts_config(const char *var, const char *value, void *data)
|
|
{
|
|
struct script_config *c = data;
|
|
|
|
if (!strstarts(var, "scripts."))
|
|
return -1;
|
|
if (c->index >= SCRIPT_MAX_NO)
|
|
return -1;
|
|
c->names[c->index] = strdup(var + 7);
|
|
if (!c->names[c->index])
|
|
return -1;
|
|
if (asprintf(&c->paths[c->index], "%s %s", value,
|
|
c->extra_format) < 0)
|
|
return -1;
|
|
c->index++;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* 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, bool *custom,
|
|
struct evsel *evsel)
|
|
{
|
|
char *buf, *paths[SCRIPT_MAX_NO], *names[SCRIPT_MAX_NO];
|
|
int i, num, choice;
|
|
int ret = 0;
|
|
int max_std, custom_perf;
|
|
char pbuf[256];
|
|
const char *perf = perf_exe(pbuf, sizeof pbuf);
|
|
struct script_config scriptc = {
|
|
.names = (const char **)names,
|
|
.paths = paths,
|
|
.perf = perf
|
|
};
|
|
|
|
script_name[0] = 0;
|
|
|
|
/* Preset the script name to SCRIPT_NAMELEN */
|
|
buf = malloc(SCRIPT_MAX_NO * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN));
|
|
if (!buf)
|
|
return -1;
|
|
|
|
if (evsel)
|
|
attr_to_script(scriptc.extra_format, &evsel->core.attr);
|
|
add_script_option("Show individual samples", "", &scriptc);
|
|
add_script_option("Show individual samples with assembler", "-F +insn --xed",
|
|
&scriptc);
|
|
add_script_option("Show individual samples with source", "-F +srcline,+srccode",
|
|
&scriptc);
|
|
perf_config(scripts_config, &scriptc);
|
|
custom_perf = scriptc.index;
|
|
add_script_option("Show samples with custom perf script arguments", "", &scriptc);
|
|
i = scriptc.index;
|
|
max_std = i;
|
|
|
|
for (; i < SCRIPT_MAX_NO; i++) {
|
|
names[i] = buf + (i - max_std) * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN);
|
|
paths[i] = names[i] + SCRIPT_NAMELEN;
|
|
}
|
|
|
|
num = find_scripts(names + max_std, paths + max_std, SCRIPT_MAX_NO - max_std,
|
|
SCRIPT_FULLPATH_LEN);
|
|
if (num < 0)
|
|
num = 0;
|
|
choice = ui__popup_menu(num + max_std, (char * const *)names, NULL);
|
|
if (choice < 0) {
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
if (choice == custom_perf) {
|
|
char script_args[50];
|
|
int key = ui_browser__input_window("perf script command",
|
|
"Enter perf script command line (without perf script prefix)",
|
|
script_args, "", 0);
|
|
if (key != K_ENTER) {
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
sprintf(script_name, "%s script %s", perf, script_args);
|
|
} else if (choice < num + max_std) {
|
|
strcpy(script_name, paths[choice]);
|
|
}
|
|
*custom = choice >= max_std;
|
|
|
|
out:
|
|
free(buf);
|
|
for (i = 0; i < max_std; i++)
|
|
zfree(&paths[i]);
|
|
return ret;
|
|
}
|
|
|
|
void run_script(char *cmd)
|
|
{
|
|
pr_debug("Running %s\n", cmd);
|
|
SLang_reset_tty();
|
|
if (system(cmd) < 0)
|
|
pr_warning("Cannot run %s\n", cmd);
|
|
/*
|
|
* SLang doesn't seem to reset the whole terminal, so be more
|
|
* forceful to get back to the original state.
|
|
*/
|
|
printf("\033[c\033[H\033[J");
|
|
fflush(stdout);
|
|
SLang_init_tty(0, 0, 0);
|
|
SLsmg_refresh();
|
|
}
|
|
|
|
int script_browse(const char *script_opt, struct evsel *evsel)
|
|
{
|
|
char *cmd, script_name[SCRIPT_FULLPATH_LEN];
|
|
bool custom = false;
|
|
|
|
memset(script_name, 0, SCRIPT_FULLPATH_LEN);
|
|
if (list_scripts(script_name, &custom, evsel))
|
|
return -1;
|
|
|
|
if (asprintf(&cmd, "%s%s %s %s%s 2>&1 | less",
|
|
custom ? "perf script -s " : "",
|
|
script_name,
|
|
script_opt ? script_opt : "",
|
|
input_name ? "-i " : "",
|
|
input_name ? input_name : "") < 0)
|
|
return -1;
|
|
|
|
run_script(cmd);
|
|
free(cmd);
|
|
|
|
return 0;
|
|
}
|