perf list: Sort the output of 'perf list' to view more clearly
authorYunlong Song <yunlong.song@huawei.com>
Fri, 27 Feb 2015 10:21:25 +0000 (18:21 +0800)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 27 Feb 2015 18:51:44 +0000 (15:51 -0300)
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: Yunlong Song <yunlong.song@huawei.com>
Tested-by: Arnaldo 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: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/parse-events.c

index 109ba5c8c2e52368b061f3834bbaaf16e6920f50..f6822d9b2b53d71f4f0bfd8dc1d71e37e9c02d60 100644 (file)
@@ -1089,6 +1089,14 @@ static const char * const event_type_descriptors[] = {
        "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
  */
@@ -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;
        char evt_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);
        if (!sys_dir)
                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) {
                if (subsys_glob != NULL &&
                    !strglobmatch(sys_dirent.d_name, subsys_glob))
@@ -1121,19 +1139,56 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
                            !strglobmatch(evt_dirent.d_name, event_glob))
                                continue;
 
-                       if (name_only) {
-                               printf("%s:%s ", sys_dirent.d_name, evt_dirent.d_name);
+                       if (!evt_num_known) {
+                               evt_num++;
                                continue;
                        }
 
                        snprintf(evt_path, MAXPATHLEN, "%s:%s",
                                 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(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,
                                unsigned max)
 {
        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++) {
                if (!is_event_supported(type, i))
                        continue;
 
+               if (!evt_num_known) {
+                       evt_num++;
+                       continue;
+               }
+
                if (strlen(syms->alias))
                        snprintf(name, sizeof(name),  "%s OR %s",
                                 syms->symbol, syms->alias);
                else
                        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)
@@ -1244,8 +1340,17 @@ void print_events_type(u8 type)
 
 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 **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 (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)
                                                        type | (op << 8) | (i << 16)))
                                        continue;
 
-                               if (name_only)
-                                       printf("%s ", name);
-                               else
-                                       printf("  %-50s [%s]\n", name,
-                                              event_type_descriptors[PERF_TYPE_HW_CACHE]);
-                               ++printed;
+                               if (!evt_num_known) {
+                                       evt_num++;
+                                       continue;
+                               }
+
+                               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");
-       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,
                                struct event_symbol *syms, unsigned max,
                                bool name_only)
 {
-       unsigned i, printed = 0;
+       unsigned int i, evt_i = 0, evt_num = 0;
        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++) {
 
@@ -1295,23 +1439,49 @@ static void print_symbol_events(const char *event_glob, unsigned type,
                if (!is_event_supported(type, i))
                        continue;
 
-               if (name_only) {
-                       printf("%s ", syms->symbol);
+               if (!evt_num_known) {
+                       evt_num++;
                        continue;
                }
 
-               if (strlen(syms->alias))
+               if (!name_only && strlen(syms->alias))
                        snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias);
                else
                        strncpy(name, syms->symbol, MAX_NAME_LEN);
 
-               printf("  %-50s [%s]\n", name, event_type_descriptors[type]);
-
-               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[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;
 }
 
 /*