[PATCH v2 4/4] tools lib traceevent: Added support for __get_bitmask() macro

2014-06-02 Thread Steven Rostedt
From: "Steven Rostedt (Red Hat)" 

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=000f freq=190 cdev_state=0 power=5252

Link: http://lkml.kernel.org/r/20140506132238.22e13...@gandalf.local.home

Suggested-by: Javi Merino 
Tested-by: Javi Merino 
Signed-off-by: Steven Rostedt 
---
 tools/lib/traceevent/event-parse.c | 113 +
 tools/lib/traceevent/event-parse.h |   7 ++
 .../perf/util/scripting-engines/trace-event-perl.c |   1 +
 .../util/scripting-engines/trace-event-python.c|   1 +
 4 files changed, 122 insertions(+)

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)
case PRINT_BSTRING:
free(arg->string.string);
break;
+   case PRINT_BITMASK:
+   free(arg->bitmask.bitmask);
+   break;
case PRINT_DYNAMIC_ARRAY:
free(arg->dynarray.index);
break;
@@ -2268,6 +2271,7 @@ static int arg_num_eval(struct print_arg *arg, long long 
*val)
case PRINT_FIELD ... PRINT_SYMBOL:
case PRINT_STRING:
case PRINT_BSTRING:
+   case PRINT_BITMASK:
default:
do_warning("invalid eval type %d", arg->type);
ret = 0;
@@ -2296,6 +2300,7 @@ static char *arg_eval (struct print_arg *arg)
case PRINT_FIELD ... PRINT_SYMBOL:
case PRINT_STRING:
case PRINT_BSTRING:
+   case PRINT_BITMASK:
default:
do_warning("invalid eval type %d", arg->type);
break;
@@ -2683,6 +2688,35 @@ process_str(struct event_format *event __maybe_unused, 
struct print_arg *arg,
return EVENT_ERROR;
 }
 
+static enum event_type
+process_bitmask(struct event_format *event __maybe_unused, struct print_arg 
*arg,
+   char **tok)
+{
+   enum event_type type;
+   char *token;
+
+   if (read_expect_type(EVENT_ITEM, ) < 0)
+   goto out_free;
+
+   arg->type = PRINT_BITMASK;
+   arg->bitmask.bitmask = token;
+   arg->bitmask.offset = -1;
+
+   if (read_expected(EVENT_DELIM, ")") < 0)
+   goto out_err;
+
+   type = read_token();
+   *tok = token;
+
+   return type;
+
+ out_free:
+   free_token(token);
+ out_err:
+   *tok = NULL;
+   return EVENT_ERROR;
+}
+
 static struct pevent_function_handler *
 find_func_handler(struct pevent *pevent, char *func_name)
 {
@@ -2797,6 +2831,10 @@ process_function(struct event_format *event, struct 
print_arg *arg,
free_token(token);
return process_str(event, arg, tok);
}
+   if (strcmp(token, "__get_bitmask") == 0) {
+   free_token(token);
+   return process_bitmask(event, arg, tok);
+   }
if (strcmp(token, "__get_dynamic_array") == 0) {
free_token(token);
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
return eval_type(val, arg, 0);
case PRINT_STRING:
case PRINT_BSTRING:
+   case PRINT_BITMASK:
return 0;
case PRINT_FUNC: {
struct trace_seq s;
@@ -3556,6 +3595,60 @@ static void print_str_to_seq(struct trace_seq *s, const 
char *format,
trace_seq_printf(s, format, str);
 }
 
+static void print_bitmask_to_seq(struct pevent *pevent,
+struct trace_seq *s, const char *format,
+int len_arg, const void *data, int size)
+{
+   int nr_bits = size * 8;
+   int str_size = (nr_bits + 3) / 4;
+   int len = 0;
+   char buf[3];
+   char *str;
+   int index;
+   int i;
+
+   /*
+* The kernel likes to put in commas every 32 bits, we
+* can do the same.
+*/
+   str_size += (nr_bits - 1) / 32;
+
+   str = malloc(str_size + 1);
+   if (!str) {
+   do_warning("%s: not enough memory!", __func__);
+   return;
+   }
+   str[str_size] = 0;
+
+   /* Start out with -2 for the two chars per byte */
+   for (i = str_size - 2; i >= 0; i -= 2) 

[PATCH v2 4/4] tools lib traceevent: Added support for __get_bitmask() macro

2014-06-02 Thread Steven Rostedt
From: Steven Rostedt (Red Hat) rost...@goodmis.org

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=000f freq=190 cdev_state=0 power=5252

Link: http://lkml.kernel.org/r/20140506132238.22e13...@gandalf.local.home

Suggested-by: Javi Merino javi.mer...@arm.com
Tested-by: Javi Merino javi.mer...@arm.com
Signed-off-by: Steven Rostedt rost...@goodmis.org
---
 tools/lib/traceevent/event-parse.c | 113 +
 tools/lib/traceevent/event-parse.h |   7 ++
 .../perf/util/scripting-engines/trace-event-perl.c |   1 +
 .../util/scripting-engines/trace-event-python.c|   1 +
 4 files changed, 122 insertions(+)

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)
case PRINT_BSTRING:
free(arg-string.string);
break;
+   case PRINT_BITMASK:
+   free(arg-bitmask.bitmask);
+   break;
case PRINT_DYNAMIC_ARRAY:
free(arg-dynarray.index);
break;
@@ -2268,6 +2271,7 @@ static int arg_num_eval(struct print_arg *arg, long long 
*val)
case PRINT_FIELD ... PRINT_SYMBOL:
case PRINT_STRING:
case PRINT_BSTRING:
+   case PRINT_BITMASK:
default:
do_warning(invalid eval type %d, arg-type);
ret = 0;
@@ -2296,6 +2300,7 @@ static char *arg_eval (struct print_arg *arg)
case PRINT_FIELD ... PRINT_SYMBOL:
case PRINT_STRING:
case PRINT_BSTRING:
+   case PRINT_BITMASK:
default:
do_warning(invalid eval type %d, arg-type);
break;
@@ -2683,6 +2688,35 @@ process_str(struct event_format *event __maybe_unused, 
struct print_arg *arg,
return EVENT_ERROR;
 }
 
+static enum event_type
+process_bitmask(struct event_format *event __maybe_unused, struct print_arg 
*arg,
+   char **tok)
+{
+   enum event_type type;
+   char *token;
+
+   if (read_expect_type(EVENT_ITEM, token)  0)
+   goto out_free;
+
+   arg-type = PRINT_BITMASK;
+   arg-bitmask.bitmask = token;
+   arg-bitmask.offset = -1;
+
+   if (read_expected(EVENT_DELIM, ))  0)
+   goto out_err;
+
+   type = read_token(token);
+   *tok = token;
+
+   return type;
+
+ out_free:
+   free_token(token);
+ out_err:
+   *tok = NULL;
+   return EVENT_ERROR;
+}
+
 static struct pevent_function_handler *
 find_func_handler(struct pevent *pevent, char *func_name)
 {
@@ -2797,6 +2831,10 @@ process_function(struct event_format *event, struct 
print_arg *arg,
free_token(token);
return process_str(event, arg, tok);
}
+   if (strcmp(token, __get_bitmask) == 0) {
+   free_token(token);
+   return process_bitmask(event, arg, tok);
+   }
if (strcmp(token, __get_dynamic_array) == 0) {
free_token(token);
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
return eval_type(val, arg, 0);
case PRINT_STRING:
case PRINT_BSTRING:
+   case PRINT_BITMASK:
return 0;
case PRINT_FUNC: {
struct trace_seq s;
@@ -3556,6 +3595,60 @@ static void print_str_to_seq(struct trace_seq *s, const 
char *format,
trace_seq_printf(s, format, str);
 }
 
+static void print_bitmask_to_seq(struct pevent *pevent,
+struct trace_seq *s, const char *format,
+int len_arg, const void *data, int size)
+{
+   int nr_bits = size * 8;
+   int str_size = (nr_bits + 3) / 4;
+   int len = 0;
+   char buf[3];
+   char *str;
+   int index;
+   int i;
+
+   /*
+* The kernel likes to put in commas every 32 bits, we
+* can do the same.
+*/
+   str_size += (nr_bits - 1) / 32;
+
+   str = malloc(str_size + 1);
+   if (!str) {
+   do_warning(%s: not enough memory!, __func__);
+   return;
+   }
+   str[str_size] = 0;
+
+   /* Start out with -2 for the two