perf tools: Reconstruct hw cache event with modifiers from perf_event_attr
authorArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 11 Jun 2012 17:08:07 +0000 (14:08 -0300)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Tue, 19 Jun 2012 16:06:20 +0000 (13:06 -0300)
  [root@sandy ~]# perf record -a -e dTLB-load-misses:u usleep 1
  [ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 0.486 MB perf.data (~21216 samples) ]

Before:

  [root@sandy ~]# perf evlist
  dTLB-load-misses
  [root@sandy ~]#

After:

  [root@sandy ~]# perf evlist
  dTLB-load-misses:u
  [root@sandy ~]#

Ditto for other tools.

Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-7x1b0e6jthkr93lfjzsuakk5@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/parse-events.c

index dab893804a147bb778b222ee0bf1550fa2346b12..47f1fe2feab89495d06283ec270b079c3e1f2181 100644 (file)
@@ -128,6 +128,105 @@ static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
        return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
 }
 
+const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX]
+                               [PERF_EVSEL__MAX_ALIASES] = {
+ { "L1-dcache",        "l1-d",         "l1d",          "L1-data",              },
+ { "L1-icache",        "l1-i",         "l1i",          "L1-instruction",       },
+ { "LLC",      "L2",                                                   },
+ { "dTLB",     "d-tlb",        "Data-TLB",                             },
+ { "iTLB",     "i-tlb",        "Instruction-TLB",                      },
+ { "branch",   "branches",     "bpu",          "btb",          "bpc",  },
+ { "node",                                                             },
+};
+
+const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX]
+                                  [PERF_EVSEL__MAX_ALIASES] = {
+ { "load",     "loads",        "read",                                 },
+ { "store",    "stores",       "write",                                },
+ { "prefetch", "prefetches",   "speculative-read", "speculative-load", },
+};
+
+const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
+                                      [PERF_EVSEL__MAX_ALIASES] = {
+ { "refs",     "Reference",    "ops",          "access",               },
+ { "misses",   "miss",                                                 },
+};
+
+#define C(x)           PERF_COUNT_HW_CACHE_##x
+#define CACHE_READ     (1 << C(OP_READ))
+#define CACHE_WRITE    (1 << C(OP_WRITE))
+#define CACHE_PREFETCH (1 << C(OP_PREFETCH))
+#define COP(x)         (1 << x)
+
+/*
+ * cache operartion stat
+ * L1I : Read and prefetch only
+ * ITLB and BPU : Read-only
+ */
+static unsigned long perf_evsel__hw_cache_stat[C(MAX)] = {
+ [C(L1D)]      = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+ [C(L1I)]      = (CACHE_READ | CACHE_PREFETCH),
+ [C(LL)]       = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+ [C(DTLB)]     = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+ [C(ITLB)]     = (CACHE_READ),
+ [C(BPU)]      = (CACHE_READ),
+ [C(NODE)]     = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+};
+
+bool perf_evsel__is_cache_op_valid(u8 type, u8 op)
+{
+       if (perf_evsel__hw_cache_stat[type] & COP(op))
+               return true;    /* valid */
+       else
+               return false;   /* invalid */
+}
+
+int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
+                                           char *bf, size_t size)
+{
+       if (result) {
+               return scnprintf(bf, size, "%s-%s-%s", perf_evsel__hw_cache[type][0],
+                                perf_evsel__hw_cache_op[op][0],
+                                perf_evsel__hw_cache_result[result][0]);
+       }
+
+       return scnprintf(bf, size, "%s-%s", perf_evsel__hw_cache[type][0],
+                        perf_evsel__hw_cache_op[op][1]);
+}
+
+int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size)
+{
+       u8 op, result, type = (config >>  0) & 0xff;
+       const char *err = "unknown-ext-hardware-cache-type";
+
+       if (type > PERF_COUNT_HW_CACHE_MAX)
+               goto out_err;
+
+       op = (config >>  8) & 0xff;
+       err = "unknown-ext-hardware-cache-op";
+       if (op > PERF_COUNT_HW_CACHE_OP_MAX)
+               goto out_err;
+
+       result = (config >> 16) & 0xff;
+       err = "unknown-ext-hardware-cache-result";
+       if (result > PERF_COUNT_HW_CACHE_RESULT_MAX)
+               goto out_err;
+
+       err = "invalid-cache";
+       if (!perf_evsel__is_cache_op_valid(type, op))
+               goto out_err;
+
+       return __perf_evsel__hw_cache_type_op_res_name(type, op, result, bf, size);
+out_err:
+       return scnprintf(bf, size, "%s", err);
+}
+
+static int perf_evsel__hw_cache_name(struct perf_evsel *evsel, char *bf, size_t size)
+{
+       int ret = __perf_evsel__hw_cache_name(evsel->attr.config, bf, size);
+       return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret);
+}
+
 int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size)
 {
        int ret;
@@ -140,6 +239,11 @@ int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size)
        case PERF_TYPE_HARDWARE:
                ret = perf_evsel__hw_name(evsel, bf, size);
                break;
+
+       case PERF_TYPE_HW_CACHE:
+               ret = perf_evsel__hw_cache_name(evsel, bf, size);
+               break;
+
        default:
                /*
                 * FIXME
index 4ba8b564e6f47f039652ebac739d9d899d5881f5..5bf946a05a6b1f1dd175adf87b67e8644d5a35e9 100644 (file)
@@ -83,7 +83,21 @@ void perf_evsel__config(struct perf_evsel *evsel,
                        struct perf_record_opts *opts,
                        struct perf_evsel *first);
 
-const char* __perf_evsel__hw_name(u64 config);
+bool perf_evsel__is_cache_op_valid(u8 type, u8 op);
+
+#define PERF_EVSEL__MAX_ALIASES 8
+
+extern const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX]
+                                      [PERF_EVSEL__MAX_ALIASES];
+extern const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX]
+                                         [PERF_EVSEL__MAX_ALIASES];
+const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
+                                      [PERF_EVSEL__MAX_ALIASES];
+int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
+                                           char *bf, size_t size);
+int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size);
+
+const char *__perf_evsel__hw_name(u64 config);
 int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size);
 
 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
index 05dbc8b3c767217ceb3204c7be46f5aedbb205c4..c8f8cf4a69209fb676929b94fbed8ff18948533d 100644 (file)
@@ -74,51 +74,6 @@ static const char *sw_event_names[PERF_COUNT_SW_MAX] = {
        "emulation-faults",
 };
 
-#define MAX_ALIASES 8
-
-static const char *hw_cache[PERF_COUNT_HW_CACHE_MAX][MAX_ALIASES] = {
- { "L1-dcache",        "l1-d",         "l1d",          "L1-data",              },
- { "L1-icache",        "l1-i",         "l1i",          "L1-instruction",       },
- { "LLC",      "L2",                                                   },
- { "dTLB",     "d-tlb",        "Data-TLB",                             },
- { "iTLB",     "i-tlb",        "Instruction-TLB",                      },
- { "branch",   "branches",     "bpu",          "btb",          "bpc",  },
- { "node",                                                             },
-};
-
-static const char *hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX][MAX_ALIASES] = {
- { "load",     "loads",        "read",                                 },
- { "store",    "stores",       "write",                                },
- { "prefetch", "prefetches",   "speculative-read", "speculative-load", },
-};
-
-static const char *hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
-                                 [MAX_ALIASES] = {
- { "refs",     "Reference",    "ops",          "access",               },
- { "misses",   "miss",                                                 },
-};
-
-#define C(x)           PERF_COUNT_HW_CACHE_##x
-#define CACHE_READ     (1 << C(OP_READ))
-#define CACHE_WRITE    (1 << C(OP_WRITE))
-#define CACHE_PREFETCH (1 << C(OP_PREFETCH))
-#define COP(x)         (1 << x)
-
-/*
- * cache operartion stat
- * L1I : Read and prefetch only
- * ITLB and BPU : Read-only
- */
-static unsigned long hw_cache_stat[C(MAX)] = {
- [C(L1D)]      = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
- [C(L1I)]      = (CACHE_READ | CACHE_PREFETCH),
- [C(LL)]       = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
- [C(DTLB)]     = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
- [C(ITLB)]     = (CACHE_READ),
- [C(BPU)]      = (CACHE_READ),
- [C(NODE)]     = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
-};
-
 #define for_each_subsystem(sys_dir, sys_dirent, sys_next)             \
        while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next)        \
        if (sys_dirent.d_type == DT_DIR &&                                     \
@@ -236,30 +191,6 @@ static const char *tracepoint_id_to_name(u64 config)
        return buf;
 }
 
-static int is_cache_op_valid(u8 cache_type, u8 cache_op)
-{
-       if (hw_cache_stat[cache_type] & COP(cache_op))
-               return 1;       /* valid */
-       else
-               return 0;       /* invalid */
-}
-
-static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
-{
-       static char name[50];
-
-       if (cache_result) {
-               sprintf(name, "%s-%s-%s", hw_cache[cache_type][0],
-                       hw_cache_op[cache_op][0],
-                       hw_cache_result[cache_result][0]);
-       } else {
-               sprintf(name, "%s-%s", hw_cache[cache_type][0],
-                       hw_cache_op[cache_op][1]);
-       }
-
-       return name;
-}
-
 const char *event_type(int type)
 {
        switch (type) {
@@ -287,7 +218,7 @@ const char *event_name(struct perf_evsel *evsel)
        u64 config = evsel->attr.config;
        int type = evsel->attr.type;
 
-       if (type == PERF_TYPE_RAW || type == PERF_TYPE_HARDWARE) {
+       if (type == PERF_TYPE_RAW || type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE) {
                /*
                 * XXX minimal fix, see comment on perf_evsen__name, this static buffer
                 * will go away together with event_name in the next devel cycle.
@@ -316,26 +247,9 @@ const char *__event_name(int type, u64 config)
        case PERF_TYPE_HARDWARE:
                return __perf_evsel__hw_name(config);
 
-       case PERF_TYPE_HW_CACHE: {
-               u8 cache_type, cache_op, cache_result;
-
-               cache_type   = (config >>  0) & 0xff;
-               if (cache_type > PERF_COUNT_HW_CACHE_MAX)
-                       return "unknown-ext-hardware-cache-type";
-
-               cache_op     = (config >>  8) & 0xff;
-               if (cache_op > PERF_COUNT_HW_CACHE_OP_MAX)
-                       return "unknown-ext-hardware-cache-op";
-
-               cache_result = (config >> 16) & 0xff;
-               if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
-                       return "unknown-ext-hardware-cache-result";
-
-               if (!is_cache_op_valid(cache_type, cache_op))
-                       return "invalid-cache";
-
-               return event_cache_name(cache_type, cache_op, cache_result);
-       }
+       case PERF_TYPE_HW_CACHE:
+               __perf_evsel__hw_cache_name(config, buf, sizeof(buf));
+               return buf;
 
        case PERF_TYPE_SOFTWARE:
                if (config < PERF_COUNT_SW_MAX && sw_event_names[config])
@@ -379,13 +293,13 @@ static int add_event(struct list_head **_list, int *idx,
        return 0;
 }
 
-static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
+static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size)
 {
        int i, j;
        int n, longest = -1;
 
        for (i = 0; i < size; i++) {
-               for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
+               for (j = 0; j < PERF_EVSEL__MAX_ALIASES && names[i][j]; j++) {
                        n = strlen(names[i][j]);
                        if (n > longest && !strncasecmp(str, names[i][j], n))
                                longest = n;
@@ -410,7 +324,7 @@ int parse_events_add_cache(struct list_head **list, int *idx,
         * No fallback - if we cannot get a clear cache type
         * then bail out:
         */
-       cache_type = parse_aliases(type, hw_cache,
+       cache_type = parse_aliases(type, perf_evsel__hw_cache,
                                   PERF_COUNT_HW_CACHE_MAX);
        if (cache_type == -1)
                return -EINVAL;
@@ -423,18 +337,18 @@ int parse_events_add_cache(struct list_head **list, int *idx,
                snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str);
 
                if (cache_op == -1) {
-                       cache_op = parse_aliases(str, hw_cache_op,
+                       cache_op = parse_aliases(str, perf_evsel__hw_cache_op,
                                                 PERF_COUNT_HW_CACHE_OP_MAX);
                        if (cache_op >= 0) {
-                               if (!is_cache_op_valid(cache_type, cache_op))
+                               if (!perf_evsel__is_cache_op_valid(cache_type, cache_op))
                                        return -EINVAL;
                                continue;
                        }
                }
 
                if (cache_result == -1) {
-                       cache_result = parse_aliases(str, hw_cache_result,
-                                               PERF_COUNT_HW_CACHE_RESULT_MAX);
+                       cache_result = parse_aliases(str, perf_evsel__hw_cache_result,
+                                                    PERF_COUNT_HW_CACHE_RESULT_MAX);
                        if (cache_result >= 0)
                                continue;
                }
@@ -970,16 +884,17 @@ void print_events_type(u8 type)
 int print_hwcache_events(const char *event_glob)
 {
        unsigned int type, op, i, printed = 0;
+       char name[64];
 
        for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
                for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
                        /* skip invalid cache type */
-                       if (!is_cache_op_valid(type, op))
+                       if (!perf_evsel__is_cache_op_valid(type, op))
                                continue;
 
                        for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
-                               char *name = event_cache_name(type, op, i);
-
+                               __perf_evsel__hw_cache_type_op_res_name(type, op, i,
+                                                                       name, sizeof(name));
                                if (event_glob != NULL && !strglobmatch(name, event_glob))
                                        continue;