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 /tools | |
| 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>
Diffstat (limited to 'tools')
| -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; | ||
