From 76a3b0c8ac344e1d0f436160cbb59b670b086947 Mon Sep 17 00:00:00 2001 From: Tom Zanussi Date: Thu, 3 Mar 2016 12:54:44 -0600 Subject: tracing: Add hist trigger support for compound keys Allow users to specify multiple trace event fields to use in keys by allowing multiple fields in the 'keys=' keyword. With this addition, any unique combination of any of the fields named in the 'keys' keyword will result in a new entry being added to the hash table. Link: http://lkml.kernel.org/r/0cfa24e6ac3b0dcece7737d94aa1f322ae3afc4b.1457029949.git.tom.zanussi@linux.intel.com Signed-off-by: Tom Zanussi Tested-by: Masami Hiramatsu Reviewed-by: Namhyung Kim Signed-off-by: Steven Rostedt --- kernel/trace/trace_events_hist.c | 41 +++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) (limited to 'kernel/trace/trace_events_hist.c') diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index 1b33590b9c8f..65fdfc6cb633 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -32,6 +32,7 @@ struct hist_field { unsigned long flags; hist_field_fn_t fn; unsigned int size; + unsigned int offset; }; static u64 hist_field_counter(struct hist_field *field, void *event) @@ -73,8 +74,7 @@ DEFINE_HIST_FIELD_FN(u8); for ((i) = (hist_data)->n_vals; (i) < (hist_data)->n_fields; (i)++) #define HITCOUNT_IDX 0 -#define HIST_KEY_MAX 1 -#define HIST_KEY_SIZE_MAX MAX_FILTER_STR_VAL +#define HIST_KEY_SIZE_MAX (MAX_FILTER_STR_VAL + sizeof(u64)) enum hist_field_flags { HIST_FIELD_FL_HITCOUNT = 1, @@ -351,6 +351,7 @@ static int create_val_fields(struct hist_trigger_data *hist_data, static int create_key_field(struct hist_trigger_data *hist_data, unsigned int key_idx, + unsigned int key_offset, struct trace_event_file *file, char *field_str) { @@ -380,7 +381,8 @@ static int create_key_field(struct hist_trigger_data *hist_data, key_size = ALIGN(key_size, sizeof(u64)); hist_data->fields[key_idx]->size = key_size; - hist_data->key_size = key_size; + hist_data->fields[key_idx]->offset = key_offset; + hist_data->key_size += key_size; if (hist_data->key_size > HIST_KEY_SIZE_MAX) { ret = -EINVAL; goto out; @@ -399,7 +401,7 @@ static int create_key_field(struct hist_trigger_data *hist_data, static int create_key_fields(struct hist_trigger_data *hist_data, struct trace_event_file *file) { - unsigned int i, n_vals = hist_data->n_vals; + unsigned int i, key_offset = 0, n_vals = hist_data->n_vals; char *fields_str, *field_str; int ret = -EINVAL; @@ -411,13 +413,15 @@ static int create_key_fields(struct hist_trigger_data *hist_data, if (!fields_str) goto out; - for (i = n_vals; i < n_vals + HIST_KEY_MAX; i++) { + for (i = n_vals; i < n_vals + TRACING_MAP_KEYS_MAX; i++) { field_str = strsep(&fields_str, ","); if (!field_str) break; - ret = create_key_field(hist_data, i, file, field_str); + ret = create_key_field(hist_data, i, key_offset, + file, field_str); if (ret < 0) goto out; + key_offset += ret; } if (fields_str) { ret = -EINVAL; @@ -482,7 +486,10 @@ static int create_tracing_map_fields(struct hist_trigger_data *hist_data) else cmp_fn = tracing_map_cmp_num(field->size, field->is_signed); - idx = tracing_map_add_key_field(map, 0, cmp_fn); + idx = tracing_map_add_key_field(map, + hist_field->offset, + cmp_fn); + } else idx = tracing_map_add_sum_field(map); @@ -562,12 +569,16 @@ static void hist_trigger_elt_update(struct hist_trigger_data *hist_data, static void event_hist_trigger(struct event_trigger_data *data, void *rec) { struct hist_trigger_data *hist_data = data->private_data; + char compound_key[HIST_KEY_SIZE_MAX]; struct hist_field *key_field; struct tracing_map_elt *elt; u64 field_contents; void *key = NULL; unsigned int i; + if (hist_data->n_keys > 1) + memset(compound_key, 0, hist_data->key_size); + for_each_hist_key_field(i, hist_data) { key_field = hist_data->fields[i]; @@ -576,8 +587,16 @@ static void event_hist_trigger(struct event_trigger_data *data, void *rec) key = (void *)(unsigned long)field_contents; else key = (void *)&field_contents; + + if (hist_data->n_keys > 1) { + memcpy(compound_key + key_field->offset, key, + key_field->size); + } } + if (hist_data->n_keys > 1) + key = compound_key; + elt = tracing_map_insert(hist_data->map, key); if (elt) hist_trigger_elt_update(hist_data, elt, rec); @@ -602,11 +621,11 @@ hist_trigger_entry_print(struct seq_file *m, if (key_field->flags & HIST_FIELD_FL_STRING) { seq_printf(m, "%s: %-50s", key_field->field->name, - (char *)key); + (char *)(key + key_field->offset)); } else { - uval = *(u64 *)key; - seq_printf(m, "%s: %10llu", - key_field->field->name, uval); + uval = *(u64 *)(key + key_field->offset); + seq_printf(m, "%s: %10llu", key_field->field->name, + uval); } } -- cgit v1.2.3-59-g8ed1b