[19/54] tracing: Add per-element variable support to tracing_map
diff mbox series

Message ID TY1PR01MB169240F6BA2FADAEA41A508196090@TY1PR01MB1692.jpnprd01.prod.outlook.com
State New
Headers show
Series
  • [01/54] tracing: Remove redundant unread variable ret
Related show

Commit Message

Motai.Hirotaka@aj.MitsubishiElectric.co.jp Aug. 29, 2018, 12:17 p.m. UTC
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.

Link: http://lkml.kernel.org/r/7fa001108252556f0c6dd9d63145eabfe3370d1a.1516069914.git.tom.zanussi@linux.intel.com

Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
(cherry picked from commit 2734b629525a9dae5bf217cbf0a9651da93d2108)
Signed-off-by: Hirotaka MOTAI <Motai.Hirotaka@aj.MitsubishiElectric.co.jp>
---
 kernel/trace/tracing_map.c | 108 +++++++++++++++++++++++++++++++++++++
 kernel/trace/tracing_map.h |  11 ++++
 2 files changed, 119 insertions(+)

Patch
diff mbox series

diff --git a/kernel/trace/tracing_map.c b/kernel/trace/tracing_map.c
index 8d9feee5..28e4200a 100644
--- a/kernel/trace/tracing_map.c
+++ b/kernel/trace/tracing_map.c
@@ -61,16 +61,83 @@  void tracing_map_update_sum(struct tracing_map_elt *elt, unsigned int i, u64 n)
  *
  * Return: The sum associated with field i for elt.
  */
 u64 tracing_map_read_sum(struct tracing_map_elt *elt, unsigned int i)
 {
 	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;
 	char *b = val_b;
 
 	return strcmp(a, b);
 }
 
@@ -165,16 +232,38 @@  static int tracing_map_add_field(struct tracing_map *map,
  * Return: The index identifying the field in the map and associated
  * tracing_map_elts, or -EINVAL on error.
  */
 int tracing_map_add_sum_field(struct tracing_map *map)
 {
 	return tracing_map_add_field(map, tracing_map_cmp_atomic64);
 }
 
+/**
+ * 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
  * @cmp_fn: The comparison function that will be used to sort on the key
  *
  * Let the map know there is a key and that if it's used as a sort key
  * to use cmp_fn.
@@ -275,16 +364,21 @@  struct tracing_map_array *tracing_map_array_alloc(unsigned int n_elts,
 static void tracing_map_elt_clear(struct tracing_map_elt *elt)
 {
 	unsigned i;
 
 	for (i = 0; i < elt->map->n_fields; i++)
 		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);
 }
 
 static void tracing_map_elt_init_fields(struct tracing_map_elt *elt)
 {
 	unsigned int i;
 
@@ -301,16 +395,18 @@  static void tracing_map_elt_init_fields(struct tracing_map_elt *elt)
 static void tracing_map_elt_free(struct tracing_map_elt *elt)
 {
 	if (!elt)
 		return;
 
 	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);
 }
 
 static struct tracing_map_elt *tracing_map_elt_alloc(struct tracing_map *map)
 {
 	struct tracing_map_elt *elt;
 	int err = 0;
@@ -328,16 +424,28 @@  static struct tracing_map_elt *tracing_map_elt_alloc(struct tracing_map *map)
 	}
 
 	elt->fields = kcalloc(map->n_fields, sizeof(*elt->fields), GFP_KERNEL);
 	if (!elt->fields) {
 		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);
 
 	if (map->ops && map->ops->elt_alloc) {
 		err = map->ops->elt_alloc(elt);
 		if (err)
 			goto free;
 	}
 	return elt;
diff --git a/kernel/trace/tracing_map.h b/kernel/trace/tracing_map.h
index 0de50bbc..9a063dfb 100644
--- a/kernel/trace/tracing_map.h
+++ b/kernel/trace/tracing_map.h
@@ -5,16 +5,17 @@ 
 #define TRACING_MAP_BITS_DEFAULT	11
 #define TRACING_MAP_BITS_MAX		17
 #define TRACING_MAP_BITS_MIN		7
 
 #define TRACING_MAP_KEYS_MAX		2
 #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);
 
 /*
  * This is an overview of the tracing_map data structures and how they
  * relate to the tracing_map API.  The details of the algorithms
  * aren't discussed here - this is just a general overview of the data
@@ -132,16 +133,18 @@  struct tracing_map_field {
 		atomic64_t			sum;
 		unsigned int			offset;
 	};
 };
 
 struct tracing_map_elt {
 	struct tracing_map		*map;
 	struct tracing_map_field	*fields;
+	atomic64_t			*vars;
+	bool				*var_set;
 	void				*key;
 	void				*private_data;
 };
 
 struct tracing_map_entry {
 	u32				key;
 	struct tracing_map_elt		*val;
 };
@@ -187,16 +190,17 @@  struct tracing_map {
 	struct tracing_map_array	*map;
 	const struct tracing_map_ops	*ops;
 	void				*private_data;
 	struct tracing_map_field	fields[TRACING_MAP_FIELDS_MAX];
 	unsigned int			n_fields;
 	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;
 };
 
 /**
  * struct tracing_map_ops - callbacks for tracing_map
  *
  * The methods in this structure define callback functions for various
@@ -236,16 +240,17 @@  struct tracing_map_ops {
 extern struct tracing_map *
 tracing_map_create(unsigned int map_bits,
 		   unsigned int key_size,
 		   const struct tracing_map_ops *ops,
 		   void *private_data);
 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);
 
 extern void tracing_map_destroy(struct tracing_map *map);
 extern void tracing_map_clear(struct tracing_map *map);
 
 extern struct tracing_map_elt *
@@ -255,17 +260,23 @@  tracing_map_lookup(struct tracing_map *map, void *key);
 
 extern tracing_map_cmp_fn_t tracing_map_cmp_num(int field_size,
 						int field_is_signed);
 extern int tracing_map_cmp_string(void *val_a, void *val_b);
 extern int tracing_map_cmp_none(void *val_a, void *val_b);
 
 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,
 					tracing_map_cmp_fn_t cmp_fn);
 extern int
 tracing_map_sort_entries(struct tracing_map *map,
 			 struct tracing_map_sort_key *sort_keys,
 			 unsigned int n_sort_keys,