From 26a50744b21fff65bd754874072857bee8967f4d Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Tue, 6 Oct 2009 01:09:50 -0500 Subject: tracing/events: Add 'signed' field to format files The sign info used for filters in the kernel is also useful to applications that process the trace stream. Add it to the format files and make it available to userspace. Signed-off-by: Tom Zanussi Acked-by: Frederic Weisbecker Cc: rostedt@goodmis.org Cc: lizf@cn.fujitsu.com Cc: hch@infradead.org Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo LKML-Reference: <1254809398-8078-2-git-send-email-tzanussi@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 55b41b9e3834..be8412d699a1 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -894,6 +894,21 @@ 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) + goto fail_expect; + + if (read_expected(EVENT_ITEM, (char *)"signed") < 0) + goto fail_expect; + + if (read_expected(EVENT_OP, (char *)":") < 0) + goto fail_expect; + + if (read_expect_type(EVENT_ITEM, &token)) + goto fail; + if (strtoul(token, NULL, 0)) + field->flags |= FIELD_IS_SIGNED; + free_token(token); + if (read_expected(EVENT_OP, (char *)";") < 0) goto fail_expect; @@ -2843,6 +2858,15 @@ static void parse_header_field(char *type, return; *size = atoi(token); free_token(token); + if (read_expected(EVENT_OP, (char *)";") < 0) + return; + if (read_expected(EVENT_ITEM, (char *)"signed") < 0) + return; + if (read_expected(EVENT_OP, (char *)":") < 0) + return; + if (read_expect_type(EVENT_ITEM, &token) < 0) + return; + free_token(token); if (read_expected(EVENT_OP, (char *)";") < 0) return; if (read_expect_type(EVENT_NEWLINE, &token) < 0) -- cgit v1.2.2 From 2774601811bedd04ee7e38624343ea80b4a62d7e Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Tue, 6 Oct 2009 01:09:51 -0500 Subject: perf trace: Add subsystem string to struct event Needed to fully qualify event names for event stream processing. Signed-off-by: Tom Zanussi Acked-by: Frederic Weisbecker Cc: rostedt@goodmis.org Cc: lizf@cn.fujitsu.com Cc: hch@infradead.org Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo LKML-Reference: <1254809398-8078-3-git-send-email-tzanussi@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index be8412d699a1..de3fc8bf8bfe 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -2950,7 +2950,7 @@ int parse_ftrace_file(char *buf, unsigned long size) return 0; } -int parse_event_file(char *buf, unsigned long size, char *system__unused __unused) +int parse_event_file(char *buf, unsigned long size, char *sys) { struct event *event; int ret; @@ -2977,6 +2977,8 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse if (ret < 0) die("failed to read event print fmt"); + event->system = strdup(sys); + #define PRINT_ARGS 0 if (PRINT_ARGS && event->print_fmt.args) print_args(event->print_fmt.args); -- cgit v1.2.2 From 064739bc4b3d7f424b2f25547e6611bcf0132415 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Tue, 6 Oct 2009 01:09:52 -0500 Subject: perf trace: Add string/dynamic cases to format_flags Needed for distinguishing string fields in event stream processing. Signed-off-by: Tom Zanussi Acked-by: Frederic Weisbecker Cc: rostedt@goodmis.org Cc: lizf@cn.fujitsu.com Cc: hch@infradead.org Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo LKML-Reference: <1254809398-8078-4-git-send-email-tzanussi@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index de3fc8bf8bfe..6f851f98b5b4 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -721,6 +721,24 @@ static int event_read_id(void) return -1; } +static int field_is_string(struct format_field *field) +{ + if ((field->flags & FIELD_IS_ARRAY) && + (!strstr(field->type, "char") || !strstr(field->type, "u8") || + !strstr(field->type, "s8"))) + return 1; + + return 0; +} + +static int field_is_dynamic(struct format_field *field) +{ + if (!strcmp(field->type, "__data_loc")) + return 1; + + return 0; +} + static int event_read_fields(struct event *event, struct format_field **fields) { struct format_field *field = NULL; @@ -865,6 +883,12 @@ static int event_read_fields(struct event *event, struct format_field **fields) free(brackets); } + if (field_is_string(field)) { + field->flags |= FIELD_IS_STRING; + if (field_is_dynamic(field)) + field->flags |= FIELD_IS_DYNAMIC; + } + if (test_type_token(type, token, EVENT_OP, (char *)";")) goto fail; free_token(token); -- cgit v1.2.2 From 924a79af2cdee26a034b9bdce8c9c76995b5c901 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 14 Oct 2009 15:43:32 -0400 Subject: perf tools: Handle print concatenations in event format file kmem_alloc ftrace event format had a string that was broken up by two tokens. "string 1" "string 2". This patch lets the parser be able to handle the concatenation. Signed-off-by: Steven Rostedt Cc: Peter Zijlstra Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo LKML-Reference: <20091014194357.253818714@goodmis.org> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index eef60df7a5bf..a05c7144aded 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -1734,6 +1734,7 @@ static int event_read_print(struct event *event) if (read_expect_type(EVENT_DQUOTE, &token) < 0) goto fail; + concat: event->print_fmt.format = token; event->print_fmt.args = NULL; @@ -1743,6 +1744,21 @@ static int event_read_print(struct event *event) if (type == EVENT_NONE) return 0; + /* Handle concatination of print lines */ + if (type == EVENT_DQUOTE) { + char *cat; + + cat = malloc_or_die(strlen(event->print_fmt.format) + + strlen(token) + 1); + strcpy(cat, event->print_fmt.format); + strcat(cat, token); + free_token(token); + free_token(event->print_fmt.format); + event->print_fmt.format = NULL; + token = cat; + goto concat; + } + if (test_type_token(type, token, EVENT_DELIM, (char *)",")) goto fail; -- cgit v1.2.2 From 91ff2bc191827f0d3f5ad0a433ff7df7d2dd9aee Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 14 Oct 2009 15:43:33 -0400 Subject: perf tools: Fix backslash processing on trace print formats The handling of backslashes was broken. It would stop parsing when encountering one. Also, '\n', '\t', '\r' and '\\' were not converted. Signed-off-by: Steven Rostedt Cc: Peter Zijlstra Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo LKML-Reference: <20091014194357.521974680@goodmis.org> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index a05c7144aded..2b75ec2f57e8 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -522,7 +522,10 @@ static enum event_type __read_token(char **tok) last_ch = ch; ch = __read_char(); buf[i++] = ch; - } while (ch != quote_ch && last_ch != '\\'); + /* the '\' '\' will cancel itself */ + if (ch == '\\' && last_ch == '\\') + last_ch = 0; + } while (ch != quote_ch || last_ch == '\\'); /* remove the last quote */ i--; goto out; @@ -2325,7 +2328,27 @@ static void pretty_print(void *data, int size, struct event *event) for (; *ptr; ptr++) { ls = 0; - if (*ptr == '%') { + if (*ptr == '\\') { + ptr++; + switch (*ptr) { + case 'n': + printf("\n"); + break; + case 't': + printf("\t"); + break; + case 'r': + printf("\r"); + break; + case '\\': + printf("\\"); + break; + default: + printf("%c", *ptr); + break; + } + + } else if (*ptr == '%') { saveptr = ptr; show_func = 0; cont_process: -- cgit v1.2.2 From 298ebc3ef2a6c569b3eb51651f04e26aecbf8a1d Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 14 Oct 2009 15:43:34 -0400 Subject: perf tools: Handle trace parsing of < and > The code to handle the '<' and '>' ops was all in place, but they were not in the switch statement to consider them as valid ops. Signed-off-by: Steven Rostedt Cc: Peter Zijlstra Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo LKML-Reference: <20091014194357.807434040@goodmis.org> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 2b75ec2f57e8..3e643f5da202 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -1170,6 +1170,8 @@ process_op(struct event *event, struct print_arg *arg, char **tok) strcmp(token, "*") == 0 || strcmp(token, "^") == 0 || strcmp(token, "/") == 0 || + strcmp(token, "<") == 0 || + strcmp(token, ">") == 0 || strcmp(token, "==") == 0 || strcmp(token, "!=") == 0) { -- cgit v1.2.2 From 0959b8d65ce26131c2d5ccfa518a7b76529280fa Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 14 Oct 2009 15:43:35 -0400 Subject: perf tools: Handle arrays in print fields for trace parsing The array used by the ftrace stack events (caller[x]) causes issues with the parser. This adds code to handle the case, but it also assumes that the array is of type long. Note, this is a special case used (currently) only by the ftrace user and kernel stack records. Signed-off-by: Steven Rostedt Cc: Peter Zijlstra Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo LKML-Reference: <20091014194358.124833639@goodmis.org> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 62 +++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 3e643f5da202..7aeedb09ea7d 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -1046,6 +1046,35 @@ out_free: return EVENT_ERROR; } +static enum event_type +process_array(struct event *event, struct print_arg *top, char **tok) +{ + struct print_arg *arg; + enum event_type type; + char *token = NULL; + + arg = malloc_or_die(sizeof(*arg)); + memset(arg, 0, sizeof(*arg)); + + *tok = NULL; + type = process_arg(event, arg, &token); + if (test_type_token(type, token, EVENT_OP, (char *)"]")) + goto out_free; + + top->op.right = arg; + + free_token(token); + type = read_token_item(&token); + *tok = token; + + return type; + +out_free: + free_token(*tok); + free_arg(arg); + return EVENT_ERROR; +} + static int get_op_prio(char *op) { if (!op[1]) { @@ -1192,6 +1221,18 @@ process_op(struct event *event, struct print_arg *arg, char **tok) arg->op.right = right; + } else if (strcmp(token, "[") == 0) { + + left = malloc_or_die(sizeof(*left)); + *left = *arg; + + arg->type = PRINT_OP; + arg->op.op = token; + arg->op.left = left; + + arg->op.prio = 0; + type = process_array(event, arg, tok); + } else { die("unknown op '%s'", token); /* the arg is now the left side */ @@ -1931,6 +1972,7 @@ static unsigned long long eval_num_arg(void *data, int size, { unsigned long long val = 0; unsigned long long left, right; + struct print_arg *larg; switch (arg->type) { case PRINT_NULL: @@ -1957,6 +1999,26 @@ static unsigned long long eval_num_arg(void *data, int size, return 0; break; case PRINT_OP: + if (strcmp(arg->op.op, "[") == 0) { + /* + * Arrays are special, since we don't want + * to read the arg as is. + */ + if (arg->op.left->type != PRINT_FIELD) + goto default_op; /* oops, all bets off */ + larg = arg->op.left; + if (!larg->field.field) { + larg->field.field = + find_any_field(event, larg->field.name); + if (!larg->field.field) + die("field %s not found", larg->field.name); + } + right = eval_num_arg(data, size, event, arg->op.right); + val = read_size(data + larg->field.field->offset + + right * long_size, long_size); + break; + } + default_op: left = eval_num_arg(data, size, event, arg->op.left); right = eval_num_arg(data, size, event, arg->op.right); switch (arg->op.op[0]) { -- cgit v1.2.2 From b99af874829cba2b30d212bc6fd31b56275ee4d2 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 14 Oct 2009 15:43:36 -0400 Subject: perf tools: Handle * as typecast in trace parsing The '*' is currently only treated as a multiplication, and it needs to be handled as a typecast pointer. This is the version used by trace-cmd. Signed-off-by: Steven Rostedt Cc: Peter Zijlstra Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo LKML-Reference: <20091014194358.409327875@goodmis.org> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 50 ++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 28 deletions(-) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 7aeedb09ea7d..f73ee55b51e8 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -1217,7 +1217,24 @@ process_op(struct event *event, struct print_arg *arg, char **tok) right = malloc_or_die(sizeof(*right)); - type = process_arg(event, right, tok); + type = read_token_item(&token); + *tok = token; + + /* could just be a type pointer */ + if ((strcmp(arg->op.op, "*") == 0) && + type == EVENT_DELIM && (strcmp(token, ")") == 0)) { + if (left->type != PRINT_ATOM) + die("bad pointer type"); + left->atom.atom = realloc(left->atom.atom, + sizeof(left->atom.atom) + 3); + strcat(left->atom.atom, " *"); + *arg = *left; + free(arg); + + return type; + } + + type = process_arg_token(event, right, tok, type); arg->op.right = right; @@ -1548,7 +1565,6 @@ process_paren(struct event *event, struct print_arg *arg, char **tok) { struct print_arg *item_arg; enum event_type type; - int ptr_cast = 0; char *token; type = process_arg(event, arg, &token); @@ -1556,26 +1572,11 @@ process_paren(struct event *event, struct print_arg *arg, char **tok) if (type == EVENT_ERROR) return EVENT_ERROR; - if (type == EVENT_OP) { - /* handle the ptr casts */ - if (!strcmp(token, "*")) { - /* - * FIXME: should we zapp whitespaces before ')' ? - * (may require a peek_token_item()) - */ - if (__peek_char() == ')') { - ptr_cast = 1; - free_token(token); - type = read_token_item(&token); - } - } - if (!ptr_cast) { - type = process_op(event, arg, &token); + if (type == EVENT_OP) + type = process_op(event, arg, &token); - if (type == EVENT_ERROR) - return EVENT_ERROR; - } - } + if (type == EVENT_ERROR) + return EVENT_ERROR; if (test_type_token(type, token, EVENT_DELIM, (char *)")")) { free_token(token); @@ -1601,13 +1602,6 @@ process_paren(struct event *event, struct print_arg *arg, char **tok) item_arg = malloc_or_die(sizeof(*item_arg)); arg->type = PRINT_TYPE; - if (ptr_cast) { - char *old = arg->atom.atom; - - arg->atom.atom = malloc_or_die(strlen(old + 3)); - sprintf(arg->atom.atom, "%s *", old); - free(old); - } arg->typecast.type = arg->atom.atom; arg->typecast.item = item_arg; type = process_arg_token(event, item_arg, &token, type); -- cgit v1.2.2 From f1d1feecf07261d083859ecfef0d4399036f9683 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 14 Oct 2009 15:43:37 -0400 Subject: perf tools: Handle newlines in trace parsing better New lines between args in the trace format can break the parsing. This should not be the case. Signed-off-by: Steven Rostedt Cc: Peter Zijlstra Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo LKML-Reference: <20091014194358.637991808@goodmis.org> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index f73ee55b51e8..59e4e4db7438 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -1716,12 +1716,18 @@ process_arg_token(struct event *event, struct print_arg *arg, static int event_read_print_args(struct event *event, struct print_arg **list) { - enum event_type type; + enum event_type type = EVENT_ERROR; struct print_arg *arg; char *token; int args = 0; do { + if (type == EVENT_NEWLINE) { + free_token(token); + type = read_token_item(&token); + continue; + } + arg = malloc_or_die(sizeof(*arg)); memset(arg, 0, sizeof(*arg)); -- cgit v1.2.2 From 13999e59343b042b0807be2df6ae5895d29782a0 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 14 Oct 2009 15:43:38 -0400 Subject: perf tools: Handle the case with and without the "signed" trace field The trace format files now have a "signed" field. But we should still be able to handle the kernels that do not have this field. Signed-off-by: Steven Rostedt Cc: Peter Zijlstra Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo LKML-Reference: <20091014194358.888239553@goodmis.org> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 81 ++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 29 deletions(-) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 59e4e4db7438..0739b12675f0 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -924,23 +924,30 @@ static int event_read_fields(struct event *event, struct format_field **fields) if (read_expected(EVENT_OP, (char *)";") < 0) goto fail_expect; - if (read_expected(EVENT_ITEM, (char *)"signed") < 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")) + goto fail; - if (read_expected(EVENT_OP, (char *)":") < 0) - goto fail_expect; + free_token(token); - if (read_expect_type(EVENT_ITEM, &token)) - goto fail; - if (strtoul(token, NULL, 0)) - field->flags |= FIELD_IS_SIGNED; - free_token(token); + if (read_expected(EVENT_OP, (char *)":") < 0) + goto fail_expect; - if (read_expected(EVENT_OP, (char *)";") < 0) - goto fail_expect; + if (read_expect_type(EVENT_ITEM, &token)) + goto fail; + + /* add signed type */ + + free_token(token); + if (read_expected(EVENT_OP, (char *)";") < 0) + goto fail_expect; + + if (read_expect_type(EVENT_NEWLINE, &token)) + goto fail; + } - if (read_expect_type(EVENT_NEWLINE, &token) < 0) - goto fail; free_token(token); *fields = field; @@ -2949,21 +2956,23 @@ static void print_args(struct print_arg *args) } } -static void parse_header_field(char *type, +static void parse_header_field(char *field, int *offset, int *size) { char *token; + int type; if (read_expected(EVENT_ITEM, (char *)"field") < 0) return; if (read_expected(EVENT_OP, (char *)":") < 0) return; + /* type */ if (read_expect_type(EVENT_ITEM, &token) < 0) - return; + goto fail; free_token(token); - if (read_expected(EVENT_ITEM, type) < 0) + if (read_expected(EVENT_ITEM, field) < 0) return; if (read_expected(EVENT_OP, (char *)";") < 0) return; @@ -2972,7 +2981,7 @@ static void parse_header_field(char *type, if (read_expected(EVENT_OP, (char *)":") < 0) return; if (read_expect_type(EVENT_ITEM, &token) < 0) - return; + goto fail; *offset = atoi(token); free_token(token); if (read_expected(EVENT_OP, (char *)";") < 0) @@ -2982,22 +2991,36 @@ static void parse_header_field(char *type, if (read_expected(EVENT_OP, (char *)":") < 0) return; if (read_expect_type(EVENT_ITEM, &token) < 0) - return; + goto fail; *size = atoi(token); free_token(token); if (read_expected(EVENT_OP, (char *)";") < 0) return; - if (read_expected(EVENT_ITEM, (char *)"signed") < 0) - return; - if (read_expected(EVENT_OP, (char *)":") < 0) - return; - if (read_expect_type(EVENT_ITEM, &token) < 0) - return; - free_token(token); - if (read_expected(EVENT_OP, (char *)";") < 0) - return; - if (read_expect_type(EVENT_NEWLINE, &token) < 0) - return; + type = read_token(&token); + if (type != EVENT_NEWLINE) { + /* newer versions of the kernel have a "signed" type */ + if (type != EVENT_ITEM) + goto fail; + + if (strcmp(token, (char *)"signed") != 0) + goto fail; + + free_token(token); + + if (read_expected(EVENT_OP, (char *)":") < 0) + return; + + if (read_expect_type(EVENT_ITEM, &token)) + goto fail; + + free_token(token); + if (read_expected(EVENT_OP, (char *)";") < 0) + return; + + if (read_expect_type(EVENT_NEWLINE, &token)) + goto fail; + } + fail: free_token(token); } -- cgit v1.2.2 From 07a4bdddcf2546ccfbfb3c782deab636c371edeb Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 14 Oct 2009 15:43:39 -0400 Subject: perf tools: Still continue on failed parsing of an event Even though an event may fail to parse, we should not kill the entire report. The trace should still be able to show what it can. If an event fails to parse, a warning is printed, and the output continues. Signed-off-by: Steven Rostedt Cc: Peter Zijlstra Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo LKML-Reference: <20091014194359.190809589@goodmis.org> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 38 ++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 0739b12675f0..eda0a2488c19 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -613,7 +613,7 @@ static enum event_type read_token_item(char **tok) static int test_type(enum event_type type, enum event_type expect) { if (type != expect) { - die("Error: expected type %d but read %d", + warning("Error: expected type %d but read %d", expect, type); return -1; } @@ -624,13 +624,13 @@ static int test_type_token(enum event_type type, char *token, enum event_type expect, const char *expect_tok) { if (type != expect) { - die("Error: expected type %d but read %d", + warning("Error: expected type %d but read %d", expect, type); return -1; } if (strcmp(token, expect_tok) != 0) { - die("Error: expected '%s' but read '%s'", + warning("Error: expected '%s' but read '%s'", expect_tok, token); return -1; } @@ -668,7 +668,7 @@ static int __read_expected(enum event_type expect, const char *str, int newline_ free_token(token); - return 0; + return ret; } static int read_expected(enum event_type expect, const char *str) @@ -1258,12 +1258,12 @@ process_op(struct event *event, struct print_arg *arg, char **tok) type = process_array(event, arg, tok); } else { - die("unknown op '%s'", token); + warning("unknown op '%s'", token); + event->flags |= EVENT_FL_FAILED; /* the arg is now the left side */ return EVENT_NONE; } - if (type == EVENT_OP) { int prio; @@ -2873,7 +2873,7 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs, event = trace_find_event(type); if (!event) { - printf("ug! no event found for type %d\n", type); + warning("ug! no event found for type %d", type); return; } @@ -2887,6 +2887,12 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs, comm, pid, cpu, secs, nsecs, event->name); + if (event->flags & EVENT_FL_FAILED) { + printf("EVENT '%s' FAILED TO PARSE\n", + event->name); + return; + } + pretty_print(data, size, event); printf("\n"); } @@ -3120,12 +3126,16 @@ int parse_event_file(char *buf, unsigned long size, char *sys) die("failed to read event id"); ret = event_read_format(event); - if (ret < 0) - die("failed to read event format"); + if (ret < 0) { + warning("failed to read event format for %s", event->name); + goto event_failed; + } ret = event_read_print(event); - if (ret < 0) - die("failed to read event print fmt"); + if (ret < 0) { + warning("failed to read event print fmt for %s", event->name); + goto event_failed; + } event->system = strdup(sys); @@ -3135,6 +3145,12 @@ int parse_event_file(char *buf, unsigned long size, char *sys) add_event(event); return 0; + + event_failed: + event->flags |= EVENT_FL_FAILED; + /* still add it even if it failed */ + add_event(event); + return -1; } void parse_set_info(int nr_cpus, int long_sz) -- cgit v1.2.2 From ffa1895561645103d8f8059b35d9c06e6eeead2e Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 14 Oct 2009 15:43:40 -0400 Subject: perf tools: Fix bprintk reading in trace output The bprintk parsing was broken in more ways than one. The file parsing was incorrect, and the words used by the arguments are always 4 bytes aligned, even on 64-bit machines. Signed-off-by: Steven Rostedt Cc: Peter Zijlstra Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo LKML-Reference: <20091014194359.520931637@goodmis.org> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index eda0a2488c19..93a82fead958 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -284,18 +284,16 @@ void parse_ftrace_printk(char *file, unsigned int size __unused) char *line; char *next = NULL; char *addr_str; - int ret; + char *fmt; int i; line = strtok_r(file, "\n", &next); while (line) { item = malloc_or_die(sizeof(*item)); - ret = sscanf(line, "%as : %as", - (float *)(void *)&addr_str, /* workaround gcc warning */ - (float *)(void *)&item->printk); + addr_str = strtok_r(line, ":", &fmt); item->addr = strtoull(addr_str, NULL, 16); - free(addr_str); - + /* fmt still has a space, skip it */ + item->printk = strdup(fmt+1); item->next = list; list = item; line = strtok_r(NULL, "\n", &next); @@ -2274,8 +2272,9 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc case 'u': case 'x': case 'i': - bptr = (void *)(((unsigned long)bptr + (long_size - 1)) & - ~(long_size - 1)); + /* the pointers are always 4 bytes aligned */ + bptr = (void *)(((unsigned long)bptr + 3) & + ~3); switch (ls) { case 0: case 1: -- cgit v1.2.2 From 0d1da915c76838c9ee7af7cdefbcb2bae9424161 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 14 Oct 2009 15:43:41 -0400 Subject: perf tools: Handle both versions of ftrace output The ftrace output events can have either arguments or no arguments. The parser needs to be able to handle both. Signed-off-by: Steven Rostedt Cc: Peter Zijlstra Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo LKML-Reference: <20091014194359.790221427@goodmis.org> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 93a82fead958..c174765d4056 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -1819,7 +1819,7 @@ static int event_read_print(struct event *event) if (ret < 0) return -1; - return 0; + return ret; fail: free_token(token); @@ -3088,6 +3088,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. -- cgit v1.2.2 From cda48461c7fb8431a99b7960480f5f42cc1a5324 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 14 Oct 2009 15:43:42 -0400 Subject: perf tools: Add latency format to trace output Add the irqs disabled, preemption count, need resched, and other info that is shown in the latency format of ftrace. # perf trace -l perf-16457 2..s2. 53636.260344: kmem_cache_free: call_site=ffffffff811198f perf-16457 2..s2. 53636.264330: kmem_cache_free: call_site=ffffffff811198f perf-16457 2d.s4. 53636.300006: kmem_cache_free: call_site=ffffffff810d889 Signed-off-by: Steven Rostedt Cc: Peter Zijlstra Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo LKML-Reference: <20091014194400.076588953@goodmis.org> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 120 ++++++++++++++++++++++++++++++------ 1 file changed, 101 insertions(+), 19 deletions(-) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index c174765d4056..fde1a434d630 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -40,6 +40,8 @@ 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; @@ -1928,37 +1930,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, + 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, + (char *)"common_type"); } static int parse_common_pid(void *data) { static int pid_offset; static int pid_size; + + return __parse_common(data, &pid_size, &pid_offset, + (char *)"common_pid"); +} + +static int parse_common_pc(void *data) +{ + static int pc_offset; + static int pc_size; + + return __parse_common(data, &pc_size, &pc_offset, + (char *)"common_preempt_count"); +} + +static int parse_common_flags(void *data) +{ + static int flags_offset; + static int flags_size; + + return __parse_common(data, &flags_size, &flags_offset, + (char *)"common_flags"); +} + +static 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, + (char *)"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) @@ -2525,6 +2557,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) { @@ -2768,6 +2835,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 +2883,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"); @@ -2882,9 +2959,14 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs, 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", -- cgit v1.2.2 From afdf1a404eed236d6f762ee44cc0f1dcc97206e0 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 14 Oct 2009 15:43:43 -0400 Subject: perf tools: Handle - and + in parsing trace print format The opterators '-' and '+' are not handled in the trace print format. To do: '++' and '--'. Signed-off-by: Steven Rostedt Cc: Peter Zijlstra Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo LKML-Reference: <20091014194400.330843045@goodmis.org> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index fde1a434d630..2d424ff50ec2 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -2106,6 +2106,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); } -- cgit v1.2.2 From c4dc775f53136cd6af8f88bce67cce9b42751768 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 14 Oct 2009 15:43:44 -0400 Subject: perf tools: Remove all char * typecasts and use const in prototype The (char *) for all the static strings was a fix for the symptom and not the disease. The real issue was that the function prototypes needed to be declared "const char *". Signed-off-by: Steven Rostedt Cc: Peter Zijlstra Cc: Frederic Weisbecker Cc: Arnaldo Carvalho de Melo LKML-Reference: <20091014194400.635935008@goodmis.org> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 122 ++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 61 deletions(-) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 2d424ff50ec2..4b61b497040e 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -685,10 +685,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) @@ -706,10 +706,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) @@ -759,7 +759,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); @@ -774,7 +774,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) @@ -892,14 +892,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)) @@ -907,13 +907,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)) @@ -921,18 +921,18 @@ 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)) @@ -941,7 +941,7 @@ static int event_read_fields(struct event *event, struct format_field **fields) /* add signed type */ 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)) @@ -970,10 +970,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)) @@ -1033,7 +1033,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; @@ -1065,7 +1065,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; @@ -1287,7 +1287,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) @@ -1447,14 +1447,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)); @@ -1465,7 +1465,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); @@ -1500,13 +1500,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; @@ -1517,11 +1517,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); @@ -1543,19 +1543,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); @@ -1585,7 +1585,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; } @@ -1626,7 +1626,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) @@ -1636,7 +1636,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); @@ -1775,13 +1775,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) @@ -1811,8 +1811,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); @@ -1931,7 +1931,7 @@ static int get_common_info(const char *type, int *offset, int *size) } static int __parse_common(void *data, int *size, int *offset, - char *name) + const char *name) { int ret; @@ -1949,7 +1949,7 @@ int trace_parse_common_type(void *data) static int type_size; return __parse_common(data, &type_size, &type_offset, - (char *)"common_type"); + "common_type"); } static int parse_common_pid(void *data) @@ -1958,7 +1958,7 @@ static int parse_common_pid(void *data) static int pid_size; return __parse_common(data, &pid_size, &pid_offset, - (char *)"common_pid"); + "common_pid"); } static int parse_common_pc(void *data) @@ -1967,7 +1967,7 @@ static int parse_common_pc(void *data) static int pc_size; return __parse_common(data, &pc_size, &pc_offset, - (char *)"common_preempt_count"); + "common_preempt_count"); } static int parse_common_flags(void *data) @@ -1976,7 +1976,7 @@ static int parse_common_flags(void *data) static int flags_size; return __parse_common(data, &flags_size, &flags_offset, - (char *)"common_flags"); + "common_flags"); } static int parse_common_lock_depth(void *data) @@ -1986,7 +1986,7 @@ static int parse_common_lock_depth(void *data) int ret; ret = __parse_common(data, &ld_size, &ld_offset, - (char *)"common_lock_depth"); + "common_lock_depth"); if (ret < 0) return -1; @@ -3049,15 +3049,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 */ @@ -3067,27 +3067,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) { @@ -3095,19 +3095,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)) @@ -3121,11 +3121,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; -- cgit v1.2.2 From 4e3b799d7dbb2a12ca8dca8d3594d32095772973 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 20 Oct 2009 19:19:35 -0400 Subject: perf tools: Use strsep() over strtok_r() for parsing single line The second argument in the strtok_r() function is not to be used generically and can have different implementations. Currently the function parsing of the perf trace code uses the second argument to copy data from. This can crash the tool or just have unpredictable results. The correct solution is to use strsep() which has a defined result. I also added a check to see if the result was correct, and will break out of the loop in case it fails to parse as expected. Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Steven Rostedt Cc: Peter Zijlstra Cc: Frederic Weisbecker LKML-Reference: <20091020232034.237814877@goodmis.org> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 4b61b497040e..eae560503086 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -286,16 +286,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); -- cgit v1.2.2 From 0d0bea5ea4a0e91feff22ac5e32e14ff3a682247 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Wed, 25 Nov 2009 01:14:58 -0600 Subject: perf tools: Add 'signed' flag setting back into trace-event-parse.c Commit 13999e59343b042b0807be2df6ae5895d29782a0 (perf tools: Handle the case with and without the "signed" trace field) removed code to set the FIELD_IS_SIGNED flag that was originally added by commit 26a50744b21fff65bd754874072857bee8967f4d (tracing/events: Add 'signed' field to format files). This adds it back. Signed-off-by: Tom Zanussi Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: <1259133299-23594-2-git-send-email-tzanussi@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index eae560503086..7021dc1b0ca6 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -941,7 +941,8 @@ static int event_read_fields(struct event *event, struct format_field **fields) 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, ";") < 0) -- cgit v1.2.2 From eb9a42caa7a926beb935a22bc59d981b35f0b652 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Wed, 25 Nov 2009 01:15:47 -0600 Subject: perf trace: Add flag/symbolic format_flags It's useful to know whether a field is a flag or symbolic field for e.g. when generating scripts - it allows us to translate those fields specially rather than literally as plain numeric values. Signed-off-by: Tom Zanussi Cc: fweisbec@gmail.com Cc: rostedt@goodmis.org Cc: anton@samba.org Cc: hch@infradead.org LKML-Reference: <1259133352-23685-3-git-send-email-tzanussi@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 7021dc1b0ca6..85d7163a9fd4 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -48,6 +48,11 @@ 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) { @@ -1301,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; @@ -1668,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); -- cgit v1.2.2 From 16c632de64a74644a46e7636db26b2cfb530ca13 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Wed, 25 Nov 2009 01:15:48 -0600 Subject: perf trace: Add Perl scripting support Implement trace_scripting_ops to make Perl a supported perf trace scripting language. Additionally adds code that allows Perl trace scripts to access the 'flag' and 'symbolic' (__print_flags(), __print_symbolic()) field information parsed from the trace format files. Also adds the Perl implementation of the generate_script() trace_scripting_op, which creates a ready-to-run perf trace Perl script based on existing trace data. Scripts generated by this implementation print out all the fields for each event mentioned in perf.data (and will detect and generate the proper scripting code for 'flag' and 'symbolic' fields), and will additionally generate handlers for the special 'trace_unhandled', 'trace_begin' and 'trace_end' handlers. Script authors can simply remove the printing code to implement their own custom event handling. Signed-off-by: Tom Zanussi Cc: fweisbec@gmail.com Cc: rostedt@goodmis.org Cc: anton@samba.org Cc: hch@infradead.org LKML-Reference: <1259133352-23685-4-git-send-email-tzanussi@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 85d7163a9fd4..1f16495e5597 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -1888,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: @@ -1973,7 +1973,7 @@ int trace_parse_common_type(void *data) "common_type"); } -static int parse_common_pid(void *data) +int trace_parse_common_pid(void *data) { static int pid_offset; static int pid_size; @@ -2025,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) { @@ -2164,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; @@ -2694,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"); @@ -2980,7 +2988,7 @@ 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, -- cgit v1.2.2 From d1b93772be78486397693fc39d3ddea3fda90105 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Wed, 25 Nov 2009 01:15:50 -0600 Subject: perf trace: Add interface to access perf data from Perl handlers The Perl scripting support for perf trace allows most of a trace event's data to be accessed directly as handler arguments, but not all of it e.g. the less common fields aren't passed in. To give scripts access to the other fields and/or any other data or metadata in the main perf executable that might be useful, a way to access the C data in perf from Perl is needed; this patch uses the Perl XS facility to do it for the common_xxx event fields not passed to handler functions. Context.pm exports three functions to Perl scripts that access fields for the current event by calling back into perf: common_pc(), common_flags() and common_lock_depth(). Support for common_flags() field values was added to Core.pm and a script used to sanity check these and other basic scripting features, check-perf-trace.pl, was also added. Signed-off-by: Tom Zanussi Cc: fweisbec@gmail.com Cc: rostedt@goodmis.org Cc: anton@samba.org Cc: hch@infradead.org LKML-Reference: <1259133352-23685-6-git-send-email-tzanussi@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/trace-event-parse.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tools/perf/util/trace-event-parse.c') diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 1f16495e5597..0302405aa2ca 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -1982,7 +1982,7 @@ int trace_parse_common_pid(void *data) "common_pid"); } -static int parse_common_pc(void *data) +int parse_common_pc(void *data) { static int pc_offset; static int pc_size; @@ -1991,7 +1991,7 @@ static int parse_common_pc(void *data) "common_preempt_count"); } -static int parse_common_flags(void *data) +int parse_common_flags(void *data) { static int flags_offset; static int flags_size; @@ -2000,7 +2000,7 @@ static int parse_common_flags(void *data) "common_flags"); } -static int parse_common_lock_depth(void *data) +int parse_common_lock_depth(void *data) { static int ld_offset; static int ld_size; -- cgit v1.2.2