diff options
author | Steven Rostedt (Red Hat) <rostedt@goodmis.org> | 2014-06-02 23:20:16 -0400 |
---|---|---|
committer | Jiri Olsa <jolsa@kernel.org> | 2014-06-07 17:33:37 -0400 |
commit | 473a778a2f2949972b52ad7fc61577f381f2d05e (patch) | |
tree | 17cbf62b89bcbc38b600027cc61eda50469a796b | |
parent | 49440828ad7b809e9d31f6108875e3b1e974690c (diff) |
tools lib traceevent: Added support for __get_bitmask() macro
Coming in v3.16, trace events will be able to save bitmasks in raw
format in the ring buffer and output it with the __get_bitmask() macro.
In order for userspace tools to parse this, it must be able to handle
the __get_bitmask() call and be able to convert the data that's in
the ring buffer into a nice bitmask format. The output is similar to
what the kernel uses to print bitmasks, with a comma separator every
4 bytes (8 characters).
This allows for cpumasks to also be saved efficiently.
The first user is the thermal:thermal_power_limit event which has the
following output:
thermal_power_limit: cpus=0000000f freq=1900000 cdev_state=0 power=5252
Link: http://lkml.kernel.org/r/20140506132238.22e136d1@gandalf.local.home
Suggested-by: Javi Merino <javi.merino@arm.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Tested-by: Javi Merino <javi.merino@arm.com>
Link: http://lkml.kernel.org/r/20140603032224.229186537@goodmis.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
-rw-r--r-- | tools/lib/traceevent/event-parse.c | 113 | ||||
-rw-r--r-- | tools/lib/traceevent/event-parse.h | 7 | ||||
-rw-r--r-- | tools/perf/util/scripting-engines/trace-event-perl.c | 1 | ||||
-rw-r--r-- | tools/perf/util/scripting-engines/trace-event-python.c | 1 |
4 files changed, 122 insertions, 0 deletions
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index b83184f2d484..93825a17dcce 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
@@ -765,6 +765,9 @@ static void free_arg(struct print_arg *arg) | |||
765 | case PRINT_BSTRING: | 765 | case PRINT_BSTRING: |
766 | free(arg->string.string); | 766 | free(arg->string.string); |
767 | break; | 767 | break; |
768 | case PRINT_BITMASK: | ||
769 | free(arg->bitmask.bitmask); | ||
770 | break; | ||
768 | case PRINT_DYNAMIC_ARRAY: | 771 | case PRINT_DYNAMIC_ARRAY: |
769 | free(arg->dynarray.index); | 772 | free(arg->dynarray.index); |
770 | break; | 773 | break; |
@@ -2268,6 +2271,7 @@ static int arg_num_eval(struct print_arg *arg, long long *val) | |||
2268 | case PRINT_FIELD ... PRINT_SYMBOL: | 2271 | case PRINT_FIELD ... PRINT_SYMBOL: |
2269 | case PRINT_STRING: | 2272 | case PRINT_STRING: |
2270 | case PRINT_BSTRING: | 2273 | case PRINT_BSTRING: |
2274 | case PRINT_BITMASK: | ||
2271 | default: | 2275 | default: |
2272 | do_warning("invalid eval type %d", arg->type); | 2276 | do_warning("invalid eval type %d", arg->type); |
2273 | ret = 0; | 2277 | ret = 0; |
@@ -2296,6 +2300,7 @@ static char *arg_eval (struct print_arg *arg) | |||
2296 | case PRINT_FIELD ... PRINT_SYMBOL: | 2300 | case PRINT_FIELD ... PRINT_SYMBOL: |
2297 | case PRINT_STRING: | 2301 | case PRINT_STRING: |
2298 | case PRINT_BSTRING: | 2302 | case PRINT_BSTRING: |
2303 | case PRINT_BITMASK: | ||
2299 | default: | 2304 | default: |
2300 | do_warning("invalid eval type %d", arg->type); | 2305 | do_warning("invalid eval type %d", arg->type); |
2301 | break; | 2306 | break; |
@@ -2683,6 +2688,35 @@ process_str(struct event_format *event __maybe_unused, struct print_arg *arg, | |||
2683 | return EVENT_ERROR; | 2688 | return EVENT_ERROR; |
2684 | } | 2689 | } |
2685 | 2690 | ||
2691 | static enum event_type | ||
2692 | process_bitmask(struct event_format *event __maybe_unused, struct print_arg *arg, | ||
2693 | char **tok) | ||
2694 | { | ||
2695 | enum event_type type; | ||
2696 | char *token; | ||
2697 | |||
2698 | if (read_expect_type(EVENT_ITEM, &token) < 0) | ||
2699 | goto out_free; | ||
2700 | |||
2701 | arg->type = PRINT_BITMASK; | ||
2702 | arg->bitmask.bitmask = token; | ||
2703 | arg->bitmask.offset = -1; | ||
2704 | |||
2705 | if (read_expected(EVENT_DELIM, ")") < 0) | ||
2706 | goto out_err; | ||
2707 | |||
2708 | type = read_token(&token); | ||
2709 | *tok = token; | ||
2710 | |||
2711 | return type; | ||
2712 | |||
2713 | out_free: | ||
2714 | free_token(token); | ||
2715 | out_err: | ||
2716 | *tok = NULL; | ||
2717 | return EVENT_ERROR; | ||
2718 | } | ||
2719 | |||
2686 | static struct pevent_function_handler * | 2720 | static struct pevent_function_handler * |
2687 | find_func_handler(struct pevent *pevent, char *func_name) | 2721 | find_func_handler(struct pevent *pevent, char *func_name) |
2688 | { | 2722 | { |
@@ -2797,6 +2831,10 @@ process_function(struct event_format *event, struct print_arg *arg, | |||
2797 | free_token(token); | 2831 | free_token(token); |
2798 | return process_str(event, arg, tok); | 2832 | return process_str(event, arg, tok); |
2799 | } | 2833 | } |
2834 | if (strcmp(token, "__get_bitmask") == 0) { | ||
2835 | free_token(token); | ||
2836 | return process_bitmask(event, arg, tok); | ||
2837 | } | ||
2800 | if (strcmp(token, "__get_dynamic_array") == 0) { | 2838 | if (strcmp(token, "__get_dynamic_array") == 0) { |
2801 | free_token(token); | 2839 | free_token(token); |
2802 | return process_dynamic_array(event, arg, tok); | 2840 | return process_dynamic_array(event, arg, tok); |
@@ -3324,6 +3362,7 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg | |||
3324 | return eval_type(val, arg, 0); | 3362 | return eval_type(val, arg, 0); |
3325 | case PRINT_STRING: | 3363 | case PRINT_STRING: |
3326 | case PRINT_BSTRING: | 3364 | case PRINT_BSTRING: |
3365 | case PRINT_BITMASK: | ||
3327 | return 0; | 3366 | return 0; |
3328 | case PRINT_FUNC: { | 3367 | case PRINT_FUNC: { |
3329 | struct trace_seq s; | 3368 | struct trace_seq s; |
@@ -3556,6 +3595,60 @@ static void print_str_to_seq(struct trace_seq *s, const char *format, | |||
3556 | trace_seq_printf(s, format, str); | 3595 | trace_seq_printf(s, format, str); |
3557 | } | 3596 | } |
3558 | 3597 | ||
3598 | static void print_bitmask_to_seq(struct pevent *pevent, | ||
3599 | struct trace_seq *s, const char *format, | ||
3600 | int len_arg, const void *data, int size) | ||
3601 | { | ||
3602 | int nr_bits = size * 8; | ||
3603 | int str_size = (nr_bits + 3) / 4; | ||
3604 | int len = 0; | ||
3605 | char buf[3]; | ||
3606 | char *str; | ||
3607 | int index; | ||
3608 | int i; | ||
3609 | |||
3610 | /* | ||
3611 | * The kernel likes to put in commas every 32 bits, we | ||
3612 | * can do the same. | ||
3613 | */ | ||
3614 | str_size += (nr_bits - 1) / 32; | ||
3615 | |||
3616 | str = malloc(str_size + 1); | ||
3617 | if (!str) { | ||
3618 | do_warning("%s: not enough memory!", __func__); | ||
3619 | return; | ||
3620 | } | ||
3621 | str[str_size] = 0; | ||
3622 | |||
3623 | /* Start out with -2 for the two chars per byte */ | ||
3624 | for (i = str_size - 2; i >= 0; i -= 2) { | ||
3625 | /* | ||
3626 | * data points to a bit mask of size bytes. | ||
3627 | * In the kernel, this is an array of long words, thus | ||
3628 | * endianess is very important. | ||
3629 | */ | ||
3630 | if (pevent->file_bigendian) | ||
3631 | index = size - (len + 1); | ||
3632 | else | ||
3633 | index = len; | ||
3634 | |||
3635 | snprintf(buf, 3, "%02x", *((unsigned char *)data + index)); | ||
3636 | memcpy(str + i, buf, 2); | ||
3637 | len++; | ||
3638 | if (!(len & 3) && i > 0) { | ||
3639 | i--; | ||
3640 | str[i] = ','; | ||
3641 | } | ||
3642 | } | ||
3643 | |||
3644 | if (len_arg >= 0) | ||
3645 | trace_seq_printf(s, format, len_arg, str); | ||
3646 | else | ||
3647 | trace_seq_printf(s, format, str); | ||
3648 | |||
3649 | free(str); | ||
3650 | } | ||
3651 | |||
3559 | static void print_str_arg(struct trace_seq *s, void *data, int size, | 3652 | static void print_str_arg(struct trace_seq *s, void *data, int size, |
3560 | struct event_format *event, const char *format, | 3653 | struct event_format *event, const char *format, |
3561 | int len_arg, struct print_arg *arg) | 3654 | int len_arg, struct print_arg *arg) |
@@ -3691,6 +3784,23 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, | |||
3691 | case PRINT_BSTRING: | 3784 | case PRINT_BSTRING: |
3692 | print_str_to_seq(s, format, len_arg, arg->string.string); | 3785 | print_str_to_seq(s, format, len_arg, arg->string.string); |
3693 | break; | 3786 | break; |
3787 | case PRINT_BITMASK: { | ||
3788 | int bitmask_offset; | ||
3789 | int bitmask_size; | ||
3790 | |||
3791 | if (arg->bitmask.offset == -1) { | ||
3792 | struct format_field *f; | ||
3793 | |||
3794 | f = pevent_find_any_field(event, arg->bitmask.bitmask); | ||
3795 | arg->bitmask.offset = f->offset; | ||
3796 | } | ||
3797 | bitmask_offset = data2host4(pevent, data + arg->bitmask.offset); | ||
3798 | bitmask_size = bitmask_offset >> 16; | ||
3799 | bitmask_offset &= 0xffff; | ||
3800 | print_bitmask_to_seq(pevent, s, format, len_arg, | ||
3801 | data + bitmask_offset, bitmask_size); | ||
3802 | break; | ||
3803 | } | ||
3694 | case PRINT_OP: | 3804 | case PRINT_OP: |
3695 | /* | 3805 | /* |
3696 | * The only op for string should be ? : | 3806 | * The only op for string should be ? : |
@@ -4822,6 +4932,9 @@ static void print_args(struct print_arg *args) | |||
4822 | case PRINT_BSTRING: | 4932 | case PRINT_BSTRING: |
4823 | printf("__get_str(%s)", args->string.string); | 4933 | printf("__get_str(%s)", args->string.string); |
4824 | break; | 4934 | break; |
4935 | case PRINT_BITMASK: | ||
4936 | printf("__get_bitmask(%s)", args->bitmask.bitmask); | ||
4937 | break; | ||
4825 | case PRINT_TYPE: | 4938 | case PRINT_TYPE: |
4826 | printf("(%s)", args->typecast.type); | 4939 | printf("(%s)", args->typecast.type); |
4827 | print_args(args->typecast.item); | 4940 | print_args(args->typecast.item); |
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 56e0e6c12411..7a3873ff9a4f 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h | |||
@@ -208,6 +208,11 @@ struct print_arg_string { | |||
208 | int offset; | 208 | int offset; |
209 | }; | 209 | }; |
210 | 210 | ||
211 | struct print_arg_bitmask { | ||
212 | char *bitmask; | ||
213 | int offset; | ||
214 | }; | ||
215 | |||
211 | struct print_arg_field { | 216 | struct print_arg_field { |
212 | char *name; | 217 | char *name; |
213 | struct format_field *field; | 218 | struct format_field *field; |
@@ -274,6 +279,7 @@ enum print_arg_type { | |||
274 | PRINT_DYNAMIC_ARRAY, | 279 | PRINT_DYNAMIC_ARRAY, |
275 | PRINT_OP, | 280 | PRINT_OP, |
276 | PRINT_FUNC, | 281 | PRINT_FUNC, |
282 | PRINT_BITMASK, | ||
277 | }; | 283 | }; |
278 | 284 | ||
279 | struct print_arg { | 285 | struct print_arg { |
@@ -288,6 +294,7 @@ struct print_arg { | |||
288 | struct print_arg_hex hex; | 294 | struct print_arg_hex hex; |
289 | struct print_arg_func func; | 295 | struct print_arg_func func; |
290 | struct print_arg_string string; | 296 | struct print_arg_string string; |
297 | struct print_arg_bitmask bitmask; | ||
291 | struct print_arg_op op; | 298 | struct print_arg_op op; |
292 | struct print_arg_dynarray dynarray; | 299 | struct print_arg_dynarray dynarray; |
293 | }; | 300 | }; |
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index e108207c5de0..af7da565a750 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c | |||
@@ -215,6 +215,7 @@ static void define_event_symbols(struct event_format *event, | |||
215 | case PRINT_BSTRING: | 215 | case PRINT_BSTRING: |
216 | case PRINT_DYNAMIC_ARRAY: | 216 | case PRINT_DYNAMIC_ARRAY: |
217 | case PRINT_STRING: | 217 | case PRINT_STRING: |
218 | case PRINT_BITMASK: | ||
218 | break; | 219 | break; |
219 | case PRINT_TYPE: | 220 | case PRINT_TYPE: |
220 | define_event_symbols(event, ev_name, args->typecast.item); | 221 | define_event_symbols(event, ev_name, args->typecast.item); |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index cd9774df3750..c3de0971bfdd 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -197,6 +197,7 @@ static void define_event_symbols(struct event_format *event, | |||
197 | case PRINT_BSTRING: | 197 | case PRINT_BSTRING: |
198 | case PRINT_DYNAMIC_ARRAY: | 198 | case PRINT_DYNAMIC_ARRAY: |
199 | case PRINT_FUNC: | 199 | case PRINT_FUNC: |
200 | case PRINT_BITMASK: | ||
200 | /* we should warn... */ | 201 | /* we should warn... */ |
201 | return; | 202 | return; |
202 | } | 203 | } |