perf: Make the trace events sample period default to 1
[safe/jmp/linux-2.6] / tools / perf / util / parse-events.c
index 0faf4f2..3b4ec67 100644 (file)
@@ -1,10 +1,11 @@
-
+#include "../../../include/linux/hw_breakpoint.h"
 #include "util.h"
 #include "../perf.h"
 #include "parse-options.h"
 #include "parse-events.h"
 #include "exec_cmd.h"
 #include "string.h"
+#include "symbol.h"
 #include "cache.h"
 #include "header.h"
 #include "debugfs.h"
@@ -197,7 +198,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
                        if (id == config) {
                                closedir(evt_dir);
                                closedir(sys_dir);
-                               path = calloc(1, sizeof(path));
+                               path = zalloc(sizeof(*path));
                                path->system = malloc(MAX_EVENT_LENGTH);
                                if (!path->system) {
                                        free(path);
@@ -409,7 +410,6 @@ static enum event_result
 parse_single_tracepoint_event(char *sys_name,
                              const char *evt_name,
                              unsigned int evt_length,
-                             char *flags,
                              struct perf_event_attr *attr,
                              const char **strp)
 {
@@ -418,13 +418,11 @@ parse_single_tracepoint_event(char *sys_name,
        u64 id;
        int fd;
 
-       if (flags) {
-               if (!strncmp(flags, "record", strlen(flags))) {
-                       attr->sample_type |= PERF_SAMPLE_RAW;
-                       attr->sample_type |= PERF_SAMPLE_TIME;
-                       attr->sample_type |= PERF_SAMPLE_CPU;
-               }
-       }
+       attr->sample_type |= PERF_SAMPLE_RAW;
+       attr->sample_type |= PERF_SAMPLE_TIME;
+       attr->sample_type |= PERF_SAMPLE_CPU;
+
+       attr->sample_period = 1;
 
        snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
                 sys_name, evt_name);
@@ -450,7 +448,8 @@ parse_single_tracepoint_event(char *sys_name,
 /* sys + ':' + event + ':' + flags*/
 #define MAX_EVOPT_LEN  (MAX_EVENT_LENGTH * 2 + 2 + 128)
 static enum event_result
-parse_subsystem_tracepoint_event(char *sys_name, char *flags)
+parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,
+                               char *flags)
 {
        char evt_path[MAXPATHLEN];
        struct dirent *evt_ent;
@@ -467,7 +466,6 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
        while ((evt_ent = readdir(evt_dir))) {
                char event_opt[MAX_EVOPT_LEN + 1];
                int len;
-               unsigned int rem = MAX_EVOPT_LEN;
 
                if (!strcmp(evt_ent->d_name, ".")
                    || !strcmp(evt_ent->d_name, "..")
@@ -475,20 +473,15 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
                    || !strcmp(evt_ent->d_name, "filter"))
                        continue;
 
-               len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s", sys_name,
-                              evt_ent->d_name);
+               if (!strglobmatch(evt_ent->d_name, evt_exp))
+                       continue;
+
+               len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
+                              evt_ent->d_name, flags ? ":" : "",
+                              flags ?: "");
                if (len < 0)
                        return EVT_FAILED;
 
-               rem -= len;
-               if (flags) {
-                       if (rem < strlen(flags) + 1)
-                               return EVT_FAILED;
-
-                       strcat(event_opt, ":");
-                       strcat(event_opt, flags);
-               }
-
                if (parse_events(NULL, event_opt, 0))
                        return EVT_FAILED;
        }
@@ -531,13 +524,88 @@ static enum event_result parse_tracepoint_event(const char **strp,
        if (evt_length >= MAX_EVENT_LENGTH)
                return EVT_FAILED;
 
-       if (!strcmp(evt_name, "*")) {
+       if (strpbrk(evt_name, "*?")) {
                *strp = evt_name + evt_length;
-               return parse_subsystem_tracepoint_event(sys_name, flags);
+               return parse_multiple_tracepoint_event(sys_name, evt_name,
+                                                      flags);
        } else
                return parse_single_tracepoint_event(sys_name, evt_name,
-                                                    evt_length, flags,
-                                                    attr, strp);
+                                                    evt_length, attr, strp);
+}
+
+static enum event_result
+parse_breakpoint_type(const char *type, const char **strp,
+                     struct perf_event_attr *attr)
+{
+       int i;
+
+       for (i = 0; i < 3; i++) {
+               if (!type[i])
+                       break;
+
+               switch (type[i]) {
+               case 'r':
+                       attr->bp_type |= HW_BREAKPOINT_R;
+                       break;
+               case 'w':
+                       attr->bp_type |= HW_BREAKPOINT_W;
+                       break;
+               case 'x':
+                       attr->bp_type |= HW_BREAKPOINT_X;
+                       break;
+               default:
+                       return EVT_FAILED;
+               }
+       }
+       if (!attr->bp_type) /* Default */
+               attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
+
+       *strp = type + i;
+
+       return EVT_HANDLED;
+}
+
+static enum event_result
+parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
+{
+       const char *target;
+       const char *type;
+       char *endaddr;
+       u64 addr;
+       enum event_result err;
+
+       target = strchr(*strp, ':');
+       if (!target)
+               return EVT_FAILED;
+
+       if (strncmp(*strp, "mem", target - *strp) != 0)
+               return EVT_FAILED;
+
+       target++;
+
+       addr = strtoull(target, &endaddr, 0);
+       if (target == endaddr)
+               return EVT_FAILED;
+
+       attr->bp_addr = addr;
+       *strp = endaddr;
+
+       type = strchr(target, ':');
+
+       /* If no type is defined, just rw as default */
+       if (!type) {
+               attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
+       } else {
+               err = parse_breakpoint_type(++type, strp, attr);
+               if (err == EVT_FAILED)
+                       return EVT_FAILED;
+       }
+
+       /* We should find a nice way to override the access type */
+       attr->bp_len = HW_BREAKPOINT_LEN_4;
+       attr->type = PERF_TYPE_BREAKPOINT;
+
+       return EVT_HANDLED;
 }
 
 static int check_events(const char *str, unsigned int i)
@@ -585,6 +653,10 @@ parse_raw_event(const char **strp, struct perf_event_attr *attr)
                return EVT_FAILED;
        n = hex2u64(str + 1, &config);
        if (n > 0) {
+               if (str[n+1] == 'p') {
+                       attr->precise = 1;
+                       n++;
+               }
                *strp = str + n + 1;
                attr->type = PERF_TYPE_RAW;
                attr->config = config;
@@ -673,6 +745,10 @@ parse_event_symbols(const char **str, struct perf_event_attr *attr)
        if (ret != EVT_FAILED)
                goto modifier;
 
+       ret = parse_breakpoint_event(str, attr);
+       if (ret != EVT_FAILED)
+               goto modifier;
+
        fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
        fprintf(stderr, "Run 'perf list' for a list of valid events\n");
        return EVT_FAILED;
@@ -683,11 +759,11 @@ modifier:
        return ret;
 }
 
-static void store_event_type(const char *orgname)
+static int store_event_type(const char *orgname)
 {
        char filename[PATH_MAX], *c;
        FILE *file;
-       int id;
+       int id, n;
 
        sprintf(filename, "%s/", debugfs_path);
        strncat(filename, orgname, strlen(orgname));
@@ -699,11 +775,14 @@ static void store_event_type(const char *orgname)
 
        file = fopen(filename, "r");
        if (!file)
-               return;
-       if (fscanf(file, "%i", &id) < 1)
-               die("cannot store event ID");
+               return 0;
+       n = fscanf(file, "%i", &id);
        fclose(file);
-       perf_header__push_event(id, orgname);
+       if (n < 1) {
+               pr_err("cannot store event ID\n");
+               return -EINVAL;
+       }
+       return perf_header__push_event(id, orgname);
 }
 
 int parse_events(const struct option *opt __used, const char *str, int unset __used)
@@ -712,7 +791,8 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
        enum event_result ret;
 
        if (strchr(str, ':'))
-               store_event_type(str);
+               if (store_event_type(str) < 0)
+                       return -1;
 
        for (;;) {
                if (nr_counters == MAX_COUNTERS)
@@ -765,11 +845,12 @@ int parse_filter(const struct option *opt __used, const char *str,
 }
 
 static const char * const event_type_descriptors[] = {
-       "",
        "Hardware event",
        "Software event",
        "Tracepoint event",
        "Hardware cache event",
+       "Raw hardware event descriptor",
+       "Hardware breakpoint",
 };
 
 /*
@@ -802,7 +883,7 @@ static void print_tracepoint_events(void)
                        snprintf(evt_path, MAXPATHLEN, "%s:%s",
                                 sys_dirent.d_name, evt_dirent.d_name);
                        printf("  %-42s [%s]\n", evt_path,
-                               event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
+                               event_type_descriptors[PERF_TYPE_TRACEPOINT]);
                }
                closedir(evt_dir);
        }
@@ -822,9 +903,7 @@ void print_events(void)
        printf("List of pre-defined events (to be used in -e):\n");
 
        for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
-               type = syms->type + 1;
-               if (type >= ARRAY_SIZE(event_type_descriptors))
-                       type = 0;
+               type = syms->type;
 
                if (type != prev_type)
                        printf("\n");
@@ -849,14 +928,19 @@ void print_events(void)
                        for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
                                printf("  %-42s [%s]\n",
                                        event_cache_name(type, op, i),
-                                       event_type_descriptors[4]);
+                                       event_type_descriptors[PERF_TYPE_HW_CACHE]);
                        }
                }
        }
 
        printf("\n");
-       printf("  %-42s [raw hardware event descriptor]\n",
-               "rNNN");
+       printf("  %-42s [%s]\n",
+               "rNNN", event_type_descriptors[PERF_TYPE_RAW]);
+       printf("\n");
+
+       printf("  %-42s [%s]\n",
+                       "mem:<addr>[:access]",
+                       event_type_descriptors[PERF_TYPE_BREAKPOINT]);
        printf("\n");
 
        print_tracepoint_events();