[PATCH v8 10/23] tracing: Add hist trigger support for compound keys

From: Tom Zanussi
Date: Mon Jun 29 2015 - 16:40:42 EST


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.

Signed-off-by: Tom Zanussi <tom.zanussi@xxxxxxxxxxxxxxx>
---
kernel/trace/trace.c | 8 +++++---
kernel/trace/trace_events_hist.c | 40 ++++++++++++++++++++++++++++++----------
2 files changed, 35 insertions(+), 13 deletions(-)

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 8109b89..1e4801e 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -3787,19 +3787,21 @@ static const char readme_msg[] =
"\t Filters can be ignored when removing a trigger.\n"
#ifdef CONFIG_HIST_TRIGGERS
" hist trigger\t- If set, event hits are aggregated into a hash table\n"
- "\t Format: hist:keys=<field1>\n"
+ "\t Format: hist:keys=<field1>[,field2,...]\n"
"\t [:values=<field1[,field2,...]]\n"
"\t [:size=#entries]\n"
"\t [if <filter>]\n\n"
"\t When a matching event is hit, an entry is added to a hash\n"
- "\t table using the key and value(s) named. Keys and values\n"
+ "\t table using the key(s) and value(s) named. Keys and values\n"
"\t correspond to fields in the event's format description.\n"
"\t Values must correspond to numeric fields - on an event hit,\n"
"\t the value(s) will be added to a sum kept for that field.\n"
"\t The special string 'hitcount' can be used in place of an\n"
"\t explicit value field - this is simply a count of event hits.\n"
"\t If 'values' is not specified, 'hitcount' will be assumed.\n"
- "\t of event hits. Keys can be any field.\n\n"
+ "\t of event hits. Keys can be any field. Compound keys\n"
+ "\t consisting of up to two fields can be specified by the 'keys'\n"
+ "\t keyword.\n\n"
"\t Reading the 'hist' file for the event will dump the hash\n"
"\t table in its entirety to stdout. Each printed hash table\n"
"\t entry is a simple list of the keys and values comprising the\n"
diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index 503df07..3d5433a 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)
@@ -64,8 +65,8 @@ DEFINE_HIST_FIELD_FN(s8);
DEFINE_HIST_FIELD_FN(u8);

#define HITCOUNT_IDX 0
-#define HIST_KEY_MAX 1
-#define HIST_KEY_SIZE_MAX MAX_FILTER_STR_VAL
+#define HIST_KEY_MAX 2
+#define HIST_KEY_SIZE_MAX (MAX_FILTER_STR_VAL + sizeof(u64))

enum hist_field_flags {
HIST_FIELD_HITCOUNT = 1,
@@ -327,6 +328,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)
{
@@ -353,7 +355,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;
@@ -368,7 +371,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;

@@ -384,9 +387,11 @@ static int create_key_fields(struct hist_trigger_data *hist_data,
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;
@@ -451,7 +456,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);

@@ -531,6 +539,7 @@ 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;
@@ -542,6 +551,9 @@ static void event_hist_trigger(struct event_trigger_data *data, void *rec)
return;
}

+ if (hist_data->n_keys > 1)
+ memset(compound_key, 0, hist_data->key_size);
+
for (i = hist_data->n_vals; i < hist_data->n_fields; i++) {
key_field = hist_data->fields[i];

@@ -550,8 +562,16 @@ static void event_hist_trigger(struct event_trigger_data *data, void *rec)
key = (void *)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);
@@ -580,11 +600,11 @@ hist_trigger_entry_print(struct seq_file *m,

if (key_field->flags & HIST_FIELD_STRING) {
seq_printf(m, "%s: %-35s", 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);
}
}

--
1.9.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/