OSDN Git Service

perf list: Add metric groups to perf list
authorAndi Kleen <ak@linux.intel.com>
Thu, 31 Aug 2017 19:40:32 +0000 (12:40 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 13 Sep 2017 12:49:13 +0000 (09:49 -0300)
Add code to perf list to print metric groups, and metrics
that don't have an event name. The metricgroup code collects
the eventgroups and events into a rblist, and then prints
them according to the configured filters.

The metricgroups are printed by default, but can be
limited by perf list metric or perf list metricgroup

  % perf list metricgroup
  ..
  Metric Groups:

  DSB:
    DSB_Coverage
          [Fraction of Uops delivered by the DSB (aka Decoded Icache; or Uop Cache)]
  FLOPS:
    GFLOPs
          [Giga Floating Point Operations Per Second]
  Frontend:
    IFetch_Line_Utilization
          [Rough Estimation of fraction of fetched lines bytes that were likely consumed by program instructions]
  Frontend_Bandwidth:
    DSB_Coverage
          [Fraction of Uops delivered by the DSB (aka Decoded Icache; or Uop Cache)]
  Memory_BW:
    MLP
          [Memory-Level-Parallelism (average number of L1 miss demand load when there is at least 1 such miss)]

v2: Check return value of asprintf to fix warning on FC26
Fix key in lookup/addition for the groups list

Signed-off-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Link: http://lkml.kernel.org/r/20170831194036.30146-8-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/Documentation/perf-list.txt
tools/perf/builtin-list.c
tools/perf/util/metricgroup.c
tools/perf/util/parse-events.c

index 75fc17f..24679ae 100644 (file)
@@ -8,7 +8,8 @@ perf-list - List all symbolic event types
 SYNOPSIS
 --------
 [verse]
-'perf list' [--no-desc] [--long-desc] [hw|sw|cache|tracepoint|pmu|sdt|event_glob]
+'perf list' [--no-desc] [--long-desc]
+            [hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob]
 
 DESCRIPTION
 -----------
@@ -248,6 +249,10 @@ To limit the list use:
 
 . 'sdt' to list all Statically Defined Tracepoint events.
 
+. 'metric' to list metrics
+
+. 'metricgroup' to list metricgroups with metrics.
+
 . If none of the above is matched, it will apply the supplied glob to all
   events, printing the ones that match.
 
index 4bf2cb4..b2d2ad3 100644 (file)
@@ -15,6 +15,7 @@
 #include "util/cache.h"
 #include "util/pmu.h"
 #include "util/debug.h"
+#include "util/metricgroup.h"
 #include <subcmd/parse-options.h>
 
 static bool desc_flag = true;
@@ -79,6 +80,10 @@ int cmd_list(int argc, const char **argv)
                                                long_desc_flag, details_flag);
                else if (strcmp(argv[i], "sdt") == 0)
                        print_sdt_events(NULL, NULL, raw_dump);
+               else if (strcmp(argv[i], "metric") == 0)
+                       metricgroup__print(true, false, NULL, raw_dump);
+               else if (strcmp(argv[i], "metricgroup") == 0)
+                       metricgroup__print(false, true, NULL, raw_dump);
                else if ((sep = strchr(argv[i], ':')) != NULL) {
                        int sep_idx;
 
@@ -96,6 +101,7 @@ int cmd_list(int argc, const char **argv)
                        s[sep_idx] = '\0';
                        print_tracepoint_events(s, s + sep_idx + 1, raw_dump);
                        print_sdt_events(s, s + sep_idx + 1, raw_dump);
+                       metricgroup__print(true, true, s, raw_dump);
                        free(s);
                } else {
                        if (asprintf(&s, "*%s*", argv[i]) < 0) {
@@ -112,6 +118,7 @@ int cmd_list(int argc, const char **argv)
                                                details_flag);
                        print_tracepoint_events(NULL, s, raw_dump);
                        print_sdt_events(NULL, s, raw_dump);
+                       metricgroup__print(true, true, NULL, raw_dump);
                        free(s);
                }
        }
index 7516b17..2d60114 100644 (file)
@@ -189,6 +189,182 @@ static bool match_metric(const char *n, const char *list)
        return false;
 }
 
+struct mep {
+       struct rb_node nd;
+       const char *name;
+       struct strlist *metrics;
+};
+
+static int mep_cmp(struct rb_node *rb_node, const void *entry)
+{
+       struct mep *a = container_of(rb_node, struct mep, nd);
+       struct mep *b = (struct mep *)entry;
+
+       return strcmp(a->name, b->name);
+}
+
+static struct rb_node *mep_new(struct rblist *rl __maybe_unused,
+                                       const void *entry)
+{
+       struct mep *me = malloc(sizeof(struct mep));
+
+       if (!me)
+               return NULL;
+       memcpy(me, entry, sizeof(struct mep));
+       me->name = strdup(me->name);
+       if (!me->name)
+               goto out_me;
+       me->metrics = strlist__new(NULL, NULL);
+       if (!me->metrics)
+               goto out_name;
+       return &me->nd;
+out_name:
+       free((char *)me->name);
+out_me:
+       free(me);
+       return NULL;
+}
+
+static struct mep *mep_lookup(struct rblist *groups, const char *name)
+{
+       struct rb_node *nd;
+       struct mep me = {
+               .name = name
+       };
+       nd = rblist__find(groups, &me);
+       if (nd)
+               return container_of(nd, struct mep, nd);
+       rblist__add_node(groups, &me);
+       nd = rblist__find(groups, &me);
+       if (nd)
+               return container_of(nd, struct mep, nd);
+       return NULL;
+}
+
+static void mep_delete(struct rblist *rl __maybe_unused,
+                      struct rb_node *nd)
+{
+       struct mep *me = container_of(nd, struct mep, nd);
+
+       strlist__delete(me->metrics);
+       free((void *)me->name);
+       free(me);
+}
+
+static void metricgroup__print_strlist(struct strlist *metrics, bool raw)
+{
+       struct str_node *sn;
+       int n = 0;
+
+       strlist__for_each_entry (sn, metrics) {
+               if (raw)
+                       printf("%s%s", n > 0 ? " " : "", sn->s);
+               else
+                       printf("  %s\n", sn->s);
+               n++;
+       }
+       if (raw)
+               putchar('\n');
+}
+
+void metricgroup__print(bool metrics, bool metricgroups, char *filter,
+                       bool raw)
+{
+       struct pmu_events_map *map = perf_pmu__find_map();
+       struct pmu_event *pe;
+       int i;
+       struct rblist groups;
+       struct rb_node *node, *next;
+       struct strlist *metriclist = NULL;
+
+       if (!map)
+               return;
+
+       if (!metricgroups) {
+               metriclist = strlist__new(NULL, NULL);
+               if (!metriclist)
+                       return;
+       }
+
+       rblist__init(&groups);
+       groups.node_new = mep_new;
+       groups.node_cmp = mep_cmp;
+       groups.node_delete = mep_delete;
+       for (i = 0; ; i++) {
+               const char *g;
+               pe = &map->table[i];
+
+               if (!pe->name && !pe->metric_group && !pe->metric_name)
+                       break;
+               if (!pe->metric_expr)
+                       continue;
+               g = pe->metric_group;
+               if (!g && pe->metric_name) {
+                       if (pe->name)
+                               continue;
+                       g = "No_group";
+               }
+               if (g) {
+                       char *omg;
+                       char *mg = strdup(g);
+
+                       if (!mg)
+                               return;
+                       omg = mg;
+                       while ((g = strsep(&mg, ";")) != NULL) {
+                               struct mep *me;
+                               char *s;
+
+                               if (*g == 0)
+                                       g = "No_group";
+                               while (isspace(*g))
+                                       g++;
+                               if (filter && !strstr(g, filter))
+                                       continue;
+                               if (raw)
+                                       s = (char *)pe->metric_name;
+                               else {
+                                       if (asprintf(&s, "%s\n\t[%s]",
+                                                    pe->metric_name, pe->desc) < 0)
+                                               return;
+                               }
+
+                               if (!s)
+                                       continue;
+
+                               if (!metricgroups) {
+                                       strlist__add(metriclist, s);
+                               } else {
+                                       me = mep_lookup(&groups, g);
+                                       if (!me)
+                                               continue;
+                                       strlist__add(me->metrics, s);
+                               }
+                       }
+                       free(omg);
+               }
+       }
+
+       if (metricgroups && !raw)
+               printf("\nMetric Groups:\n\n");
+       else if (metrics && !raw)
+               printf("\nMetrics:\n\n");
+
+       for (node = rb_first(&groups.entries); node; node = next) {
+               struct mep *me = container_of(node, struct mep, nd);
+
+               if (metricgroups)
+                       printf("%s%s%s", me->name, metrics ? ":" : "", raw ? " " : "\n");
+               if (metrics)
+                       metricgroup__print_strlist(me->metrics, raw);
+               next = rb_next(node);
+               rblist__remove_node(&groups, node);
+       }
+       if (!metricgroups)
+               metricgroup__print_strlist(metriclist, raw);
+       strlist__delete(metriclist);
+}
+
 static int metricgroup__add_metric(const char *metric, struct strbuf *events,
                                   struct list_head *group_list)
 {
index 57d7acf..7558892 100644 (file)
@@ -28,6 +28,7 @@
 #include "probe-file.h"
 #include "asm/bug.h"
 #include "util/parse-branch-options.h"
+#include "metricgroup.h"
 
 #define MAX_NAME_LEN 100
 
@@ -2380,6 +2381,8 @@ void print_events(const char *event_glob, bool name_only, bool quiet_flag,
        print_tracepoint_events(NULL, NULL, name_only);
 
        print_sdt_events(NULL, NULL, name_only);
+
+       metricgroup__print(true, true, NULL, name_only);
 }
 
 int parse_events__is_hardcoded_term(struct parse_events_term *term)