Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 473a778a authored by Steven Rostedt (Red Hat)'s avatar Steven Rostedt (Red Hat) Committed by Jiri Olsa
Browse files

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: default avatarJavi Merino <javi.merino@arm.com>
Signed-off-by: default avatarSteven Rostedt <rostedt@goodmis.org>
Acked-by: default avatarNamhyung Kim <namhyung@kernel.org>
Tested-by: default avatarJavi Merino <javi.merino@arm.com>
Link: http://lkml.kernel.org/r/20140603032224.229186537@goodmis.org


Signed-off-by: default avatarJiri Olsa <jolsa@kernel.org>
parent 49440828
Loading
Loading
Loading
Loading
+113 −0
Original line number Diff line number Diff line
@@ -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 chars per byte */
	for (i = str_size - 2; i >= 0; i -= 2) {
		/*
		 * data points to a bit mask of size bytes.
		 * In the kernel, this is an array of long words, thus
		 * endianess is very important.
		 */
		if (pevent->file_bigendian)
			index = size - (len + 1);
		else
			index = len;

		snprintf(buf, 3, "%02x", *((unsigned char *)data + index));
		memcpy(str + i, buf, 2);
		len++;
		if (!(len & 3) && i > 0) {
			i--;
			str[i] = ',';
		}
	}

	if (len_arg >= 0)
		trace_seq_printf(s, format, len_arg, str);
	else
		trace_seq_printf(s, format, str);

	free(str);
}

static void print_str_arg(struct trace_seq *s, void *data, int size,
			  struct event_format *event, const char *format,
			  int len_arg, struct print_arg *arg)
@@ -3691,6 +3784,23 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
	case PRINT_BSTRING:
		print_str_to_seq(s, format, len_arg, arg->string.string);
		break;
	case PRINT_BITMASK: {
		int bitmask_offset;
		int bitmask_size;

		if (arg->bitmask.offset == -1) {
			struct format_field *f;

			f = pevent_find_any_field(event, arg->bitmask.bitmask);
			arg->bitmask.offset = f->offset;
		}
		bitmask_offset = data2host4(pevent, data + arg->bitmask.offset);
		bitmask_size = bitmask_offset >> 16;
		bitmask_offset &= 0xffff;
		print_bitmask_to_seq(pevent, s, format, len_arg,
				     data + bitmask_offset, bitmask_size);
		break;
	}
	case PRINT_OP:
		/*
		 * The only op for string should be ? :
@@ -4822,6 +4932,9 @@ static void print_args(struct print_arg *args)
	case PRINT_BSTRING:
		printf("__get_str(%s)", args->string.string);
		break;
	case PRINT_BITMASK:
		printf("__get_bitmask(%s)", args->bitmask.bitmask);
		break;
	case PRINT_TYPE:
		printf("(%s)", args->typecast.type);
		print_args(args->typecast.item);
+7 −0
Original line number Diff line number Diff line
@@ -208,6 +208,11 @@ struct print_arg_string {
	int			offset;
};

struct print_arg_bitmask {
	char			*bitmask;
	int			offset;
};

struct print_arg_field {
	char			*name;
	struct format_field	*field;
@@ -274,6 +279,7 @@ enum print_arg_type {
	PRINT_DYNAMIC_ARRAY,
	PRINT_OP,
	PRINT_FUNC,
	PRINT_BITMASK,
};

struct print_arg {
@@ -288,6 +294,7 @@ struct print_arg {
		struct print_arg_hex		hex;
		struct print_arg_func		func;
		struct print_arg_string		string;
		struct print_arg_bitmask	bitmask;
		struct print_arg_op		op;
		struct print_arg_dynarray	dynarray;
	};
+1 −0
Original line number Diff line number Diff line
@@ -215,6 +215,7 @@ static void define_event_symbols(struct event_format *event,
	case PRINT_BSTRING:
	case PRINT_DYNAMIC_ARRAY:
	case PRINT_STRING:
	case PRINT_BITMASK:
		break;
	case PRINT_TYPE:
		define_event_symbols(event, ev_name, args->typecast.item);
+1 −0
Original line number Diff line number Diff line
@@ -197,6 +197,7 @@ static void define_event_symbols(struct event_format *event,
	case PRINT_BSTRING:
	case PRINT_DYNAMIC_ARRAY:
	case PRINT_FUNC:
	case PRINT_BITMASK:
		/* we should warn... */
		return;
	}