| From: Tom Zanussi <tom.zanussi@linux.intel.com> |
| Date: Tue, 5 Sep 2017 16:57:17 -0500 |
| Subject: [PATCH 05/40] tracing: Reimplement log2 |
| |
| log2 as currently implemented applies only to u64 trace_event_field |
| derived fields, and assumes that anything it's applied to is a u64 |
| field. |
| |
| To prepare for synthetic fields like latencies, log2 should be |
| applicable to those as well, so take the opportunity now to fix the |
| current problems as well as expand to more general uses. |
| |
| log2 should be thought of as a chaining function rather than a field |
| type. To enable this as well as possible future function |
| implementations, add a hist_field operand array into the hist_field |
| definition for this purpose, and make use of it to implement the log2 |
| 'function'. |
| |
| Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com> |
| Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| --- |
| kernel/trace/trace_events_hist.c | 31 +++++++++++++++++++++++++++---- |
| 1 file changed, 27 insertions(+), 4 deletions(-) |
| |
| --- a/kernel/trace/trace_events_hist.c |
| +++ b/kernel/trace/trace_events_hist.c |
| @@ -28,12 +28,16 @@ struct hist_field; |
| |
| typedef u64 (*hist_field_fn_t) (struct hist_field *field, void *event); |
| |
| +#define HIST_FIELD_OPERANDS_MAX 2 |
| + |
| struct hist_field { |
| struct ftrace_event_field *field; |
| unsigned long flags; |
| hist_field_fn_t fn; |
| unsigned int size; |
| unsigned int offset; |
| + unsigned int is_signed; |
| + struct hist_field *operands[HIST_FIELD_OPERANDS_MAX]; |
| }; |
| |
| static u64 hist_field_none(struct hist_field *field, void *event) |
| @@ -71,7 +75,9 @@ static u64 hist_field_pstring(struct his |
| |
| static u64 hist_field_log2(struct hist_field *hist_field, void *event) |
| { |
| - u64 val = *(u64 *)(event + hist_field->field->offset); |
| + struct hist_field *operand = hist_field->operands[0]; |
| + |
| + u64 val = operand->fn(operand, event); |
| |
| return (u64) ilog2(roundup_pow_of_two(val)); |
| } |
| @@ -156,6 +162,8 @@ static const char *hist_field_name(struc |
| |
| if (field->field) |
| field_name = field->field->name; |
| + else if (field->flags & HIST_FIELD_FL_LOG2) |
| + field_name = hist_field_name(field->operands[0], ++level); |
| |
| if (field_name == NULL) |
| field_name = ""; |
| @@ -346,8 +354,20 @@ static const struct tracing_map_ops hist |
| .elt_init = hist_trigger_elt_comm_init, |
| }; |
| |
| -static void destroy_hist_field(struct hist_field *hist_field) |
| +static void destroy_hist_field(struct hist_field *hist_field, |
| + unsigned int level) |
| { |
| + unsigned int i; |
| + |
| + if (level > 2) |
| + return; |
| + |
| + if (!hist_field) |
| + return; |
| + |
| + for (i = 0; i < HIST_FIELD_OPERANDS_MAX; i++) |
| + destroy_hist_field(hist_field->operands[i], level + 1); |
| + |
| kfree(hist_field); |
| } |
| |
| @@ -374,7 +394,10 @@ static struct hist_field *create_hist_fi |
| } |
| |
| if (flags & HIST_FIELD_FL_LOG2) { |
| + unsigned long fl = flags & ~HIST_FIELD_FL_LOG2; |
| hist_field->fn = hist_field_log2; |
| + hist_field->operands[0] = create_hist_field(field, fl); |
| + hist_field->size = hist_field->operands[0]->size; |
| goto out; |
| } |
| |
| @@ -394,7 +417,7 @@ static struct hist_field *create_hist_fi |
| hist_field->fn = select_value_fn(field->size, |
| field->is_signed); |
| if (!hist_field->fn) { |
| - destroy_hist_field(hist_field); |
| + destroy_hist_field(hist_field, 0); |
| return NULL; |
| } |
| } |
| @@ -411,7 +434,7 @@ static void destroy_hist_fields(struct h |
| |
| for (i = 0; i < TRACING_MAP_FIELDS_MAX; i++) { |
| if (hist_data->fields[i]) { |
| - destroy_hist_field(hist_data->fields[i]); |
| + destroy_hist_field(hist_data->fields[i], 0); |
| hist_data->fields[i] = NULL; |
| } |
| } |