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-s390" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html