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

Commit 7e8b88a3 authored by Tom Zanussi's avatar Tom Zanussi Committed by Steven Rostedt (VMware)
Browse files

tracing: Add hist trigger support for variable reference aliases

Add support for alias=$somevar where alias can be used as
onmatch.xxx($alias).

Aliases are a way of creating a new name for an existing variable, for
flexibly in making naming more clear in certain cases.  For example in
the below the user perhaps feels that using $new_lat in the synthetic
event invocation is opaque or doesn't fit well stylistically with
previous triggers, so creates an alias of $new_lat named $latency and
uses that in the call instead:

  # echo 'hist:keys=next_pid:new_lat=common_timestamp.usecs' >
    /sys/kernel/debug/tracing/events/sched/sched_switch/trigger

  # echo 'hist:keys=pid:latency=$new_lat:
    onmatch(sched.sched_switch).wake2($latency,pid)' >
    /sys/kernel/debug/tracing/events/synthetic/wake1/trigger

Link: http://lkml.kernel.org/r/ef20a65d921af3a873a6f1e8c71407c926d5586f.1516069914.git.tom.zanussi@linux.intel.com



Signed-off-by: default avatarTom Zanussi <tom.zanussi@linux.intel.com>
Signed-off-by: default avatarSteven Rostedt (VMware) <rostedt@goodmis.org>
parent 8b7622bf
Loading
Loading
Loading
Loading
+67 −7
Original line number Original line Diff line number Diff line
@@ -228,6 +228,7 @@ enum hist_field_flags {
	HIST_FIELD_FL_EXPR		= 1 << 13,
	HIST_FIELD_FL_EXPR		= 1 << 13,
	HIST_FIELD_FL_VAR_REF		= 1 << 14,
	HIST_FIELD_FL_VAR_REF		= 1 << 14,
	HIST_FIELD_FL_CPU		= 1 << 15,
	HIST_FIELD_FL_CPU		= 1 << 15,
	HIST_FIELD_FL_ALIAS		= 1 << 16,
};
};


struct var_defs {
struct var_defs {
@@ -1609,7 +1610,8 @@ static const char *hist_field_name(struct hist_field *field,


	if (field->field)
	if (field->field)
		field_name = field->field->name;
		field_name = field->field->name;
	else if (field->flags & HIST_FIELD_FL_LOG2)
	else if (field->flags & HIST_FIELD_FL_LOG2 ||
		 field->flags & HIST_FIELD_FL_ALIAS)
		field_name = hist_field_name(field->operands[0], ++level);
		field_name = hist_field_name(field->operands[0], ++level);
	else if (field->flags & HIST_FIELD_FL_TIMESTAMP)
	else if (field->flags & HIST_FIELD_FL_TIMESTAMP)
		field_name = "common_timestamp";
		field_name = "common_timestamp";
@@ -2080,7 +2082,7 @@ static struct hist_field *create_hist_field(struct hist_trigger_data *hist_data,


	hist_field->hist_data = hist_data;
	hist_field->hist_data = hist_data;


	if (flags & HIST_FIELD_FL_EXPR)
	if (flags & HIST_FIELD_FL_EXPR || flags & HIST_FIELD_FL_ALIAS)
		goto out; /* caller will populate */
		goto out; /* caller will populate */


	if (flags & HIST_FIELD_FL_VAR_REF) {
	if (flags & HIST_FIELD_FL_VAR_REF) {
@@ -2217,11 +2219,19 @@ static int init_var_ref(struct hist_field *ref_field,
		}
		}
	}
	}


	if (var_field->var.name) {
		ref_field->name = kstrdup(var_field->var.name, GFP_KERNEL);
		ref_field->name = kstrdup(var_field->var.name, GFP_KERNEL);
		if (!ref_field->name) {
		if (!ref_field->name) {
			err = -ENOMEM;
			err = -ENOMEM;
			goto free;
			goto free;
		}
		}
	} else if (var_field->name) {
		ref_field->name = kstrdup(var_field->name, GFP_KERNEL);
		if (!ref_field->name) {
			err = -ENOMEM;
			goto free;
		}
	}


	ref_field->type = kstrdup(var_field->type, GFP_KERNEL);
	ref_field->type = kstrdup(var_field->type, GFP_KERNEL);
	if (!ref_field->type) {
	if (!ref_field->type) {
@@ -2382,6 +2392,28 @@ parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file,
	return field;
	return field;
}
}


static struct hist_field *create_alias(struct hist_trigger_data *hist_data,
				       struct hist_field *var_ref,
				       char *var_name)
{
	struct hist_field *alias = NULL;
	unsigned long flags = HIST_FIELD_FL_ALIAS | HIST_FIELD_FL_VAR;

	alias = create_hist_field(hist_data, NULL, flags, var_name);
	if (!alias)
		return NULL;

	alias->fn = var_ref->fn;
	alias->operands[0] = var_ref;

	if (init_var_ref(alias, var_ref, var_ref->system, var_ref->event_name)) {
		destroy_hist_field(alias, 0);
		return NULL;
	}

	return alias;
}

static struct hist_field *parse_atom(struct hist_trigger_data *hist_data,
static struct hist_field *parse_atom(struct hist_trigger_data *hist_data,
				     struct trace_event_file *file, char *str,
				     struct trace_event_file *file, char *str,
				     unsigned long *flags, char *var_name)
				     unsigned long *flags, char *var_name)
@@ -2415,6 +2447,13 @@ static struct hist_field *parse_atom(struct hist_trigger_data *hist_data,
		if (hist_field) {
		if (hist_field) {
			hist_data->var_refs[hist_data->n_var_refs] = hist_field;
			hist_data->var_refs[hist_data->n_var_refs] = hist_field;
			hist_field->var_ref_idx = hist_data->n_var_refs++;
			hist_field->var_ref_idx = hist_data->n_var_refs++;
			if (var_name) {
				hist_field = create_alias(hist_data, hist_field, var_name);
				if (!hist_field) {
					ret = -ENOMEM;
					goto out;
				}
			}
			return hist_field;
			return hist_field;
		}
		}
	} else
	} else
@@ -2515,6 +2554,26 @@ static int check_expr_operands(struct hist_field *operand1,
	unsigned long operand1_flags = operand1->flags;
	unsigned long operand1_flags = operand1->flags;
	unsigned long operand2_flags = operand2->flags;
	unsigned long operand2_flags = operand2->flags;


	if ((operand1_flags & HIST_FIELD_FL_VAR_REF) ||
	    (operand1_flags & HIST_FIELD_FL_ALIAS)) {
		struct hist_field *var;

		var = find_var_field(operand1->var.hist_data, operand1->name);
		if (!var)
			return -EINVAL;
		operand1_flags = var->flags;
	}

	if ((operand2_flags & HIST_FIELD_FL_VAR_REF) ||
	    (operand2_flags & HIST_FIELD_FL_ALIAS)) {
		struct hist_field *var;

		var = find_var_field(operand2->var.hist_data, operand2->name);
		if (!var)
			return -EINVAL;
		operand2_flags = var->flags;
	}

	if ((operand1_flags & HIST_FIELD_FL_TIMESTAMP_USECS) !=
	if ((operand1_flags & HIST_FIELD_FL_TIMESTAMP_USECS) !=
	    (operand2_flags & HIST_FIELD_FL_TIMESTAMP_USECS))
	    (operand2_flags & HIST_FIELD_FL_TIMESTAMP_USECS))
		return -EINVAL;
		return -EINVAL;
@@ -4646,7 +4705,8 @@ static void hist_field_print(struct seq_file *m, struct hist_field *hist_field)
	else if (hist_field->flags & HIST_FIELD_FL_CPU)
	else if (hist_field->flags & HIST_FIELD_FL_CPU)
		seq_puts(m, "cpu");
		seq_puts(m, "cpu");
	else if (field_name) {
	else if (field_name) {
		if (hist_field->flags & HIST_FIELD_FL_VAR_REF)
		if (hist_field->flags & HIST_FIELD_FL_VAR_REF ||
		    hist_field->flags & HIST_FIELD_FL_ALIAS)
			seq_putc(m, '$');
			seq_putc(m, '$');
		seq_printf(m, "%s", field_name);
		seq_printf(m, "%s", field_name);
	}
	}