[RFC] [Patch 2/4] timer_stats slimmed down: statistics prereq,labels

From: Martin Peschke
Date: Sat Apr 14 2007 - 06:11:04 EST


This patch allows clients of the statistics infrastructure to be called
back when an entry of a statistic is printed and if the client might
want to add some kind of label to the output string. A line would look
like this then:

<statistic name> <basket> <hits> <label>

Signed-off-by: Martin Peschke <mp3@xxxxxxxxxx>
---

include/linux/statistic.h | 5 +++
lib/statistic.c | 68 ++++++++++++++++++++++++++++++++--------------
2 files changed, 53 insertions(+), 20 deletions(-)

Index: linux/include/linux/statistic.h
===================================================================
--- linux.orig/include/linux/statistic.h
+++ linux/include/linux/statistic.h
@@ -55,6 +55,7 @@ struct statistic_info {
int flags;
#define STATISTIC_FLAGS_NOINCR 0x01 /* no incremental data */
#define STATISTIC_FLAGS_NOFLEX 0x02 /* type can't be altered by user */
+#define STATISTIC_FLAGS_LABEL 0x04 /* client want's to label buckets */
char *defaults;
};

@@ -106,6 +107,7 @@ struct statistic {
* @info: a struct statistic_info array describing the struct statistic array
* @number: number of entries in both arrays
* @pull: an optional function called when user reads data from file
+ * @label: an optional function retrieving a label for each statistics entry
* @private: optional data pointer reserved for use by clients
*
* Exploiters must setup a struct statistic_interface prior to calling
@@ -122,6 +124,9 @@ struct statistic_interface {
struct statistic_info *info;
int number;
int (*pull)(struct statistic_interface *interface);
+ void (*label)(struct statistic_interface *interface,
+ int i, s64 value,
+ struct seq_file *seq);
void *private;
};

Index: linux/lib/statistic.c
===================================================================
--- linux.orig/lib/statistic.c
+++ linux/lib/statistic.c
@@ -95,7 +95,7 @@ struct statistic_discipline {
void (*merge)(struct statistic *stat, void *dst, void *src);
void (*def)(struct statistic *stat, struct seq_file *seq);
void (*data)(struct statistic *stat, struct seq_file *seq,
- const char *name);
+ struct statistic_interface *interface, int i);
void (*add)(struct statistic *stat, s64 value, u64 incr);
void (*set)(struct statistic *stat, s64 value, u64 total);
char *name;
@@ -559,13 +559,11 @@ static int statistic_seq_show_def(struct
static int statistic_seq_show_data(struct seq_file *seq, void *_seq_priv)
{
struct statistic_seq_private *seq_priv = _seq_priv;
- struct statistic_interface *interface = seq_priv->interface;
struct statistic *stat = &seq_priv->stat[seq_priv->i];
- struct statistic_info *info = &interface->info[seq_priv->i];
struct statistic_discipline *disc = &statistic_discs[stat->type];

if (stat->state >= STATISTIC_STATE_OFF)
- disc->data(stat, seq, info->name);
+ disc->data(stat, seq, seq_priv->interface, seq_priv->i);
return 0;
}

@@ -783,9 +781,12 @@ static void statistic_merge_counter(stru
}

static void statistic_data_counter(struct statistic *stat, struct seq_file *seq,
- const char *name)
+ struct statistic_interface *interface, int i)
{
- seq_printf(seq, "%s %Lu\n", name, *(unsigned long long *)stat->data);
+ struct statistic_info *info = &interface->info[i];
+
+ seq_printf(seq, "%s %Lu\n",
+ info->name, *(unsigned long long *)stat->data);
}

/* code concerned with utilisation indicator statistic */
@@ -869,8 +870,9 @@ static int statistic_div(signed long lon
}

static void statistic_data_util(struct statistic *stat, struct seq_file *seq,
- const char *name)
+ struct statistic_interface *interface, int i)
{
+ struct statistic_info *info = &interface->info[i];
struct statistic_entry_util *util = stat->data;
unsigned long long mean_w = 0, mean_d = 0, var_w = 0, var_d = 0,
num = util->num, acc = util->acc, sqr = util->sqr;
@@ -881,8 +883,12 @@ static void statistic_data_util(struct s
statistic_div(&var_w, &var_d, sqr - mean_w * mean_w, num, 3);
seq_printf(seq, "%s samples %Lu\n%s minimum %Ld\n"
"%s average %Ld.%03Ld\n%s maximum %Ld\n"
- "%s variance %Ld.%03Ld\n", name, num, name, min,
- name, mean_w, mean_d, name, max, name, var_w, var_d);
+ "%s variance %Ld.%03Ld\n",
+ info->name, num,
+ info->name, min,
+ info->name, mean_w, mean_d,
+ info->name, max,
+ info->name, var_w, var_d);
}

/* code concerned with histogram statistics */
@@ -977,19 +983,36 @@ static void statistic_merge_histogram(st
dst[i] += src[i];
}

+static void _statistic_data_histogram(struct seq_file *seq, const char *prefix,
+ signed long long bound,
+ unsigned long long hits,
+ struct statistic_info *info,
+ struct statistic_interface *interface,
+ int i)
+{
+ seq_printf(seq, "%s %s%Ld %Lu ", info->name, prefix, bound, hits);
+ if (info->flags & STATISTIC_FLAGS_LABEL)
+ interface->label(interface, i, bound, seq);
+ seq_printf(seq, "\n");
+}
+
static void statistic_data_histogram(struct statistic *stat,
- struct seq_file *seq, const char *name)
+ struct seq_file *seq,
+ struct statistic_interface *interface,
+ int i)
{
- int i;
+ struct statistic_info *info = &interface->info[i];
+ int j;
signed long long bound = 0;
unsigned long long hits = 0;

- for (i = 0; i < (stat->u.histogram.last_index); i++) {
- bound = statistic_histogram_calc_value(stat, i);
- hits = ((u64*)stat->data)[i];
- seq_printf(seq, "%s <=%Ld %Lu\n", name, bound, hits);
+ for (j = 0; j < (stat->u.histogram.last_index); j++) {
+ bound = statistic_histogram_calc_value(stat, j);
+ hits = ((u64*)stat->data)[j];
+ _statistic_data_histogram(seq, "<=", bound, hits, info,
+ interface, i);
}
- seq_printf(seq, "%s >%Ld %Lu\n", name, bound, hits);
+ _statistic_data_histogram(seq, ">", bound, hits, info, interface, i);
}

static void statistic_def_histogram(struct statistic *stat,
@@ -1170,17 +1193,22 @@ static void statistic_merge_sparse(struc
}

static void statistic_data_sparse(struct statistic *stat, struct seq_file *seq,
- const char *name)
+ struct statistic_interface *interface, int i)
{
+ struct statistic_info *info = &interface->info[i];
struct statistic_sparse_list *slist = stat->data;
struct statistic_entry_sparse *entry;

- seq_printf(seq, "%s missed 0x%Lu\n", name,
+ seq_printf(seq, "%s missed 0x%Lu\n", info->name,
(unsigned long long)slist->hits_missed);
- list_for_each_entry(entry, &slist->entry_lh, list)
- seq_printf(seq, "%s 0x%Lx %Lu\n", name,
+ list_for_each_entry(entry, &slist->entry_lh, list) {
+ seq_printf(seq, "%s 0x%Lx %Lu ", info->name,
(signed long long)entry->value,
(unsigned long long)entry->hits);
+ if (info->flags & STATISTIC_FLAGS_LABEL)
+ interface->label(interface, i, entry->value, seq);
+ seq_printf(seq, "\n");
+ }
}

static void statistic_def_sparse(struct statistic *stat, struct seq_file *seq)


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