Commit ab0e4800 authored by Yunlong Song's avatar Yunlong Song Committed by Arnaldo Carvalho de Melo

perf list: Sort the output of 'perf list' to view more clearly

Sort the output according to ASCII character list (using strcmp), which
supports both number sequence and alphabet sequence.

Example:

Before this patch:

 $ perf list

 List of pre-defined events (to be used in -e):
   cpu-cycles OR cycles                               [Hardware event]
   instructions                                       [Hardware event]
   cache-references                                   [Hardware event]
   cache-misses                                       [Hardware event]
   branch-instructions OR branches                    [Hardware event]
   branch-misses                                      [Hardware event]
   bus-cycles                                         [Hardware event]
   ...                                                ...

   jbd2:jbd2_start_commit                             [Tracepoint event]
   jbd2:jbd2_commit_locking                           [Tracepoint event]
   jbd2:jbd2_run_stats                                [Tracepoint event]
   block:block_rq_issue                               [Tracepoint event]
   block:block_bio_complete                           [Tracepoint event]
   block:block_bio_backmerge                          [Tracepoint event]
   block:block_getrq                                  [Tracepoint event]
   ...                                                ...

After this patch:

 $ perf list

 List of pre-defined events (to be used in -e):
   branch-instructions OR branches                    [Hardware event]
   branch-misses                                      [Hardware event]
   bus-cycles                                         [Hardware event]
   cache-misses                                       [Hardware event]
   cache-references                                   [Hardware event]
   cpu-cycles OR cycles                               [Hardware event]
   instructions                                       [Hardware event]
   ...                                                ...

   block:block_bio_backmerge                          [Tracepoint event]
   block:block_bio_complete                           [Tracepoint event]
   block:block_getrq                                  [Tracepoint event]
   block:block_rq_issue                               [Tracepoint event]
   jbd2:jbd2_commit_locking                           [Tracepoint event]
   jbd2:jbd2_run_stats                                [Tracepoint event]
   jbd2:jbd2_start_commit                             [Tracepoint event]
   ...                                                ...
Signed-off-by: default avatarYunlong Song <yunlong.song@huawei.com>
Tested-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/r/1425032491-20224-2-git-send-email-yunlong.song@huawei.com
[ Don't forget closedir({sys,evt}_dir) when handling errors ]
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 1f924c29
...@@ -1089,6 +1089,14 @@ static const char * const event_type_descriptors[] = { ...@@ -1089,6 +1089,14 @@ static const char * const event_type_descriptors[] = {
"Hardware breakpoint", "Hardware breakpoint",
}; };
static int cmp_string(const void *a, const void *b)
{
const char * const *as = a;
const char * const *bs = b;
return strcmp(*as, *bs);
}
/* /*
* Print the events from <debugfs_mount_point>/tracing/events * Print the events from <debugfs_mount_point>/tracing/events
*/ */
...@@ -1100,11 +1108,21 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob, ...@@ -1100,11 +1108,21 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
char evt_path[MAXPATHLEN]; char evt_path[MAXPATHLEN];
char dir_path[MAXPATHLEN]; char dir_path[MAXPATHLEN];
char **evt_list = NULL;
unsigned int evt_i = 0, evt_num = 0;
bool evt_num_known = false;
restart:
sys_dir = opendir(tracing_events_path); sys_dir = opendir(tracing_events_path);
if (!sys_dir) if (!sys_dir)
return; return;
if (evt_num_known) {
evt_list = zalloc(sizeof(char *) * evt_num);
if (!evt_list)
goto out_close_sys_dir;
}
for_each_subsystem(sys_dir, sys_dirent, sys_next) { for_each_subsystem(sys_dir, sys_dirent, sys_next) {
if (subsys_glob != NULL && if (subsys_glob != NULL &&
!strglobmatch(sys_dirent.d_name, subsys_glob)) !strglobmatch(sys_dirent.d_name, subsys_glob))
...@@ -1121,19 +1139,56 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob, ...@@ -1121,19 +1139,56 @@ 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) { if (!evt_num_known) {
printf("%s:%s ", sys_dirent.d_name, evt_dirent.d_name); evt_num++;
continue; 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,
event_type_descriptors[PERF_TYPE_TRACEPOINT]); evt_list[evt_i] = strdup(evt_path);
if (evt_list[evt_i] == NULL)
goto out_close_evt_dir;
evt_i++;
} }
closedir(evt_dir); closedir(evt_dir);
} }
closedir(sys_dir); closedir(sys_dir);
if (!evt_num_known) {
evt_num_known = true;
goto restart;
}
qsort(evt_list, evt_num, sizeof(char *), cmp_string);
evt_i = 0;
while (evt_i < evt_num) {
if (name_only) {
printf("%s ", evt_list[evt_i++]);
continue;
}
printf(" %-50s [%s]\n", evt_list[evt_i++],
event_type_descriptors[PERF_TYPE_TRACEPOINT]);
}
if (evt_num)
printf("\n");
out_free:
evt_num = evt_i;
for (evt_i = 0; evt_i < evt_num; evt_i++)
zfree(&evt_list[evt_i]);
zfree(&evt_list);
return;
out_close_evt_dir:
closedir(evt_dir);
out_close_sys_dir:
closedir(sys_dir);
printf("FATAL: not enough memory to print %s\n",
event_type_descriptors[PERF_TYPE_TRACEPOINT]);
if (evt_list)
goto out_free;
} }
/* /*
...@@ -1218,20 +1273,61 @@ static void __print_events_type(u8 type, struct event_symbol *syms, ...@@ -1218,20 +1273,61 @@ static void __print_events_type(u8 type, struct event_symbol *syms,
unsigned max) unsigned max)
{ {
char name[64]; char name[64];
unsigned i; unsigned int i, evt_i = 0, evt_num = 0;
char **evt_list = NULL;
bool evt_num_known = false;
restart:
if (evt_num_known) {
evt_list = zalloc(sizeof(char *) * evt_num);
if (!evt_list)
goto out_enomem;
syms -= max;
}
for (i = 0; i < max ; i++, syms++) { for (i = 0; i < max ; i++, syms++) {
if (!is_event_supported(type, i)) if (!is_event_supported(type, i))
continue; continue;
if (!evt_num_known) {
evt_num++;
continue;
}
if (strlen(syms->alias)) if (strlen(syms->alias))
snprintf(name, sizeof(name), "%s OR %s", snprintf(name, sizeof(name), "%s OR %s",
syms->symbol, syms->alias); syms->symbol, syms->alias);
else else
snprintf(name, sizeof(name), "%s", syms->symbol); snprintf(name, sizeof(name), "%s", syms->symbol);
printf(" %-50s [%s]\n", name, event_type_descriptors[type]); evt_list[evt_i] = strdup(name);
if (evt_list[evt_i] == NULL)
goto out_enomem;
evt_i++;
}
if (!evt_num_known) {
evt_num_known = true;
goto restart;
} }
qsort(evt_list, evt_num, sizeof(char *), cmp_string);
evt_i = 0;
while (evt_i < evt_num)
printf(" %-50s [%s]\n", evt_list[evt_i++], event_type_descriptors[type]);
if (evt_num)
printf("\n");
out_free:
evt_num = evt_i;
for (evt_i = 0; evt_i < evt_num; evt_i++)
zfree(&evt_list[evt_i]);
zfree(&evt_list);
return;
out_enomem:
printf("FATAL: not enough memory to print %s\n", event_type_descriptors[type]);
if (evt_list)
goto out_free;
} }
void print_events_type(u8 type) void print_events_type(u8 type)
...@@ -1244,8 +1340,17 @@ void print_events_type(u8 type) ...@@ -1244,8 +1340,17 @@ void print_events_type(u8 type)
int print_hwcache_events(const char *event_glob, bool name_only) int print_hwcache_events(const char *event_glob, bool name_only)
{ {
unsigned int type, op, i, printed = 0; unsigned int type, op, i, evt_i = 0, evt_num = 0;
char name[64]; char name[64];
char **evt_list = NULL;
bool evt_num_known = false;
restart:
if (evt_num_known) {
evt_list = zalloc(sizeof(char *) * evt_num);
if (!evt_list)
goto out_enomem;
}
for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
...@@ -1263,27 +1368,66 @@ int print_hwcache_events(const char *event_glob, bool name_only) ...@@ -1263,27 +1368,66 @@ int print_hwcache_events(const char *event_glob, bool name_only)
type | (op << 8) | (i << 16))) type | (op << 8) | (i << 16)))
continue; continue;
if (name_only) if (!evt_num_known) {
printf("%s ", name); evt_num++;
else continue;
printf(" %-50s [%s]\n", name, }
event_type_descriptors[PERF_TYPE_HW_CACHE]);
++printed; evt_list[evt_i] = strdup(name);
if (evt_list[evt_i] == NULL)
goto out_enomem;
evt_i++;
} }
} }
} }
if (printed) if (!evt_num_known) {
evt_num_known = true;
goto restart;
}
qsort(evt_list, evt_num, sizeof(char *), cmp_string);
evt_i = 0;
while (evt_i < evt_num) {
if (name_only) {
printf("%s ", evt_list[evt_i++]);
continue;
}
printf(" %-50s [%s]\n", evt_list[evt_i++],
event_type_descriptors[PERF_TYPE_HW_CACHE]);
}
if (evt_num)
printf("\n"); printf("\n");
return printed;
out_free:
evt_num = evt_i;
for (evt_i = 0; evt_i < evt_num; evt_i++)
zfree(&evt_list[evt_i]);
zfree(&evt_list);
return evt_num;
out_enomem:
printf("FATAL: not enough memory to print %s\n", event_type_descriptors[PERF_TYPE_HW_CACHE]);
if (evt_list)
goto out_free;
return evt_num;
} }
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) bool name_only)
{ {
unsigned i, printed = 0; unsigned int i, evt_i = 0, evt_num = 0;
char name[MAX_NAME_LEN]; char name[MAX_NAME_LEN];
char **evt_list = NULL;
bool evt_num_known = false;
restart:
if (evt_num_known) {
evt_list = zalloc(sizeof(char *) * evt_num);
if (!evt_list)
goto out_enomem;
syms -= max;
}
for (i = 0; i < max; i++, syms++) { for (i = 0; i < max; i++, syms++) {
...@@ -1295,23 +1439,49 @@ static void print_symbol_events(const char *event_glob, unsigned type, ...@@ -1295,23 +1439,49 @@ static void print_symbol_events(const char *event_glob, unsigned type,
if (!is_event_supported(type, i)) if (!is_event_supported(type, i))
continue; continue;
if (name_only) { if (!evt_num_known) {
printf("%s ", syms->symbol); evt_num++;
continue; continue;
} }
if (strlen(syms->alias)) if (!name_only && 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
strncpy(name, syms->symbol, MAX_NAME_LEN); strncpy(name, syms->symbol, MAX_NAME_LEN);
printf(" %-50s [%s]\n", name, event_type_descriptors[type]); evt_list[evt_i] = strdup(name);
if (evt_list[evt_i] == NULL)
printed++; goto out_enomem;
evt_i++;
} }
if (printed) if (!evt_num_known) {
evt_num_known = true;
goto restart;
}
qsort(evt_list, evt_num, sizeof(char *), cmp_string);
evt_i = 0;
while (evt_i < evt_num) {
if (name_only) {
printf("%s ", evt_list[evt_i++]);
continue;
}
printf(" %-50s [%s]\n", evt_list[evt_i++], event_type_descriptors[type]);
}
if (evt_num)
printf("\n"); printf("\n");
out_free:
evt_num = evt_i;
for (evt_i = 0; evt_i < evt_num; evt_i++)
zfree(&evt_list[evt_i]);
zfree(&evt_list);
return;
out_enomem:
printf("FATAL: not enough memory to print %s\n", event_type_descriptors[type]);
if (evt_list)
goto out_free;
} }
/* /*
......
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