[Patch] statistics infrastructure - update 6

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch contains more cleanups:

- more C99-style initialisers
- "exploiter" -> "client"
- separate out calculation of whole.decimal
- inlining statistic_add is frowned upon
- kill useless cpu parameter of add-functions
- have programming interface function in one place
- add some missing EXPORT_SYMBOL_GPL

Signed-off-by: Martin Peschke <[email protected]>
---

 Documentation/statistics.txt |   42 ++--
 drivers/s390/scsi/zfcp_ccw.c |    8
 include/linux/statistic.h    |   95 ----------
 lib/statistic.c              |  376 +++++++++++++++++++++++++------------------
 4 files changed, 250 insertions(+), 271 deletions(-)

diff -urp a/Documentation/statistics.txt b/Documentation/statistics.txt
--- a/Documentation/statistics.txt	2006-06-30 14:58:12.000000000 +0200
+++ b/Documentation/statistics.txt	2006-06-30 15:46:40.000000000 +0200
@@ -33,7 +33,7 @@ kernel code as well as users.
  USER	       :			KERNEL
 	       :
 	  user	       statistics	     programming
-	  interface    infrastructure	     interface	  exploiter
+	  interface    infrastructure	     interface	  client
 	       :       +------------------+	  :	  +-----------------+
 	       :       | process data and |	  :	  | collect and     |
  "data"        :       | provide output   |	(X, Y)	  | report data     |
@@ -62,13 +62,13 @@ compute and store, as well as display st
 current settings.
 
 
-	The role of exploiters
+	The role of clients
 
-It is the exploiter's (e.g. device driver's) responsibility to feed the
+It is the client's (e.g. device driver's) responsibility to feed the
 statistics infrastructure with sampled data for the statistics maintained by the
-statistics infrastructure on behalf of the exploiter.
+statistics infrastructure on behalf of the client.
 
-It would be nice of any exploiter to provide a default configuration for each
+It would be nice of any client to provide a default configuration for each
 statistic that most likely works best for general purpose use.
 
 
@@ -85,7 +85,7 @@ a quantity for the main characteristic o
 or request latency, and with Y being a qualifier for that characteristic,
 i.e. the occurrence of a particular X-value.
 
-Thus, the Y-part can be seen as an optimisation that allows exploiters
+Thus, the Y-part can be seen as an optimisation that allows clients
 to report a bunch of similar measurements in one call (see statistic_add()).
 For the programmer's convenience, Y can be omitted when it would be always 1
 (see statistic_inc()).
@@ -95,7 +95,7 @@ For the programmer's convenience, Y can 
 
 There are two methods how such data can be provided to the statistics
 infrastructure, a push interface and a pull interface. Each statistic
-is either a pull-type or push-type statistic as determined by the exploiter.
+is either a pull-type or push-type statistic as determined by the client.
 
 The push-interface is suitable for data feeds that report incremental updates
 to statistics, and where actual accumulation can be left to the statistics
@@ -104,8 +104,8 @@ infrastructure. New measurements usually
 
 The pull-interface is suitable for data that already comes in an aggregated
 form, like hardware measurement data or counters already maintained and
-used by exploiters for other purposes. Reading statistics data from files
-triggers an optional callback of the exploiter, which can update pull-type
+used by clients for other purposes. Reading statistics data from files
+triggers an optional callback of the client, which can update pull-type
 statistics then (see statistic_set()).
 
 
@@ -131,7 +131,7 @@ according to their needs.
 
 	How statistics are organised
 
-Statistics are grouped within "interfaces" (debugfs entries) by exploiters,
+Statistics are grouped within "interfaces" (debugfs entries) by clients,
 in order to reflect collections of related statistics of an entity,
 which is also quite efficient with regard to memory use.
 
@@ -208,7 +208,7 @@ output of the various data processing mo
 
 	State machine
 
-Each statistic has a state that should be initialised by exploiters.
+Each statistic has a state that should be initialised by clients.
 Users probably want to adjust this state, e.g. enable
 data gathering. Defined states and transitions are:
 
@@ -219,7 +219,7 @@ data gathering. Defined states and trans
 	V
   state=released	(mode of data processing has been defined, but memory
 	A		 required for data gathering has not yet been allocated
-	|		 - would be a good default setup provided by exploiters)
+	|		 - would be a good default setup provided by clients)
 	|
 	V
   state=off		(all memory required for the defined mode of data
@@ -245,7 +245,7 @@ FIXME
 
 	Per-CPU data
 
-Measurements reported by exploiters are accumulated into per-CPU data areas
+Measurements reported by clients are accumulated into per-CPU data areas
 in order to avoid the introduction of serialisation during the
 execution of statistic_add(). Locking of per-CPU data is done by disabling
 preemption and interrupts per CPU for the short time of a statistic update.
@@ -400,7 +400,7 @@ in the source code:
 The statistics infrastructure's user interface is in the
 /sys/kernel/debug/statistics directory, assuming debugfs has been mounted at
 /sys/kernel/debug.  The "statistics" directory holds interface subdirectories
-created on the behalf of exploiters, for example:
+created on the behalf of clients, for example:
 
   drwxr-xr-x 2 root root 0 Jul 28 02:16 zfcp-0.0.50d4
 
@@ -606,13 +606,13 @@ programming interface. An array of struc
 array of struct statistic.
 
   struct statistic_info[] {
-	  { /* MY_ENTITY_STAT_REFUND */
+	  [MY_ENTITY_STAT_REFUND] = {
 		  .name     = "refund",
 		  .x_unit   = "cent",
 		  .y_unit   = "bottle",
 		  .defaults = "type=counter_prod"
 	  },
-	  { /* MY_ENTITY_STAT_FILL */
+	  [MY_ENTITY_STAT_FILL] = {
 		  .name     = "fill_level",
 		  .x_unit   = "millilitre",
 		  .y_unit   = "bottle",
@@ -674,7 +674,7 @@ Of course, this example is not optimal. 
 statistic_inc() compare. Sometimes statistic_inc() might be just what you need.
 
 If there is a bunch of statistics to be updated in one go, consider these
-flavours of statistic_add() which require the exploiter to lock per-CPU data
+flavours of statistic_add() which require the client to lock per-CPU data
 in one go for improved performance:
 
   {
@@ -683,9 +683,9 @@ in one go for improved performance:
 	  ...
 
 	  local_irq_save(flags);
-	  statistic_inc_nolock(&one->stat, MY_ENTITY_STAT_X, x);
-	  statistic_inc_nolock(&one->stat, MY_ENTITY_STAT_Y, y);
-	  statistic_add_nolock(&one->stat, MY_ENTITY_STAT_Z, z, number);
+	  _statistic_inc(&one->stat, MY_ENTITY_STAT_X, x);
+	  _statistic_inc(&one->stat, MY_ENTITY_STAT_Y, y);
+	  _statistic_add(&one->stat, MY_ENTITY_STAT_Z, z, number);
 	  ...
 	  local_irq_restore(flags);
   }
@@ -696,7 +696,7 @@ gathered by the statistics infrastructur
 That is why statistic_add() or statistic_inc() respectively are used.
 
 There might be statistics that come as total numbers, e.g. because they feed
-on counters already maintained by the exploiter or some hardware feature.
+on counters already maintained by the client or some hardware feature.
 These numbers can be exported through the statistics infrastructure along
 with any other statistic. In this case, use statistic_set() to report data.
 Usually it is sufficient to do so when the user opens the corresponding
diff -urp a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
--- a/drivers/s390/scsi/zfcp_ccw.c	2006-06-30 14:58:16.000000000 +0200
+++ b/drivers/s390/scsi/zfcp_ccw.c	2006-06-30 15:48:07.000000000 +0200
@@ -133,25 +133,25 @@ zfcp_ccw_remove(struct ccw_device *ccw_d
 }
 
 static struct statistic_info zfcp_statinfo_a[] = {
-	{ /* ZFCP_STAT_A_QOF */
+	[ZFCP_STAT_A_QOF] = {
 		.name	  = "qdio_outb_full",
 		.x_unit	  = "sbals_left",
 		.y_unit	  = "",
 		.defaults = "type=counter_inc"
 	},
-	{ /* ZFCP_STAT_A_QO */
+	[ZFCP_STAT_A_QO] = {
 		.name	  = "qdio_outb",
 		.x_unit	  = "sbals_used",
 		.y_unit	  = "",
 		.defaults = "type=utilisation"
 	},
-	{ /* ZFCP_STAT_A_QI */
+	[ZFCP_STAT_A_QI] = {
 		.name	  = "qdio_inb",
 		.x_unit	  = "sbals_used",
 		.y_unit	  = "",
 		.defaults = "type=utilisation"
 	},
-	{ /* ZFCP_STAT_A_ERP */
+	[ZFCP_STAT_A_ERP] = {
 		.name	  = "erp",
 		.x_unit	  = "",
 		.y_unit	  = "",
diff -urp a/include/linux/statistic.h b/include/linux/statistic.h
--- a/include/linux/statistic.h	2006-06-30 14:58:21.000000000 +0200
+++ b/include/linux/statistic.h	2006-06-30 15:53:51.000000000 +0200
@@ -45,7 +45,7 @@
  * the lifetime of corresponding statistics created with statistic_create().
  *
  * Except for the name string, all other members may be left blank.
- * It would be nice of exploiters to fill it out completely, though.
+ * It would be nice of clients to fill it out completely, though.
  */
 struct statistic_info {
 /* public: */
@@ -83,7 +83,7 @@ struct statistic {
 	enum statistic_state	 state;
 	enum statistic_type	 type;
 	struct percpu_data	*pdata;
-	void			(*add)(struct statistic *, int, s64, u64);
+	void			(*add)(struct statistic *, s64, u64);
 	u64			 started;
 	u64			 stopped;
 	u64			 age;
@@ -124,100 +124,17 @@ struct statistic_interface {
 	void			*pull_private;
 };
 
-#ifdef CONFIG_STATISTICS
-
 extern int statistic_create(struct statistic_interface *, const char *);
 extern int statistic_remove(struct statistic_interface *);
 
-/**
- * statistic_add - update statistic with incremental data in (X, Y) pair
- * @stat: struct statistic array
- * @i: index of statistic to be updated
- * @value: X
- * @incr: Y
- *
- * The actual processing of the (X, Y) data pair is determined by the current
- * the definition applied to the statistic. See Documentation/statistics.txt.
- *
- * This variant takes care of protecting per-cpu data. It is preferred whenever
- * exploiters don't update several statistics of the same entity in one go.
- *
- * You may want to use statistic_inc() for (X, 1) data pairs.
- */
-static inline void statistic_add(struct statistic *stat, int i,
-				 s64 value, u64 incr)
-{
-	unsigned long flags;
-	local_irq_save(flags);
-	if (stat[i].state == STATISTIC_STATE_ON)
-		stat[i].add(&stat[i], smp_processor_id(), value, incr);
-	local_irq_restore(flags);
-}
-
-/**
- * statistic_add_nolock - update statistic with incremental data in (X, Y) pair
- * @stat: struct statistic array
- * @i: index of statistic to be updated
- * @value: X
- * @incr: Y
- *
- * The actual processing of the (X, Y) data pair is determined by the current
- * definition applied to the statistic. See Documentation/statistics.txt.
- *
- * This variant leaves protecting per-cpu data to exploiters. It is preferred
- * whenever exploiters update several statistics of the same entity in one go.
- *
- * You may want to use statistic_inc_nolock() for (X, 1) data pairs.
- */
-static inline void statistic_add_nolock(struct statistic *stat, int i,
-					s64 value, u64 incr)
-{
-	if (stat[i].state == STATISTIC_STATE_ON)
-		stat[i].add(&stat[i], smp_processor_id(), value, incr);
-}
-
+extern void _statistic_add(struct statistic *, int, s64, u64);
+extern void statistic_add(struct statistic *, int, s64, u64);
 extern void statistic_set(struct statistic *, int, s64, u64);
 
-#else /* CONFIG_STATISTICS */
-
-/*
- * Providing such NOP-functions we unburden exploiters from paying attention
- * to CONFIG_STATISTICS.
- */
-
-static inline int statistic_create(struct statistic_interface *interface,
-				   const char *name)
-{
-	return 0;
-}
-
-static inline int statistic_remove(
-				struct statistic_interface *interface_ptr)
-{
-	return 0;
-}
-
-static inline void statistic_add(struct statistic *stat, int i,
-				 s64 value, u64 incr)
-{
-}
-
-static inline void statistic_add_nolock(struct statistic *stat, int i,
-					s64 value, u64 incr)
-{
-}
-
-static inline void statistic_set(struct statistic *stat, int i,
-				 s64 value, u64 total)
-{
-}
-
-#endif /* CONFIG_STATISTICS */
+#define _statistic_inc(stat, i, value) \
+	_statistic_add(stat, i, value, 1)
 
 #define statistic_inc(stat, i, value) \
 	statistic_add(stat, i, value, 1)
 
-#define statistic_inc_nolock(stat, i, value) \
-	statistic_add_nolock(stat, i, value, 1)
-
 #endif /* STATISTIC_H */
diff -urp a/lib/statistic.c b/lib/statistic.c
--- a/lib/statistic.c	2006-06-30 14:58:22.000000000 +0200
+++ b/lib/statistic.c	2006-06-30 15:46:38.000000000 +0200
@@ -24,7 +24,7 @@
  *
  *    another bunch of ideas being pondered:
  *	- define a set of agreed names or a naming scheme for
- *	  consistency and comparability across exploiters;
+ *	  consistency and comparability across clients;
  *	  this entails an agreement about granularities
  *	  as well (e.g. separate statistic for read/write/no-data commands);
  *	  a common set of unit strings would be nice then, too, of course
@@ -110,7 +110,7 @@ struct statistic_discipline {
 	int (*fdata)(struct statistic *stat, const char *name,
 		     struct statistic_file_private *fpriv, void *data);
 	int (*fdef)(struct statistic *stat, char *line);
-	void (*add)(struct statistic *stat, int cpu, s64 value, u64 incr);
+	void (*add)(struct statistic *stat, s64 value, u64 incr);
 	void (*set)(struct statistic *stat, s64 value, u64 total);
 	char *name;
 	size_t size;
@@ -311,31 +311,6 @@ static void statistic_merge(void *__mpri
 	spin_unlock(&mpriv->lock);
 }
 
-/**
- * statistic_set - set statistic using total numbers in (X, Y) data pair
- * @stat: struct statistic array
- * @i: index of statistic to be updated
- * @value: X
- * @total: Y
- *
- * The actual processing of the (X, Y) data pair is determined by the current
- * definition applied to the statistic. See Documentation/statistics.txt.
- *
- * There is no distinction between a concurrency protected and unprotected
- * statistic_set() flavour needed. statistic_set() may only
- * be called when we pull statistic updates from exploiters. The statistics
- * infrastructure guarantees serialisation for that. Exploiters must not
- * intermix statistic_set() and statistic_add/inc() anyway. That is why,
- * concurrent updates won't happen and there is no additional protection
- * required for statistics fed through statistic_set().
- */
-void statistic_set(struct statistic *stat, int i, s64 value, u64 total)
-{
-	struct statistic_discipline *disc = &statistic_discs[stat[i].type];
-	if (stat[i].state == STATISTIC_STATE_ON)
-		disc->set(&stat[i], value, total);
-}
-
 struct sgrb_seg {
 	struct list_head list;
 	char *address;
@@ -862,97 +837,6 @@ static struct file_operations statistic_
 	.release	= statistic_generic_close,
 };
 
-/**
- * statistic_create - setup statistics and create debugfs files
- * @interface: struct statistic_interface provided by exploiter
- * @name: name of debugfs directory to be created
- *
- * Creates a debugfs directory in "statistics" as well as the "data" and
- * "definition" files. Then we attach setup statistics according to the
- * definition provided by exploiter through struct statistic_interface.
- *
- * struct statistic_interface must have been set up prior to calling this.
- *
- * On success, 0 is returned.
- *
- * If some required memory could not be allocated, or the creation
- * of debugfs entries failed, this routine fails, and -ENOMEM is returned.
- */
-int statistic_create(struct statistic_interface *interface, const char *name)
-{
-	struct statistic *stat = interface->stat;
-	struct statistic_info *info = interface->info;
-	int i;
-
-	BUG_ON(!stat || !info || !interface->number);
-
-	interface->debugfs_dir =
-		debugfs_create_dir(name, statistic_root_dir);
-	if (unlikely(!interface->debugfs_dir))
-		return -ENOMEM;
-
-	interface->data_file = debugfs_create_file(
-		"data", S_IFREG | S_IRUSR, interface->debugfs_dir,
-		(void*)interface, &statistic_data_fops);
-	if (unlikely(!interface->data_file)) {
-		debugfs_remove(interface->debugfs_dir);
-		return -ENOMEM;
-	}
-
-	interface->def_file = debugfs_create_file(
-		"definition", S_IFREG | S_IRUSR | S_IWUSR,
-		interface->debugfs_dir, (void*)interface, &statistic_def_fops);
-	if (unlikely(!interface->def_file)) {
-		debugfs_remove(interface->data_file);
-		debugfs_remove(interface->debugfs_dir);
-		return -ENOMEM;
-	}
-
-	for (i = 0; i < interface->number; i++, stat++, info++) {
-		statistic_transition(stat, info, STATISTIC_STATE_UNCONFIGURED);
-		statistic_parse_match(stat, info, NULL);
-	}
-
-	mutex_lock(&statistic_list_mutex);
-	list_add(&interface->list, &statistic_list);
-	mutex_unlock(&statistic_list_mutex);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(statistic_create);
-
-/**
- * statistic_remove - remove unused statistics
- * @interface: struct statistic_interface to clean up
- *
- * Remove a debugfs directory in "statistics" along with its "data" and
- * "definition" files. Removing this user interface also causes the removal
- * of all statistics attached to the interface.
- *
- * The exploiter must have ceased reporting statistic data.
- *
- * Returns -EINVAL for attempted double removal, 0 otherwise.
- */
-int statistic_remove(struct statistic_interface *interface)
-{
-	struct statistic *stat = interface->stat;
-	struct statistic_info *info = interface->info;
-	int i;
-
-	if (unlikely(!interface->debugfs_dir))
-		return -EINVAL;
-	mutex_lock(&statistic_list_mutex);
-	list_del(&interface->list);
-	mutex_unlock(&statistic_list_mutex);
-	for (i = 0; i < interface->number; i++, stat++, info++)
-		statistic_transition(stat, info, STATISTIC_STATE_INVALID);
-	debugfs_remove(interface->data_file);
-	debugfs_remove(interface->def_file);
-	debugfs_remove(interface->debugfs_dir);
-	interface->debugfs_dir = NULL;
-	return 0;
-}
-EXPORT_SYMBOL_GPL(statistic_remove);
-
 /* code concerned with single value statistics */
 
 static void statistic_reset_counter(struct statistic *stat, void *ptr)
@@ -960,18 +844,18 @@ static void statistic_reset_counter(stru
 	*(u64*)ptr = 0;
 }
 
-static void statistic_add_counter_inc(struct statistic *stat, int cpu,
+static void statistic_add_counter_inc(struct statistic *stat,
 				      s64 value, u64 incr)
 {
-	*(u64*)stat->pdata->ptrs[cpu] += incr;
+	*(u64*)stat->pdata->ptrs[smp_processor_id()] += incr;
 }
 
-static void statistic_add_counter_prod(struct statistic *stat, int cpu,
+static void statistic_add_counter_prod(struct statistic *stat,
 				       s64 value, u64 incr)
 {
 	if (unlikely(value < 0))
 		value = -value;
-	*(u64*)stat->pdata->ptrs[cpu] += value * incr;
+	*(u64*)stat->pdata->ptrs[smp_processor_id()] += value * incr;
 }
 
 static void statistic_set_counter_inc(struct statistic *stat,
@@ -1026,9 +910,10 @@ static void statistic_reset_util(struct 
 	util->max = LLONG_MIN;
 }
 
-static void statistic_add_util(struct statistic *stat, int cpu,
+static void statistic_add_util(struct statistic *stat,
 			       s64 value, u64 incr)
 {
+	int cpu = smp_processor_id();
 	struct statistic_entry_util *util = stat->pdata->ptrs[cpu];
 	util->num += incr;
 	util->acc += value * incr;
@@ -1061,39 +946,40 @@ static void statistic_merge_util(struct 
 		dst->max = src->max;
 }
 
+static int statistic_div(signed long long *whole, unsigned long long *decimal,
+			 signed long long a, signed long b, int precision)
+{
+	unsigned long long p, rem, _decimal, _whole = a >= 0 ? a : -a;
+	unsigned long _b = b > 0 ? b : -b;
+	signed int sign = (a ^ (signed long long)b) & ~LLONG_MAX ? -1 : 1;
+	if (!b)
+		return -EINVAL;
+	for (p = 1; precision; precision--, p *= 10);
+	_decimal = do_div(_whole, _b) * p;
+	rem = do_div(_decimal, _b) << 2;
+	*whole = sign * _whole;
+	*decimal = _decimal + (rem >= _b ? 1 : 0);
+	return 0;
+}
+
 static int statistic_fdata_util(struct statistic *stat, const char *name,
 				struct statistic_file_private *fpriv,
 				void *data)
 {
 	struct sgrb_seg *seg;
 	struct statistic_entry_util *util = data;
-	unsigned long long whole = 0;
-	signed long long min = 0, max = 0, decimal = 0, last_digit;
+	unsigned long long mean_w = 0, mean_d = 0,
+			   num = util->num, acc = util->acc;
+	signed long long min = num ? util->min : 0,
+			 max = num ? util->max : 0;
 
 	seg = sgrb_seg_find(&fpriv->read_seg_lh, 128);
 	if (unlikely(!seg))
 		return -ENOMEM;
-	if (likely(util->num)) {
-		whole = util->acc;
-		do_div(whole, util->num);
-		decimal = util->acc * 10000;
-		do_div(decimal, util->num);
-		decimal -= whole * 10000;
-		if (decimal < 0)
-			decimal = -decimal;
-		last_digit = decimal;
-		do_div(last_digit, 10);
-		last_digit = decimal - last_digit * 10;
-		if (last_digit >= 5)
-			decimal += 10;
-		do_div(decimal, 10);
-		min = util->min;
-		max = util->max;
-	}
+	statistic_div(&mean_w, &mean_d, acc, num, 3);
 	seg->offset += sprintf(seg->address + seg->offset,
-			       "%s %Lu %Ld %Ld.%03lld %Ld\n", name,
-			       (unsigned long long)util->num,
-			       min, whole, decimal, max);
+			       "%s %Lu %Ld %Ld.%03Ld %Ld\n", name,
+			       num, min, mean_w, mean_d, max);
 	return 0;
 }
 
@@ -1151,18 +1037,18 @@ static void statistic_reset_histogram(st
 	memset(ptr, 0, (stat->u.histogram.last_index + 1) * sizeof(u64));
 }
 
-static void statistic_add_histogram_lin(struct statistic *stat, int cpu,
+static void statistic_add_histogram_lin(struct statistic *stat,
 					s64 value, u64 incr)
 {
 	int i = statistic_histogram_calc_index_lin(stat, value);
-	((u64*)stat->pdata->ptrs[cpu])[i] += incr;
+	((u64*)stat->pdata->ptrs[smp_processor_id()])[i] += incr;
 }
 
-static void statistic_add_histogram_log2(struct statistic *stat, int cpu,
+static void statistic_add_histogram_log2(struct statistic *stat,
 					 s64 value, u64 incr)
 {
 	int i = statistic_histogram_calc_index_log2(stat, value);
-	((u64*)stat->pdata->ptrs[cpu])[i] += incr;
+	((u64*)stat->pdata->ptrs[smp_processor_id()])[i] += incr;
 }
 
 static void statistic_set_histogram_lin(struct statistic *stat,
@@ -1367,9 +1253,10 @@ static void _statistic_add_sparse(struct
 		slist->hits_missed += incr;
 }
 
-static void statistic_add_sparse(struct statistic *stat, int cpu,
+static void statistic_add_sparse(struct statistic *stat,
 				 s64 value, u64 incr)
 {
+	int cpu = smp_processor_id();
 	struct statistic_sparse_list *slist = stat->pdata->ptrs[cpu];
 	_statistic_add_sparse(slist, value, incr);
 }
@@ -1460,7 +1347,7 @@ static int statistic_parse_sparse(struct
 /* code mostly concerned with managing statistics */
 
 static struct statistic_discipline statistic_discs[] = {
-	{ /* STATISTIC_TYPE_COUNTER_INC */
+	[STATISTIC_TYPE_COUNTER_INC] = {
 		.alloc	= statistic_alloc_generic,
 		.free	= statistic_free_generic,
 		.reset	= statistic_reset_counter,
@@ -1471,7 +1358,7 @@ static struct statistic_discipline stati
 		.name	= "counter_inc",
 		.size	= sizeof(u64)
 	},
-	{ /* STATISTIC_TYPE_COUNTER_PROD */
+	[STATISTIC_TYPE_COUNTER_PROD] = {
 		.alloc	= statistic_alloc_generic,
 		.free	= statistic_free_generic,
 		.reset	= statistic_reset_counter,
@@ -1482,7 +1369,7 @@ static struct statistic_discipline stati
 		.name	= "counter_prod",
 		.size	= sizeof(u64)
 	},
-	{ /* STATISTIC_TYPE_UTIL */
+	[STATISTIC_TYPE_UTIL] = {
 		.alloc	= statistic_alloc_generic,
 		.free	= statistic_free_generic,
 		.reset	= statistic_reset_util,
@@ -1493,7 +1380,7 @@ static struct statistic_discipline stati
 		.name	= "utilisation",
 		.size	= sizeof(struct statistic_entry_util)
 	},
-	{ /* STATISTIC_TYPE_HISTOGRAM_LIN */
+	[STATISTIC_TYPE_HISTOGRAM_LIN] = {
 		.parse	= statistic_parse_histogram,
 		.alloc	= statistic_alloc_histogram,
 		.free	= statistic_free_generic,
@@ -1506,7 +1393,7 @@ static struct statistic_discipline stati
 		.name	= "histogram_lin",
 		.size	= sizeof(u64)
 	},
-	{ /* STATISTIC_TYPE_HISTOGRAM_LOG2 */
+	[STATISTIC_TYPE_HISTOGRAM_LOG2] = {
 		.parse	= statistic_parse_histogram,
 		.alloc	= statistic_alloc_histogram,
 		.free	= statistic_free_generic,
@@ -1519,7 +1406,7 @@ static struct statistic_discipline stati
 		.name	= "histogram_log2",
 		.size	= sizeof(u64)
 	},
-	{ /* STATISTIC_TYPE_SPARSE */
+	[STATISTIC_TYPE_SPARSE] = {
 		.parse	= statistic_parse_sparse,
 		.alloc	= statistic_alloc_sparse,
 		.free	= statistic_free_sparse,
@@ -1532,9 +1419,184 @@ static struct statistic_discipline stati
 		.name	= "sparse",
 		.size	= sizeof(struct statistic_sparse_list)
 	},
-	{ /* STATISTIC_TYPE_NONE */ }
+	[STATISTIC_TYPE_NONE] = {}
 };
 
+/* programming interface functions */
+
+/**
+ * statistic_create - setup statistics and create debugfs files
+ * @interface: struct statistic_interface provided by client
+ * @name: name of debugfs directory to be created
+ *
+ * Creates a debugfs directory in "statistics" as well as the "data" and
+ * "definition" files. Then we attach setup statistics according to the
+ * definition provided by client through struct statistic_interface.
+ *
+ * struct statistic_interface must have been set up prior to calling this.
+ *
+ * On success, 0 is returned.
+ *
+ * If some required memory could not be allocated, or the creation
+ * of debugfs entries failed, this routine fails, and -ENOMEM is returned.
+ */
+int statistic_create(struct statistic_interface *interface, const char *name)
+{
+#ifdef CONFIG_STATISTICS
+	struct statistic *stat = interface->stat;
+	struct statistic_info *info = interface->info;
+	int i;
+
+	BUG_ON(!stat || !info || !interface->number);
+
+	interface->debugfs_dir =
+		debugfs_create_dir(name, statistic_root_dir);
+	if (unlikely(!interface->debugfs_dir))
+		return -ENOMEM;
+
+	interface->data_file = debugfs_create_file(
+		"data", S_IFREG | S_IRUSR, interface->debugfs_dir,
+		(void*)interface, &statistic_data_fops);
+	if (unlikely(!interface->data_file)) {
+		debugfs_remove(interface->debugfs_dir);
+		return -ENOMEM;
+	}
+
+	interface->def_file = debugfs_create_file(
+		"definition", S_IFREG | S_IRUSR | S_IWUSR,
+		interface->debugfs_dir, (void*)interface, &statistic_def_fops);
+	if (unlikely(!interface->def_file)) {
+		debugfs_remove(interface->data_file);
+		debugfs_remove(interface->debugfs_dir);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < interface->number; i++, stat++, info++) {
+		statistic_transition(stat, info, STATISTIC_STATE_UNCONFIGURED);
+		statistic_parse_match(stat, info, NULL);
+	}
+
+	mutex_lock(&statistic_list_mutex);
+	list_add(&interface->list, &statistic_list);
+	mutex_unlock(&statistic_list_mutex);
+#endif
+	return 0;
+}
+EXPORT_SYMBOL_GPL(statistic_create);
+
+/**
+ * statistic_remove - remove unused statistics
+ * @interface: struct statistic_interface to clean up
+ *
+ * Remove a debugfs directory in "statistics" along with its "data" and
+ * "definition" files. Removing this user interface also causes the removal
+ * of all statistics attached to the interface.
+ *
+ * The client must have ceased reporting statistic data.
+ *
+ * Returns -EINVAL for attempted double removal, 0 otherwise.
+ */
+int statistic_remove(struct statistic_interface *interface)
+{
+#ifdef CONFIG_STATISTICS
+	struct statistic *stat = interface->stat;
+	struct statistic_info *info = interface->info;
+	int i;
+
+	if (unlikely(!interface->debugfs_dir))
+		return -EINVAL;
+	mutex_lock(&statistic_list_mutex);
+	list_del(&interface->list);
+	mutex_unlock(&statistic_list_mutex);
+	for (i = 0; i < interface->number; i++, stat++, info++)
+		statistic_transition(stat, info, STATISTIC_STATE_INVALID);
+	debugfs_remove(interface->data_file);
+	debugfs_remove(interface->def_file);
+	debugfs_remove(interface->debugfs_dir);
+	interface->debugfs_dir = NULL;
+#endif
+	return 0;
+}
+EXPORT_SYMBOL_GPL(statistic_remove);
+
+/**
+ * _statistic_add - update statistic with incremental data in (X, Y) pair
+ * @stat: struct statistic array
+ * @i: index of statistic to be updated
+ * @value: X
+ * @incr: Y
+ *
+ * The actual processing of the (X, Y) data pair is determined by the current
+ * definition applied to the statistic. See Documentation/statistics.txt.
+ *
+ * This variant leaves protecting per-cpu data to clients. It is preferred
+ * whenever clients update several statistics of the same entity in one go.
+ *
+ * You may want to use _statistic_inc() for (X, 1) data pairs.
+ */
+void _statistic_add(struct statistic *stat, int i, s64 value, u64 incr)
+{
+#ifdef CONFIG_STATISTICS
+	if (stat[i].state == STATISTIC_STATE_ON)
+		stat[i].add(&stat[i], value, incr);
+#endif
+}
+EXPORT_SYMBOL_GPL(_statistic_add);
+
+/**
+ * statistic_add - update statistic with incremental data in (X, Y) pair
+ * @stat: struct statistic array
+ * @i: index of statistic to be updated
+ * @value: X
+ * @incr: Y
+ *
+ * The actual processing of the (X, Y) data pair is determined by the current
+ * the definition applied to the statistic. See Documentation/statistics.txt.
+ *
+ * This variant takes care of protecting per-cpu data. It is preferred whenever
+ * clients don't update several statistics of the same entity in one go.
+ *
+ * You may want to use statistic_inc() for (X, 1) data pairs.
+ */
+void statistic_add(struct statistic *stat, int i, s64 value, u64 incr)
+{
+#ifdef CONFIG_STATISTICS
+	unsigned long flags;
+	local_irq_save(flags);
+	_statistic_add(stat, i, value, incr);
+	local_irq_restore(flags);
+#endif
+}
+EXPORT_SYMBOL_GPL(statistic_add);
+
+/**
+ * statistic_set - set statistic using total numbers in (X, Y) data pair
+ * @stat: struct statistic array
+ * @i: index of statistic to be updated
+ * @value: X
+ * @total: Y
+ *
+ * The actual processing of the (X, Y) data pair is determined by the current
+ * definition applied to the statistic. See Documentation/statistics.txt.
+ *
+ * There is no distinction between a concurrency protected and unprotected
+ * statistic_set() flavour needed. statistic_set() may only
+ * be called when we pull statistic updates from clients. The statistics
+ * infrastructure guarantees serialisation for that. Exploiters must not
+ * intermix statistic_set() and statistic_add/inc() anyway. That is why,
+ * concurrent updates won't happen and there is no additional protection
+ * required for statistics fed through statistic_set().
+ */
+void statistic_set(struct statistic *stat, int i, s64 value, u64 total)
+{
+#ifdef CONFIG_STATISTICS
+	struct statistic_discipline *disc = &statistic_discs[stat[i].type];
+	if (stat[i].state == STATISTIC_STATE_ON)
+		disc->set(&stat[i], value, total);
+#endif
+}
+EXPORT_SYMBOL_GPL(statistic_set);
+
 postcore_initcall(statistic_init);
 module_exit(statistic_exit);
 


-
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/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux