Commit a3277d2d authored by Frederic Weisbecker's avatar Frederic Weisbecker Committed by Arnaldo Carvalho de Melo

perf tools: Support for events bash completion

Add basic bash completion for the -e option in record, top and stat
subcommands. Only hardware, software and tracepoint events are
supported.

Breakpoints, raw events and events grouping completion need more
thinking.
Signed-off-by: default avatarFrederic Weisbecker <fweisbec@gmail.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1344522713-27951-3-git-send-email-fweisbec@gmail.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 98a4179c
...@@ -6,7 +6,7 @@ _perf() ...@@ -6,7 +6,7 @@ _perf()
local cur cmd local cur cmd
COMPREPLY=() COMPREPLY=()
_get_comp_words_by_ref cur _get_comp_words_by_ref cur prev
cmd=${COMP_WORDS[0]} cmd=${COMP_WORDS[0]}
...@@ -14,6 +14,10 @@ _perf() ...@@ -14,6 +14,10 @@ _perf()
if [ $COMP_CWORD -eq 1 ]; then if [ $COMP_CWORD -eq 1 ]; then
cmds=$($cmd --list-cmds) cmds=$($cmd --list-cmds)
COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) ) COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) )
# List possible events for -e option
elif [[ $prev == "-e" && "${COMP_WORDS[1]}" == @(record|stat|top) ]]; then
cmds=$($cmd list --raw-dump)
COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) )
# Fall down to list regular files # Fall down to list regular files
else else
_filedir _filedir
......
...@@ -19,15 +19,15 @@ int cmd_list(int argc, const char **argv, const char *prefix __used) ...@@ -19,15 +19,15 @@ int cmd_list(int argc, const char **argv, const char *prefix __used)
setup_pager(); setup_pager();
if (argc == 1) if (argc == 1)
print_events(NULL); print_events(NULL, false);
else { else {
int i; int i;
for (i = 1; i < argc; ++i) { for (i = 1; i < argc; ++i) {
if (i > 1) if (i > 2)
putchar('\n'); putchar('\n');
if (strncmp(argv[i], "tracepoint", 10) == 0) if (strncmp(argv[i], "tracepoint", 10) == 0)
print_tracepoint_events(NULL, NULL); print_tracepoint_events(NULL, NULL, false);
else if (strcmp(argv[i], "hw") == 0 || else if (strcmp(argv[i], "hw") == 0 ||
strcmp(argv[i], "hardware") == 0) strcmp(argv[i], "hardware") == 0)
print_events_type(PERF_TYPE_HARDWARE); print_events_type(PERF_TYPE_HARDWARE);
...@@ -36,13 +36,15 @@ int cmd_list(int argc, const char **argv, const char *prefix __used) ...@@ -36,13 +36,15 @@ int cmd_list(int argc, const char **argv, const char *prefix __used)
print_events_type(PERF_TYPE_SOFTWARE); print_events_type(PERF_TYPE_SOFTWARE);
else if (strcmp(argv[i], "cache") == 0 || else if (strcmp(argv[i], "cache") == 0 ||
strcmp(argv[i], "hwcache") == 0) strcmp(argv[i], "hwcache") == 0)
print_hwcache_events(NULL); print_hwcache_events(NULL, false);
else if (strcmp(argv[i], "--raw-dump") == 0)
print_events(NULL, true);
else { else {
char *sep = strchr(argv[i], ':'), *s; char *sep = strchr(argv[i], ':'), *s;
int sep_idx; int sep_idx;
if (sep == NULL) { if (sep == NULL) {
print_events(argv[i]); print_events(argv[i], false);
continue; continue;
} }
sep_idx = sep - argv[i]; sep_idx = sep - argv[i];
...@@ -51,7 +53,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __used) ...@@ -51,7 +53,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __used)
return -1; return -1;
s[sep_idx] = '\0'; s[sep_idx] = '\0';
print_tracepoint_events(s, s + sep_idx + 1); print_tracepoint_events(s, s + sep_idx + 1, false);
free(s); free(s);
} }
} }
......
...@@ -799,7 +799,8 @@ static const char * const event_type_descriptors[] = { ...@@ -799,7 +799,8 @@ static const char * const event_type_descriptors[] = {
* Print the events from <debugfs_mount_point>/tracing/events * Print the events from <debugfs_mount_point>/tracing/events
*/ */
void print_tracepoint_events(const char *subsys_glob, const char *event_glob) void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
bool name_only)
{ {
DIR *sys_dir, *evt_dir; DIR *sys_dir, *evt_dir;
struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
...@@ -829,6 +830,11 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob) ...@@ -829,6 +830,11 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob)
!strglobmatch(evt_dirent.d_name, event_glob)) !strglobmatch(evt_dirent.d_name, event_glob))
continue; continue;
if (name_only) {
printf("%s:%s ", sys_dirent.d_name, evt_dirent.d_name);
continue;
}
snprintf(evt_path, MAXPATHLEN, "%s:%s", snprintf(evt_path, MAXPATHLEN, "%s:%s",
sys_dirent.d_name, evt_dirent.d_name); sys_dirent.d_name, evt_dirent.d_name);
printf(" %-50s [%s]\n", evt_path, printf(" %-50s [%s]\n", evt_path,
...@@ -906,7 +912,7 @@ void print_events_type(u8 type) ...@@ -906,7 +912,7 @@ void print_events_type(u8 type)
__print_events_type(type, event_symbols_hw, PERF_COUNT_HW_MAX); __print_events_type(type, event_symbols_hw, PERF_COUNT_HW_MAX);
} }
int print_hwcache_events(const char *event_glob) int print_hwcache_events(const char *event_glob, bool name_only)
{ {
unsigned int type, op, i, printed = 0; unsigned int type, op, i, printed = 0;
char name[64]; char name[64];
...@@ -923,8 +929,11 @@ int print_hwcache_events(const char *event_glob) ...@@ -923,8 +929,11 @@ int print_hwcache_events(const char *event_glob)
if (event_glob != NULL && !strglobmatch(name, event_glob)) if (event_glob != NULL && !strglobmatch(name, event_glob))
continue; continue;
printf(" %-50s [%s]\n", name, if (name_only)
event_type_descriptors[PERF_TYPE_HW_CACHE]); printf("%s ", name);
else
printf(" %-50s [%s]\n", name,
event_type_descriptors[PERF_TYPE_HW_CACHE]);
++printed; ++printed;
} }
} }
...@@ -934,7 +943,8 @@ int print_hwcache_events(const char *event_glob) ...@@ -934,7 +943,8 @@ int print_hwcache_events(const char *event_glob)
} }
static void print_symbol_events(const char *event_glob, unsigned type, static void print_symbol_events(const char *event_glob, unsigned type,
struct event_symbol *syms, unsigned max) struct event_symbol *syms, unsigned max,
bool name_only)
{ {
unsigned i, printed = 0; unsigned i, printed = 0;
char name[MAX_NAME_LEN]; char name[MAX_NAME_LEN];
...@@ -946,6 +956,11 @@ static void print_symbol_events(const char *event_glob, unsigned type, ...@@ -946,6 +956,11 @@ static void print_symbol_events(const char *event_glob, unsigned type,
(syms->alias && strglobmatch(syms->alias, event_glob)))) (syms->alias && strglobmatch(syms->alias, event_glob))))
continue; continue;
if (name_only) {
printf("%s ", syms->symbol);
continue;
}
if (strlen(syms->alias)) if (strlen(syms->alias))
snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias);
else else
...@@ -963,39 +978,42 @@ static void print_symbol_events(const char *event_glob, unsigned type, ...@@ -963,39 +978,42 @@ static void print_symbol_events(const char *event_glob, unsigned type,
/* /*
* Print the help text for the event symbols: * Print the help text for the event symbols:
*/ */
void print_events(const char *event_glob) void print_events(const char *event_glob, bool name_only)
{ {
if (!name_only) {
printf("\n"); printf("\n");
printf("List of pre-defined events (to be used in -e):\n"); printf("List of pre-defined events (to be used in -e):\n");
}
print_symbol_events(event_glob, PERF_TYPE_HARDWARE, print_symbol_events(event_glob, PERF_TYPE_HARDWARE,
event_symbols_hw, PERF_COUNT_HW_MAX); event_symbols_hw, PERF_COUNT_HW_MAX, name_only);
print_symbol_events(event_glob, PERF_TYPE_SOFTWARE, print_symbol_events(event_glob, PERF_TYPE_SOFTWARE,
event_symbols_sw, PERF_COUNT_SW_MAX); event_symbols_sw, PERF_COUNT_SW_MAX, name_only);
print_hwcache_events(event_glob); print_hwcache_events(event_glob, name_only);
if (event_glob != NULL) if (event_glob != NULL)
return; return;
printf("\n"); if (!name_only) {
printf(" %-50s [%s]\n", printf("\n");
"rNNN", printf(" %-50s [%s]\n",
event_type_descriptors[PERF_TYPE_RAW]); "rNNN",
printf(" %-50s [%s]\n", event_type_descriptors[PERF_TYPE_RAW]);
"cpu/t1=v1[,t2=v2,t3 ...]/modifier", printf(" %-50s [%s]\n",
event_type_descriptors[PERF_TYPE_RAW]); "cpu/t1=v1[,t2=v2,t3 ...]/modifier",
printf(" (see 'perf list --help' on how to encode it)\n"); event_type_descriptors[PERF_TYPE_RAW]);
printf("\n"); printf(" (see 'perf list --help' on how to encode it)\n");
printf("\n");
printf(" %-50s [%s]\n",
"mem:<addr>[:access]", printf(" %-50s [%s]\n",
"mem:<addr>[:access]",
event_type_descriptors[PERF_TYPE_BREAKPOINT]); event_type_descriptors[PERF_TYPE_BREAKPOINT]);
printf("\n"); printf("\n");
}
print_tracepoint_events(NULL, NULL); print_tracepoint_events(NULL, NULL, name_only);
} }
int parse_events__is_hardcoded_term(struct parse_events__term *term) int parse_events__is_hardcoded_term(struct parse_events__term *term)
......
...@@ -96,10 +96,11 @@ void parse_events_update_lists(struct list_head *list_event, ...@@ -96,10 +96,11 @@ void parse_events_update_lists(struct list_head *list_event,
void parse_events_error(void *data, void *scanner, char const *msg); void parse_events_error(void *data, void *scanner, char const *msg);
int parse_events__test(void); int parse_events__test(void);
void print_events(const char *event_glob); void print_events(const char *event_glob, bool name_only);
void print_events_type(u8 type); void print_events_type(u8 type);
void print_tracepoint_events(const char *subsys_glob, const char *event_glob); void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
int print_hwcache_events(const char *event_glob); bool name_only);
int print_hwcache_events(const char *event_glob, bool name_only);
extern int is_valid_tracepoint(const char *event_string); extern int is_valid_tracepoint(const char *event_string);
extern int valid_debugfs_mount(const char *debugfs); extern int valid_debugfs_mount(const char *debugfs);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment