perf trace: Add interface to access perf data from Perl handlers
[safe/jmp/linux-2.6] / tools / perf / util / trace-event-parse.c
index 93a82fe..0302405 100644 (file)
@@ -40,12 +40,19 @@ int header_page_size_size;
 int header_page_data_offset;
 int header_page_data_size;
 
+int latency_format;
+
 static char *input_buf;
 static unsigned long long input_buf_ptr;
 static unsigned long long input_buf_siz;
 
 static int cpus;
 static int long_size;
+static int is_flag_field;
+static int is_symbolic_field;
+
+static struct format_field *
+find_any_field(struct event *event, const char *name);
 
 static void init_input_buf(char *buf, unsigned long long size)
 {
@@ -284,16 +291,19 @@ void parse_ftrace_printk(char *file, unsigned int size __unused)
        char *line;
        char *next = NULL;
        char *addr_str;
-       char *fmt;
        int i;
 
        line = strtok_r(file, "\n", &next);
        while (line) {
+               addr_str = strsep(&line, ":");
+               if (!line) {
+                       warning("error parsing print strings");
+                       break;
+               }
                item = malloc_or_die(sizeof(*item));
-               addr_str = strtok_r(line, ":", &fmt);
                item->addr = strtoull(addr_str, NULL, 16);
                /* fmt still has a space, skip it */
-               item->printk = strdup(fmt+1);
+               item->printk = strdup(line+1);
                item->next = list;
                list = item;
                line = strtok_r(NULL, "\n", &next);
@@ -683,10 +693,10 @@ static char *event_read_name(void)
 {
        char *token;
 
-       if (read_expected(EVENT_ITEM, (char *)"name") < 0)
+       if (read_expected(EVENT_ITEM, "name") < 0)
                return NULL;
 
-       if (read_expected(EVENT_OP, (char *)":") < 0)
+       if (read_expected(EVENT_OP, ":") < 0)
                return NULL;
 
        if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -704,10 +714,10 @@ static int event_read_id(void)
        char *token;
        int id;
 
-       if (read_expected_item(EVENT_ITEM, (char *)"ID") < 0)
+       if (read_expected_item(EVENT_ITEM, "ID") < 0)
                return -1;
 
-       if (read_expected(EVENT_OP, (char *)":") < 0)
+       if (read_expected(EVENT_OP, ":") < 0)
                return -1;
 
        if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -757,7 +767,7 @@ static int event_read_fields(struct event *event, struct format_field **fields)
 
                count++;
 
-               if (test_type_token(type, token, EVENT_ITEM, (char *)"field"))
+               if (test_type_token(type, token, EVENT_ITEM, "field"))
                        goto fail;
                free_token(token);
 
@@ -772,7 +782,7 @@ static int event_read_fields(struct event *event, struct format_field **fields)
                        type = read_token(&token);
                }
 
-               if (test_type_token(type, token, EVENT_OP, (char *)":") < 0)
+               if (test_type_token(type, token, EVENT_OP, ":") < 0)
                        return -1;
 
                if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -890,14 +900,14 @@ static int event_read_fields(struct event *event, struct format_field **fields)
                                field->flags |= FIELD_IS_DYNAMIC;
                }
 
-               if (test_type_token(type, token,  EVENT_OP, (char *)";"))
+               if (test_type_token(type, token,  EVENT_OP, ";"))
                        goto fail;
                free_token(token);
 
-               if (read_expected(EVENT_ITEM, (char *)"offset") < 0)
+               if (read_expected(EVENT_ITEM, "offset") < 0)
                        goto fail_expect;
 
-               if (read_expected(EVENT_OP, (char *)":") < 0)
+               if (read_expected(EVENT_OP, ":") < 0)
                        goto fail_expect;
 
                if (read_expect_type(EVENT_ITEM, &token))
@@ -905,13 +915,13 @@ static int event_read_fields(struct event *event, struct format_field **fields)
                field->offset = strtoul(token, NULL, 0);
                free_token(token);
 
-               if (read_expected(EVENT_OP, (char *)";") < 0)
+               if (read_expected(EVENT_OP, ";") < 0)
                        goto fail_expect;
 
-               if (read_expected(EVENT_ITEM, (char *)"size") < 0)
+               if (read_expected(EVENT_ITEM, "size") < 0)
                        goto fail_expect;
 
-               if (read_expected(EVENT_OP, (char *)":") < 0)
+               if (read_expected(EVENT_OP, ":") < 0)
                        goto fail_expect;
 
                if (read_expect_type(EVENT_ITEM, &token))
@@ -919,27 +929,28 @@ static int event_read_fields(struct event *event, struct format_field **fields)
                field->size = strtoul(token, NULL, 0);
                free_token(token);
 
-               if (read_expected(EVENT_OP, (char *)";") < 0)
+               if (read_expected(EVENT_OP, ";") < 0)
                        goto fail_expect;
 
                type = read_token(&token);
                if (type != EVENT_NEWLINE) {
                        /* newer versions of the kernel have a "signed" type */
-                       if (test_type_token(type, token, EVENT_ITEM, (char *)"signed"))
+                       if (test_type_token(type, token, EVENT_ITEM, "signed"))
                                goto fail;
 
                        free_token(token);
 
-                       if (read_expected(EVENT_OP, (char *)":") < 0)
+                       if (read_expected(EVENT_OP, ":") < 0)
                                goto fail_expect;
 
                        if (read_expect_type(EVENT_ITEM, &token))
                                goto fail;
 
-                       /* add signed type */
+                       if (strtoul(token, NULL, 0))
+                               field->flags |= FIELD_IS_SIGNED;
 
                        free_token(token);
-                       if (read_expected(EVENT_OP, (char *)";") < 0)
+                       if (read_expected(EVENT_OP, ";") < 0)
                                goto fail_expect;
 
                        if (read_expect_type(EVENT_NEWLINE, &token))
@@ -968,10 +979,10 @@ static int event_read_format(struct event *event)
        char *token;
        int ret;
 
-       if (read_expected_item(EVENT_ITEM, (char *)"format") < 0)
+       if (read_expected_item(EVENT_ITEM, "format") < 0)
                return -1;
 
-       if (read_expected(EVENT_OP, (char *)":") < 0)
+       if (read_expected(EVENT_OP, ":") < 0)
                return -1;
 
        if (read_expect_type(EVENT_NEWLINE, &token))
@@ -1031,7 +1042,7 @@ process_cond(struct event *event, struct print_arg *top, char **tok)
 
        *tok = NULL;
        type = process_arg(event, left, &token);
-       if (test_type_token(type, token, EVENT_OP, (char *)":"))
+       if (test_type_token(type, token, EVENT_OP, ":"))
                goto out_free;
 
        arg->op.op = token;
@@ -1063,7 +1074,7 @@ process_array(struct event *event, struct print_arg *top, char **tok)
 
        *tok = NULL;
        type = process_arg(event, arg, &token);
-       if (test_type_token(type, token, EVENT_OP, (char *)"]"))
+       if (test_type_token(type, token, EVENT_OP, "]"))
                goto out_free;
 
        top->op.right = arg;
@@ -1285,7 +1296,7 @@ process_entry(struct event *event __unused, struct print_arg *arg,
        char *field;
        char *token;
 
-       if (read_expected(EVENT_OP, (char *)"->") < 0)
+       if (read_expected(EVENT_OP, "->") < 0)
                return EVENT_ERROR;
 
        if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -1295,6 +1306,16 @@ process_entry(struct event *event __unused, struct print_arg *arg,
        arg->type = PRINT_FIELD;
        arg->field.name = field;
 
+       if (is_flag_field) {
+               arg->field.field = find_any_field(event, arg->field.name);
+               arg->field.field->flags |= FIELD_IS_FLAG;
+               is_flag_field = 0;
+       } else if (is_symbolic_field) {
+               arg->field.field = find_any_field(event, arg->field.name);
+               arg->field.field->flags |= FIELD_IS_SYMBOLIC;
+               is_symbolic_field = 0;
+       }
+
        type = read_token(&token);
        *tok = token;
 
@@ -1445,14 +1466,14 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
        do {
                free_token(token);
                type = read_token_item(&token);
-               if (test_type_token(type, token, EVENT_OP, (char *)"{"))
+               if (test_type_token(type, token, EVENT_OP, "{"))
                        break;
 
                arg = malloc_or_die(sizeof(*arg));
 
                free_token(token);
                type = process_arg(event, arg, &token);
-               if (test_type_token(type, token, EVENT_DELIM, (char *)","))
+               if (test_type_token(type, token, EVENT_DELIM, ","))
                        goto out_free;
 
                field = malloc_or_die(sizeof(*field));
@@ -1463,7 +1484,7 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
 
                free_token(token);
                type = process_arg(event, arg, &token);
-               if (test_type_token(type, token, EVENT_OP, (char *)"}"))
+               if (test_type_token(type, token, EVENT_OP, "}"))
                        goto out_free;
 
                value = arg_eval(arg);
@@ -1498,13 +1519,13 @@ process_flags(struct event *event, struct print_arg *arg, char **tok)
        memset(arg, 0, sizeof(*arg));
        arg->type = PRINT_FLAGS;
 
-       if (read_expected_item(EVENT_DELIM, (char *)"(") < 0)
+       if (read_expected_item(EVENT_DELIM, "(") < 0)
                return EVENT_ERROR;
 
        field = malloc_or_die(sizeof(*field));
 
        type = process_arg(event, field, &token);
-       if (test_type_token(type, token, EVENT_DELIM, (char *)","))
+       if (test_type_token(type, token, EVENT_DELIM, ","))
                goto out_free;
 
        arg->flags.field = field;
@@ -1515,11 +1536,11 @@ process_flags(struct event *event, struct print_arg *arg, char **tok)
                type = read_token_item(&token);
        }
 
-       if (test_type_token(type, token, EVENT_DELIM, (char *)","))
+       if (test_type_token(type, token, EVENT_DELIM, ","))
                goto out_free;
 
        type = process_fields(event, &arg->flags.flags, &token);
-       if (test_type_token(type, token, EVENT_DELIM, (char *)")"))
+       if (test_type_token(type, token, EVENT_DELIM, ")"))
                goto out_free;
 
        free_token(token);
@@ -1541,19 +1562,19 @@ process_symbols(struct event *event, struct print_arg *arg, char **tok)
        memset(arg, 0, sizeof(*arg));
        arg->type = PRINT_SYMBOL;
 
-       if (read_expected_item(EVENT_DELIM, (char *)"(") < 0)
+       if (read_expected_item(EVENT_DELIM, "(") < 0)
                return EVENT_ERROR;
 
        field = malloc_or_die(sizeof(*field));
 
        type = process_arg(event, field, &token);
-       if (test_type_token(type, token, EVENT_DELIM, (char *)","))
+       if (test_type_token(type, token, EVENT_DELIM, ","))
                goto out_free;
 
        arg->symbol.field = field;
 
        type = process_fields(event, &arg->symbol.symbols, &token);
-       if (test_type_token(type, token, EVENT_DELIM, (char *)")"))
+       if (test_type_token(type, token, EVENT_DELIM, ")"))
                goto out_free;
 
        free_token(token);
@@ -1583,7 +1604,7 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
        if (type == EVENT_ERROR)
                return EVENT_ERROR;
 
-       if (test_type_token(type, token, EVENT_DELIM, (char *)")")) {
+       if (test_type_token(type, token, EVENT_DELIM, ")")) {
                free_token(token);
                return EVENT_ERROR;
        }
@@ -1624,7 +1645,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok)
        enum event_type type;
        char *token;
 
-       if (read_expected(EVENT_DELIM, (char *)"(") < 0)
+       if (read_expected(EVENT_DELIM, "(") < 0)
                return EVENT_ERROR;
 
        if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -1634,7 +1655,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok)
        arg->string.string = token;
        arg->string.offset = -1;
 
-       if (read_expected(EVENT_DELIM, (char *)")") < 0)
+       if (read_expected(EVENT_DELIM, ")") < 0)
                return EVENT_ERROR;
 
        type = read_token(&token);
@@ -1662,9 +1683,11 @@ process_arg_token(struct event *event, struct print_arg *arg,
                        type = process_entry(event, arg, &token);
                } else if (strcmp(token, "__print_flags") == 0) {
                        free_token(token);
+                       is_flag_field = 1;
                        type = process_flags(event, arg, &token);
                } else if (strcmp(token, "__print_symbolic") == 0) {
                        free_token(token);
+                       is_symbolic_field = 1;
                        type = process_symbols(event, arg, &token);
                } else if (strcmp(token, "__get_str") == 0) {
                        free_token(token);
@@ -1773,13 +1796,13 @@ static int event_read_print(struct event *event)
        char *token;
        int ret;
 
-       if (read_expected_item(EVENT_ITEM, (char *)"print") < 0)
+       if (read_expected_item(EVENT_ITEM, "print") < 0)
                return -1;
 
-       if (read_expected(EVENT_ITEM, (char *)"fmt") < 0)
+       if (read_expected(EVENT_ITEM, "fmt") < 0)
                return -1;
 
-       if (read_expected(EVENT_OP, (char *)":") < 0)
+       if (read_expected(EVENT_OP, ":") < 0)
                return -1;
 
        if (read_expect_type(EVENT_DQUOTE, &token) < 0)
@@ -1809,8 +1832,8 @@ static int event_read_print(struct event *event)
                token = cat;
                goto concat;
        }
-                            
-       if (test_type_token(type, token, EVENT_DELIM, (char *)","))
+
+       if (test_type_token(type, token, EVENT_DELIM, ","))
                goto fail;
 
        free_token(token);
@@ -1819,7 +1842,7 @@ static int event_read_print(struct event *event)
        if (ret < 0)
                return -1;
 
-       return 0;
+       return ret;
 
  fail:
        free_token(token);
@@ -1865,7 +1888,7 @@ find_any_field(struct event *event, const char *name)
        return find_field(event, name);
 }
 
-static unsigned long long read_size(void *ptr, int size)
+unsigned long long read_size(void *ptr, int size)
 {
        switch (size) {
        case 1:
@@ -1928,37 +1951,67 @@ static int get_common_info(const char *type, int *offset, int *size)
        return 0;
 }
 
-int trace_parse_common_type(void *data)
+static int __parse_common(void *data, int *size, int *offset,
+                         const char *name)
 {
-       static int type_offset;
-       static int type_size;
        int ret;
 
-       if (!type_size) {
-               ret = get_common_info("common_type",
-                                     &type_offset,
-                                     &type_size);
+       if (!*size) {
+               ret = get_common_info(name, offset, size);
                if (ret < 0)
                        return ret;
        }
-       return read_size(data + type_offset, type_size);
+       return read_size(data + *offset, *size);
+}
+
+int trace_parse_common_type(void *data)
+{
+       static int type_offset;
+       static int type_size;
+
+       return __parse_common(data, &type_size, &type_offset,
+                             "common_type");
 }
 
-static int parse_common_pid(void *data)
+int trace_parse_common_pid(void *data)
 {
        static int pid_offset;
        static int pid_size;
+
+       return __parse_common(data, &pid_size, &pid_offset,
+                             "common_pid");
+}
+
+int parse_common_pc(void *data)
+{
+       static int pc_offset;
+       static int pc_size;
+
+       return __parse_common(data, &pc_size, &pc_offset,
+                             "common_preempt_count");
+}
+
+int parse_common_flags(void *data)
+{
+       static int flags_offset;
+       static int flags_size;
+
+       return __parse_common(data, &flags_size, &flags_offset,
+                             "common_flags");
+}
+
+int parse_common_lock_depth(void *data)
+{
+       static int ld_offset;
+       static int ld_size;
        int ret;
 
-       if (!pid_size) {
-               ret = get_common_info("common_pid",
-                                     &pid_offset,
-                                     &pid_size);
-               if (ret < 0)
-                       return ret;
-       }
+       ret = __parse_common(data, &ld_size, &ld_offset,
+                            "common_lock_depth");
+       if (ret < 0)
+               return -1;
 
-       return read_size(data + pid_offset, pid_size);
+       return ret;
 }
 
 struct event *trace_find_event(int id)
@@ -1972,6 +2025,14 @@ struct event *trace_find_event(int id)
        return event;
 }
 
+struct event *trace_find_next_event(struct event *event)
+{
+       if (!event)
+               return event_list;
+
+       return event->next;
+}
+
 static unsigned long long eval_num_arg(void *data, int size,
                                   struct event *event, struct print_arg *arg)
 {
@@ -2074,6 +2135,12 @@ static unsigned long long eval_num_arg(void *data, int size,
                                die("unknown op '%s'", arg->op.op);
                        val = left == right;
                        break;
+               case '-':
+                       val = left - right;
+                       break;
+               case '+':
+                       val = left + right;
+                       break;
                default:
                        die("unknown op '%s'", arg->op.op);
                }
@@ -2105,7 +2172,7 @@ static const struct flag flags[] = {
        { "HRTIMER_RESTART", 1 },
 };
 
-static unsigned long long eval_flag(const char *flag)
+unsigned long long eval_flag(const char *flag)
 {
        int i;
 
@@ -2525,6 +2592,41 @@ static inline int log10_cpu(int nb)
        return 1;
 }
 
+static void print_lat_fmt(void *data, int size __unused)
+{
+       unsigned int lat_flags;
+       unsigned int pc;
+       int lock_depth;
+       int hardirq;
+       int softirq;
+
+       lat_flags = parse_common_flags(data);
+       pc = parse_common_pc(data);
+       lock_depth = parse_common_lock_depth(data);
+
+       hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
+       softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
+
+       printf("%c%c%c",
+              (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
+              (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
+              'X' : '.',
+              (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
+              'N' : '.',
+              (hardirq && softirq) ? 'H' :
+              hardirq ? 'h' : softirq ? 's' : '.');
+
+       if (pc)
+               printf("%x", pc);
+       else
+               printf(".");
+
+       if (lock_depth < 0)
+               printf(".");
+       else
+               printf("%d", lock_depth);
+}
+
 /* taken from Linux, written by Frederic Weisbecker */
 static void print_graph_cpu(int cpu)
 {
@@ -2600,7 +2702,7 @@ get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
        if (!(event->flags & EVENT_FL_ISFUNCRET))
                return NULL;
 
-       pid = parse_common_pid(next->data);
+       pid = trace_parse_common_pid(next->data);
        field = find_field(event, "func");
        if (!field)
                die("function return does not have field func");
@@ -2768,6 +2870,11 @@ pretty_print_func_ent(void *data, int size, struct event *event,
 
        printf(" | ");
 
+       if (latency_format) {
+               print_lat_fmt(data, size);
+               printf(" | ");
+       }
+
        field = find_field(event, "func");
        if (!field)
                die("function entry does not have func field");
@@ -2811,6 +2918,11 @@ pretty_print_func_ret(void *data, int size __unused, struct event *event,
 
        printf(" | ");
 
+       if (latency_format) {
+               print_lat_fmt(data, size);
+               printf(" | ");
+       }
+
        field = find_field(event, "rettime");
        if (!field)
                die("can't find rettime in return graph");
@@ -2876,15 +2988,20 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
                return;
        }
 
-       pid = parse_common_pid(data);
+       pid = trace_parse_common_pid(data);
 
        if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
                return pretty_print_func_graph(data, size, event, cpu,
                                               pid, comm, secs, usecs);
 
-       printf("%16s-%-5d [%03d] %5lu.%09Lu: %s: ",
-              comm, pid,  cpu,
-              secs, nsecs, event->name);
+       if (latency_format) {
+               printf("%8.8s-%-5d %3d",
+                      comm, pid, cpu);
+               print_lat_fmt(data, size);
+       } else
+               printf("%16s-%-5d [%03d]", comm, pid,  cpu);
+
+       printf(" %5lu.%06lu: %s: ", secs, usecs, event->name);
 
        if (event->flags & EVENT_FL_FAILED) {
                printf("EVENT '%s' FAILED TO PARSE\n",
@@ -2961,15 +3078,15 @@ static void print_args(struct print_arg *args)
        }
 }
 
-static void parse_header_field(char *field,
+static void parse_header_field(const char *field,
                               int *offset, int *size)
 {
        char *token;
        int type;
 
-       if (read_expected(EVENT_ITEM, (char *)"field") < 0)
+       if (read_expected(EVENT_ITEM, "field") < 0)
                return;
-       if (read_expected(EVENT_OP, (char *)":") < 0)
+       if (read_expected(EVENT_OP, ":") < 0)
                return;
 
        /* type */
@@ -2979,27 +3096,27 @@ static void parse_header_field(char *field,
 
        if (read_expected(EVENT_ITEM, field) < 0)
                return;
-       if (read_expected(EVENT_OP, (char *)";") < 0)
+       if (read_expected(EVENT_OP, ";") < 0)
                return;
-       if (read_expected(EVENT_ITEM, (char *)"offset") < 0)
+       if (read_expected(EVENT_ITEM, "offset") < 0)
                return;
-       if (read_expected(EVENT_OP, (char *)":") < 0)
+       if (read_expected(EVENT_OP, ":") < 0)
                return;
        if (read_expect_type(EVENT_ITEM, &token) < 0)
                goto fail;
        *offset = atoi(token);
        free_token(token);
-       if (read_expected(EVENT_OP, (char *)";") < 0)
+       if (read_expected(EVENT_OP, ";") < 0)
                return;
-       if (read_expected(EVENT_ITEM, (char *)"size") < 0)
+       if (read_expected(EVENT_ITEM, "size") < 0)
                return;
-       if (read_expected(EVENT_OP, (char *)":") < 0)
+       if (read_expected(EVENT_OP, ":") < 0)
                return;
        if (read_expect_type(EVENT_ITEM, &token) < 0)
                goto fail;
        *size = atoi(token);
        free_token(token);
-       if (read_expected(EVENT_OP, (char *)";") < 0)
+       if (read_expected(EVENT_OP, ";") < 0)
                return;
        type = read_token(&token);
        if (type != EVENT_NEWLINE) {
@@ -3007,19 +3124,19 @@ static void parse_header_field(char *field,
                if (type != EVENT_ITEM)
                        goto fail;
 
-               if (strcmp(token, (char *)"signed") != 0)
+               if (strcmp(token, "signed") != 0)
                        goto fail;
 
                free_token(token);
 
-               if (read_expected(EVENT_OP, (char *)":") < 0)
+               if (read_expected(EVENT_OP, ":") < 0)
                        return;
 
                if (read_expect_type(EVENT_ITEM, &token))
                        goto fail;
 
                free_token(token);
-               if (read_expected(EVENT_OP, (char *)";") < 0)
+               if (read_expected(EVENT_OP, ";") < 0)
                        return;
 
                if (read_expect_type(EVENT_NEWLINE, &token))
@@ -3033,11 +3150,11 @@ int parse_header_page(char *buf, unsigned long size)
 {
        init_input_buf(buf, size);
 
-       parse_header_field((char *)"timestamp", &header_page_ts_offset,
+       parse_header_field("timestamp", &header_page_ts_offset,
                           &header_page_ts_size);
-       parse_header_field((char *)"commit", &header_page_size_offset,
+       parse_header_field("commit", &header_page_size_offset,
                           &header_page_size_size);
-       parse_header_field((char *)"data", &header_page_data_offset,
+       parse_header_field("data", &header_page_data_offset,
                           &header_page_data_size);
 
        return 0;
@@ -3088,6 +3205,9 @@ int parse_ftrace_file(char *buf, unsigned long size)
        if (ret < 0)
                die("failed to read ftrace event print fmt");
 
+       /* New ftrace handles args */
+       if (ret > 0)
+               return 0;
        /*
         * The arguments for ftrace files are parsed by the fields.
         * Set up the fields as their arguments.