| From: Tom Zanussi <tom.zanussi@linux.intel.com> |
| Date: Tue, 5 Sep 2017 16:57:27 -0500 |
| Subject: [PATCH 15/40] tracing: Add per-element variable support to |
| tracing_map |
| |
| In order to allow information to be passed between trace events, add |
| support for per-element variables to tracing_map. This provides a |
| means for histograms to associate a value or values with an entry when |
| it's saved or updated, and retrieved by a subsequent event occurrences. |
| |
| Variables can be set using tracing_map_set_var() and read using |
| tracing_map_read_var(). tracing_map_var_set() returns true or false |
| depending on whether or not the variable has been set or not, which is |
| important for event-matching applications. |
| |
| tracing_map_read_var_once() reads the variable and resets it to the |
| 'unset' state, implementing read-once variables, which are also |
| important for event-matching uses. |
| |
| Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com> |
| Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| --- |
| kernel/trace/tracing_map.c | 108 +++++++++++++++++++++++++++++++++++++++++++++ |
| kernel/trace/tracing_map.h | 11 ++++ |
| 2 files changed, 119 insertions(+) |
| |
| --- a/kernel/trace/tracing_map.c |
| +++ b/kernel/trace/tracing_map.c |
| @@ -66,6 +66,73 @@ u64 tracing_map_read_sum(struct tracing_ |
| return (u64)atomic64_read(&elt->fields[i].sum); |
| } |
| |
| +/** |
| + * tracing_map_set_var - Assign a tracing_map_elt's variable field |
| + * @elt: The tracing_map_elt |
| + * @i: The index of the given variable associated with the tracing_map_elt |
| + * @n: The value to assign |
| + * |
| + * Assign n to variable i associated with the specified tracing_map_elt |
| + * instance. The index i is the index returned by the call to |
| + * tracing_map_add_var() when the tracing map was set up. |
| + */ |
| +void tracing_map_set_var(struct tracing_map_elt *elt, unsigned int i, u64 n) |
| +{ |
| + atomic64_set(&elt->vars[i], n); |
| + elt->var_set[i] = true; |
| +} |
| + |
| +/** |
| + * tracing_map_var_set - Return whether or not a variable has been set |
| + * @elt: The tracing_map_elt |
| + * @i: The index of the given variable associated with the tracing_map_elt |
| + * |
| + * Return true if the variable has been set, false otherwise. The |
| + * index i is the index returned by the call to tracing_map_add_var() |
| + * when the tracing map was set up. |
| + */ |
| +bool tracing_map_var_set(struct tracing_map_elt *elt, unsigned int i) |
| +{ |
| + return elt->var_set[i]; |
| +} |
| + |
| +/** |
| + * tracing_map_read_var - Return the value of a tracing_map_elt's variable field |
| + * @elt: The tracing_map_elt |
| + * @i: The index of the given variable associated with the tracing_map_elt |
| + * |
| + * Retrieve the value of the variable i associated with the specified |
| + * tracing_map_elt instance. The index i is the index returned by the |
| + * call to tracing_map_add_var() when the tracing map was set |
| + * up. |
| + * |
| + * Return: The variable value associated with field i for elt. |
| + */ |
| +u64 tracing_map_read_var(struct tracing_map_elt *elt, unsigned int i) |
| +{ |
| + return (u64)atomic64_read(&elt->vars[i]); |
| +} |
| + |
| +/** |
| + * tracing_map_read_var_once - Return and reset a tracing_map_elt's variable field |
| + * @elt: The tracing_map_elt |
| + * @i: The index of the given variable associated with the tracing_map_elt |
| + * |
| + * Retrieve the value of the variable i associated with the specified |
| + * tracing_map_elt instance, and reset the variable to the 'not set' |
| + * state. The index i is the index returned by the call to |
| + * tracing_map_add_var() when the tracing map was set up. The reset |
| + * essentially makes the variable a read-once variable if it's only |
| + * accessed using this function. |
| + * |
| + * Return: The variable value associated with field i for elt. |
| + */ |
| +u64 tracing_map_read_var_once(struct tracing_map_elt *elt, unsigned int i) |
| +{ |
| + elt->var_set[i] = false; |
| + return (u64)atomic64_read(&elt->vars[i]); |
| +} |
| + |
| int tracing_map_cmp_string(void *val_a, void *val_b) |
| { |
| char *a = val_a; |
| @@ -171,6 +238,28 @@ int tracing_map_add_sum_field(struct tra |
| } |
| |
| /** |
| + * tracing_map_add_var - Add a field describing a tracing_map var |
| + * @map: The tracing_map |
| + * |
| + * Add a var to the map and return the index identifying it in the map |
| + * and associated tracing_map_elts. This is the index used for |
| + * instance to update a var for a particular tracing_map_elt using |
| + * tracing_map_update_var() or reading it via tracing_map_read_var(). |
| + * |
| + * Return: The index identifying the var in the map and associated |
| + * tracing_map_elts, or -EINVAL on error. |
| + */ |
| +int tracing_map_add_var(struct tracing_map *map) |
| +{ |
| + int ret = -EINVAL; |
| + |
| + if (map->n_vars < TRACING_MAP_VARS_MAX) |
| + ret = map->n_vars++; |
| + |
| + return ret; |
| +} |
| + |
| +/** |
| * tracing_map_add_key_field - Add a field describing a tracing_map key |
| * @map: The tracing_map |
| * @offset: The offset within the key |
| @@ -277,6 +366,11 @@ static void tracing_map_elt_clear(struct |
| if (elt->fields[i].cmp_fn == tracing_map_cmp_atomic64) |
| atomic64_set(&elt->fields[i].sum, 0); |
| |
| + for (i = 0; i < elt->map->n_vars; i++) { |
| + atomic64_set(&elt->vars[i], 0); |
| + elt->var_set[i] = false; |
| + } |
| + |
| if (elt->map->ops && elt->map->ops->elt_clear) |
| elt->map->ops->elt_clear(elt); |
| } |
| @@ -303,6 +397,8 @@ static void tracing_map_elt_free(struct |
| if (elt->map->ops && elt->map->ops->elt_free) |
| elt->map->ops->elt_free(elt); |
| kfree(elt->fields); |
| + kfree(elt->vars); |
| + kfree(elt->var_set); |
| kfree(elt->key); |
| kfree(elt); |
| } |
| @@ -329,6 +425,18 @@ static struct tracing_map_elt *tracing_m |
| err = -ENOMEM; |
| goto free; |
| } |
| + |
| + elt->vars = kcalloc(map->n_vars, sizeof(*elt->vars), GFP_KERNEL); |
| + if (!elt->vars) { |
| + err = -ENOMEM; |
| + goto free; |
| + } |
| + |
| + elt->var_set = kcalloc(map->n_vars, sizeof(*elt->var_set), GFP_KERNEL); |
| + if (!elt->var_set) { |
| + err = -ENOMEM; |
| + goto free; |
| + } |
| |
| tracing_map_elt_init_fields(elt); |
| |
| --- a/kernel/trace/tracing_map.h |
| +++ b/kernel/trace/tracing_map.h |
| @@ -9,6 +9,7 @@ |
| #define TRACING_MAP_VALS_MAX 3 |
| #define TRACING_MAP_FIELDS_MAX (TRACING_MAP_KEYS_MAX + \ |
| TRACING_MAP_VALS_MAX) |
| +#define TRACING_MAP_VARS_MAX 16 |
| #define TRACING_MAP_SORT_KEYS_MAX 2 |
| |
| typedef int (*tracing_map_cmp_fn_t) (void *val_a, void *val_b); |
| @@ -136,6 +137,8 @@ struct tracing_map_field { |
| struct tracing_map_elt { |
| struct tracing_map *map; |
| struct tracing_map_field *fields; |
| + atomic64_t *vars; |
| + bool *var_set; |
| void *key; |
| void *private_data; |
| }; |
| @@ -191,6 +194,7 @@ struct tracing_map { |
| int key_idx[TRACING_MAP_KEYS_MAX]; |
| unsigned int n_keys; |
| struct tracing_map_sort_key sort_key; |
| + unsigned int n_vars; |
| atomic64_t hits; |
| atomic64_t drops; |
| }; |
| @@ -240,6 +244,7 @@ tracing_map_create(unsigned int map_bits |
| extern int tracing_map_init(struct tracing_map *map); |
| |
| extern int tracing_map_add_sum_field(struct tracing_map *map); |
| +extern int tracing_map_add_var(struct tracing_map *map); |
| extern int tracing_map_add_key_field(struct tracing_map *map, |
| unsigned int offset, |
| tracing_map_cmp_fn_t cmp_fn); |
| @@ -259,7 +264,13 @@ extern int tracing_map_cmp_none(void *va |
| |
| extern void tracing_map_update_sum(struct tracing_map_elt *elt, |
| unsigned int i, u64 n); |
| +extern void tracing_map_set_var(struct tracing_map_elt *elt, |
| + unsigned int i, u64 n); |
| +extern bool tracing_map_var_set(struct tracing_map_elt *elt, unsigned int i); |
| extern u64 tracing_map_read_sum(struct tracing_map_elt *elt, unsigned int i); |
| +extern u64 tracing_map_read_var(struct tracing_map_elt *elt, unsigned int i); |
| +extern u64 tracing_map_read_var_once(struct tracing_map_elt *elt, unsigned int i); |
| + |
| extern void tracing_map_set_field_descr(struct tracing_map *map, |
| unsigned int i, |
| unsigned int key_offset, |