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 <[email protected]>
---
 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 [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to