A region currently tracks a single latency histogram, whose boundaries
and per-bucket counters are stored directly in struct dm_stat. In order
to later add histograms that only account I/O of a particular direction,
generalize the storage so that a region can hold several independent
histograms.

Each histogram is now described by struct dm_stat_histogram, carrying its
own boundaries, entry count and an offset into the per-entry bucket array.
The per-entry bucket array is the concatenation of every histogram's
buckets, and histogram_buckets holds the total. All allocation, clearing,
summing, printing and listing loops are updated to iterate over
the histograms and their individual sizes.

This is a preparatory change with no functional difference.

https://virtuozzo.atlassian.net/browse/VSTOR-103846
Signed-off-by: Andrey Zhadchenko <[email protected]>
---
 drivers/md/dm-stats.c | 160 +++++++++++++++++++++++++++++-------------
 1 file changed, 110 insertions(+), 50 deletions(-)

diff --git a/drivers/md/dm-stats.c b/drivers/md/dm-stats.c
index 7a465b5e36cd3..21109ccfa10a9 100644
--- a/drivers/md/dm-stats.c
+++ b/drivers/md/dm-stats.c
@@ -39,6 +39,14 @@ struct dm_stat_shared {
        struct dm_stat_percpu tmp;
 };
 
+#define DM_STAT_MAX_HISTOGRAMS         1
+
+struct dm_stat_histogram {
+       unsigned int n_entries;
+       unsigned int offset;
+       unsigned long long *boundaries;
+};
+
 struct dm_stat {
        struct list_head list_entry;
        int id;
@@ -47,8 +55,9 @@ struct dm_stat {
        sector_t start;
        sector_t end;
        sector_t step;
-       unsigned int n_histogram_entries;
-       unsigned long long *histogram_boundaries;
+       unsigned int n_histograms;
+       unsigned int histogram_buckets;
+       struct dm_stat_histogram histograms[DM_STAT_MAX_HISTOGRAMS];
        const char *program_id;
        const char *aux_data;
        struct rcu_head rcu_head;
@@ -173,9 +182,11 @@ static void dm_kvfree(void *ptr, size_t alloc_size)
 static void dm_stat_free(struct rcu_head *head)
 {
        int cpu;
+       unsigned int i;
        struct dm_stat *s = container_of(head, struct dm_stat, rcu_head);
 
-       kfree(s->histogram_boundaries);
+       for (i = 0; i < s->n_histograms; i++)
+               kfree(s->histograms[i].boundaries);
        kfree(s->program_id);
        kfree(s->aux_data);
        for_each_possible_cpu(cpu) {
@@ -262,8 +273,8 @@ static void dm_stats_recalc_precise_timestamps(struct 
dm_stats *stats)
 
 static int dm_stats_create(struct dm_stats *stats, sector_t start, sector_t 
end,
                           sector_t step, unsigned int stat_flags,
-                          unsigned int n_histogram_entries,
-                          unsigned long long *histogram_boundaries,
+                          unsigned int n_histograms,
+                          struct dm_stat_histogram *histograms,
                           const char *program_id, const char *aux_data,
                           void (*suspend_callback)(struct mapped_device *),
                           void (*resume_callback)(struct mapped_device *),
@@ -276,6 +287,8 @@ static int dm_stats_create(struct dm_stats *stats, sector_t 
start, sector_t end,
        size_t shared_alloc_size;
        size_t percpu_alloc_size;
        size_t histogram_alloc_size;
+       unsigned int histogram_buckets = 0;
+       unsigned int hn;
        struct dm_stat_percpu *p;
        int cpu;
        int ret_id;
@@ -284,6 +297,9 @@ static int dm_stats_create(struct dm_stats *stats, sector_t 
start, sector_t end,
        if (end < start || !step)
                return -EINVAL;
 
+       for (hn = 0; hn < n_histograms; hn++)
+               histogram_buckets += histograms[hn].n_entries + 1;
+
        n_entries = end - start;
        if (dm_sector_div64(n_entries, step))
                n_entries++;
@@ -302,15 +318,17 @@ static int dm_stats_create(struct dm_stats *stats, 
sector_t start, sector_t end,
        if (percpu_alloc_size / sizeof(struct dm_stat_percpu) != n_entries)
                return -EOVERFLOW;
 
-       histogram_alloc_size = (n_histogram_entries + 1) * (size_t)n_entries * 
sizeof(unsigned long long);
-       if (histogram_alloc_size / (n_histogram_entries + 1) != 
(size_t)n_entries * sizeof(unsigned long long))
+       histogram_alloc_size = histogram_buckets * (size_t)n_entries * 
sizeof(unsigned long long);
+       if (histogram_buckets &&
+           histogram_alloc_size / histogram_buckets
+            != (size_t)n_entries * sizeof(unsigned long long))
                return -EOVERFLOW;
 
-       if ((n_histogram_entries + 1) * (size_t)n_entries > 
DM_STAT_MAX_HISTOGRAM_ENTRIES)
+       if (histogram_buckets * (size_t)n_entries > 
DM_STAT_MAX_HISTOGRAM_ENTRIES)
                return -EOVERFLOW;
 
        if ((stat_flags & STAT_HIST_TOTAL_LATENCY) &&
-           (!n_histogram_entries || !(stat_flags & STAT_PRECISE_TIMESTAMPS)))
+           (!histogram_buckets || !(stat_flags & STAT_PRECISE_TIMESTAMPS)))
                return -EINVAL;
 
        if (!check_shared_memory(shared_alloc_size + histogram_alloc_size +
@@ -330,12 +348,20 @@ static int dm_stats_create(struct dm_stats *stats, 
sector_t start, sector_t end,
        s->percpu_alloc_size = percpu_alloc_size;
        s->histogram_alloc_size = histogram_alloc_size;
 
-       s->n_histogram_entries = n_histogram_entries;
-       s->histogram_boundaries = kmemdup(histogram_boundaries,
-                                         s->n_histogram_entries * 
sizeof(unsigned long long), GFP_KERNEL);
-       if (!s->histogram_boundaries) {
-               r = -ENOMEM;
-               goto out;
+       s->n_histograms = n_histograms;
+       s->histogram_buckets = histogram_buckets;
+       for (hn = 0; hn < n_histograms; hn++) {
+               s->histograms[hn].n_entries = histograms[hn].n_entries;
+               s->histograms[hn].offset = (hn ? s->histograms[hn - 1].offset +
+                                           s->histograms[hn - 1].n_entries + 1 
: 0);
+               s->histograms[hn].boundaries = 
kmemdup(histograms[hn].boundaries,
+                                                      histograms[hn].n_entries 
*
+                                                       sizeof(unsigned long 
long),
+                                                      GFP_KERNEL);
+               if (!s->histograms[hn].boundaries) {
+                       r = -ENOMEM;
+                       goto out;
+               }
        }
 
        s->program_id = kstrdup(program_id, GFP_KERNEL);
@@ -355,7 +381,7 @@ static int dm_stats_create(struct dm_stats *stats, sector_t 
start, sector_t end,
                cond_resched();
        }
 
-       if (s->n_histogram_entries) {
+       if (s->histogram_buckets) {
                unsigned long long *hi;
 
                hi = dm_kvzalloc(s->histogram_alloc_size, NUMA_NO_NODE);
@@ -365,7 +391,7 @@ static int dm_stats_create(struct dm_stats *stats, sector_t 
start, sector_t end,
                }
                for (ni = 0; ni < n_entries; ni++) {
                        s->stat_shared[ni].tmp.histogram = hi;
-                       hi += s->n_histogram_entries + 1;
+                       hi += s->histogram_buckets;
                        cond_resched();
                }
        }
@@ -377,7 +403,7 @@ static int dm_stats_create(struct dm_stats *stats, sector_t 
start, sector_t end,
                        goto out;
                }
                s->stat_percpu[cpu] = p;
-               if (s->n_histogram_entries) {
+               if (s->histogram_buckets) {
                        unsigned long long *hi;
 
                        hi = dm_kvzalloc(s->histogram_alloc_size, 
cpu_to_node(cpu));
@@ -387,7 +413,7 @@ static int dm_stats_create(struct dm_stats *stats, sector_t 
start, sector_t end,
                        }
                        for (ni = 0; ni < n_entries; ni++) {
                                p[ni].histogram = hi;
-                               hi += s->n_histogram_entries + 1;
+                               hi += s->histogram_buckets;
                                cond_resched();
                        }
                }
@@ -498,6 +524,7 @@ static int dm_stats_list(struct dm_stats *stats, const char 
*program,
        struct dm_stat *s;
        sector_t len;
        unsigned int sz = 0;
+       unsigned int hn;
 
        /*
         * Output format:
@@ -518,14 +545,15 @@ static int dm_stats_list(struct dm_stats *stats, const 
char *program,
                                DMEMIT(" precise_timestamps");
                        if (s->stat_flags & STAT_HIST_TOTAL_LATENCY)
                                DMEMIT(" hist_total_latency");
-                       if (s->n_histogram_entries) {
+                       for (hn = 0; hn < s->n_histograms; hn++) {
+                               struct dm_stat_histogram *h = 
&s->histograms[hn];
                                unsigned int i;
 
                                DMEMIT(" histogram:");
-                               for (i = 0; i < s->n_histogram_entries; i++) {
+                               for (i = 0; i < h->n_entries; i++) {
                                        if (i)
                                                DMEMIT(",");
-                                       DMEMIT("%llu", 
s->histogram_boundaries[i]);
+                                       DMEMIT("%llu", h->boundaries[i]);
                                }
                        }
                        DMEMIT("\n");
@@ -568,6 +596,30 @@ static void dm_stat_round(struct dm_stat *s, struct 
dm_stat_shared *shared,
        shared->stamp = now;
 }
 
+
+static void dm_stats_bin_duration(struct dm_stat *s, struct dm_stat_percpu *p,
+                                 unsigned long long duration)
+{
+       unsigned int hn;
+
+
+       for (hn = 0; hn < s->n_histograms; hn++) {
+               struct dm_stat_histogram *h = &s->histograms[hn];
+               unsigned int lo = 0, hi = h->n_entries + 1;
+
+               while (lo + 1 < hi) {
+                       unsigned int mid = (lo + hi) / 2;
+
+                       if (h->boundaries[mid - 1] > duration)
+                               hi = mid;
+                       else
+                               lo = mid;
+               }
+               p->histogram[h->offset + lo]++;
+       }
+}
+
+
 static void dm_stat_for_entry(struct dm_stat *s, size_t entry,
                              blk_opf_t bi_opf, sector_t len,
                              struct dm_stats_aux *stats_aux, bool end,
@@ -619,22 +671,12 @@ static void dm_stat_for_entry(struct dm_stat *s, size_t 
entry,
                        p->ticks[idx] += stats_aux->duration_ns;
                        duration = stats_aux->duration_ns;
                }
-               if (s->n_histogram_entries) {
-                       unsigned int lo = 0, hi = s->n_histogram_entries + 1;
-
+               if (s->n_histograms) {
                        if ((s->stat_flags & STAT_HIST_TOTAL_LATENCY) &&
                            stats_aux->histogram_duration_ns)
                                duration = stats_aux->histogram_duration_ns;
 
-                       while (lo + 1 < hi) {
-                               unsigned int mid = (lo + hi) / 2;
-
-                               if (s->histogram_boundaries[mid - 1] > duration)
-                                       hi = mid;
-                               else
-                                       lo = mid;
-                       }
-                       p->histogram[lo]++;
+                       dm_stats_bin_duration(s, p, duration);
                }
        }
 
@@ -756,8 +798,8 @@ static void __dm_stat_init_temporary_percpu_totals(struct 
dm_stat_shared *shared
        shared->tmp.io_ticks_total = 0;
        shared->tmp.time_in_queue = 0;
 
-       if (s->n_histogram_entries)
-               memset(shared->tmp.histogram, 0, (s->n_histogram_entries + 1) * 
sizeof(unsigned long long));
+       if (s->histogram_buckets)
+               memset(shared->tmp.histogram, 0, s->histogram_buckets * 
sizeof(unsigned long long));
 
        for_each_possible_cpu(cpu) {
                p = &s->stat_percpu[cpu][x];
@@ -773,10 +815,10 @@ static void __dm_stat_init_temporary_percpu_totals(struct 
dm_stat_shared *shared
                shared->tmp.io_ticks[WRITE] += READ_ONCE(p->io_ticks[WRITE]);
                shared->tmp.io_ticks_total += READ_ONCE(p->io_ticks_total);
                shared->tmp.time_in_queue += READ_ONCE(p->time_in_queue);
-               if (s->n_histogram_entries) {
+               if (s->histogram_buckets) {
                        unsigned int i;
 
-                       for (i = 0; i < s->n_histogram_entries + 1; i++)
+                       for (i = 0; i < s->histogram_buckets; i++)
                                shared->tmp.histogram[i] += 
READ_ONCE(p->histogram[i]);
                }
        }
@@ -808,10 +850,10 @@ static void __dm_stat_clear(struct dm_stat *s, size_t 
idx_start, size_t idx_end,
                p->io_ticks_total -= shared->tmp.io_ticks_total;
                p->time_in_queue -= shared->tmp.time_in_queue;
                local_irq_enable();
-               if (s->n_histogram_entries) {
+               if (s->histogram_buckets) {
                        unsigned int i;
 
-                       for (i = 0; i < s->n_histogram_entries + 1; i++) {
+                       for (i = 0; i < s->histogram_buckets; i++) {
                                local_irq_disable();
                                p = &s->stat_percpu[smp_processor_id()][x];
                                p->histogram[i] -= shared->tmp.histogram[i];
@@ -874,6 +916,7 @@ static int dm_stats_print(struct dm_stats *stats, int id,
        size_t x;
        sector_t start, end, step;
        size_t idx_end;
+       unsigned int hn;
        struct dm_stat_shared *shared;
 
        /*
@@ -924,11 +967,13 @@ static int dm_stats_print(struct dm_stats *stats, int id,
                       dm_jiffies_to_msec64(s, shared->tmp.time_in_queue),
                       dm_jiffies_to_msec64(s, shared->tmp.io_ticks[READ]),
                       dm_jiffies_to_msec64(s, shared->tmp.io_ticks[WRITE]));
-               if (s->n_histogram_entries) {
+               for (hn = 0; hn < s->n_histograms; hn++) {
+                       struct dm_stat_histogram *h = &s->histograms[hn];
                        unsigned int i;
 
-                       for (i = 0; i < s->n_histogram_entries + 1; i++)
-                               DMEMIT("%s%llu", !i ? " " : ":", 
shared->tmp.histogram[i]);
+                       for (i = 0; i < h->n_entries + 1; i++)
+                               DMEMIT("%s%llu", !i ? " " : ":",
+                                      shared->tmp.histogram[h->offset + i]);
                }
                DMEMIT("\n");
 
@@ -1013,6 +1058,21 @@ static int parse_histogram(const char *h, unsigned int 
*n_histogram_entries,
        }
 }
 
+static int add_histogram(struct dm_stat_histogram *histograms,
+                        unsigned int *n_histograms, const char *h)
+{
+       unsigned int idx;
+
+       if (*n_histograms >= DM_STAT_MAX_HISTOGRAMS)
+               return -EINVAL;
+
+       idx = (*n_histograms)++;
+       histograms[idx].boundaries = NULL;
+
+       return parse_histogram(h, &histograms[idx].n_entries,
+                              &histograms[idx].boundaries);
+}
+
 static int message_stats_create(struct mapped_device *md,
                                unsigned int argc, char **argv,
                                char *result, unsigned int maxlen)
@@ -1024,11 +1084,12 @@ static int message_stats_create(struct mapped_device 
*md,
        unsigned int divisor;
        const char *program_id, *aux_data;
        unsigned int stat_flags = 0;
-       unsigned int n_histogram_entries = 0;
-       unsigned long long *histogram_boundaries = NULL;
+       unsigned int n_histograms = 0;
+       struct dm_stat_histogram histograms[DM_STAT_MAX_HISTOGRAMS];
        struct dm_arg_set as, as_backup;
        const char *a;
        unsigned int feature_args;
+       unsigned int i;
 
        /*
         * Input format:
@@ -1081,9 +1142,7 @@ static int message_stats_create(struct mapped_device *md,
                        else if (!strcasecmp(a, "hist_total_latency"))
                                stat_flags |= STAT_HIST_TOTAL_LATENCY;
                        else if (!strncasecmp(a, "histogram:", 10)) {
-                               if (n_histogram_entries)
-                                       goto ret_einval;
-                               r = parse_histogram(a + 10, 
&n_histogram_entries, &histogram_boundaries);
+                               r = add_histogram(histograms, &n_histograms, a 
+ 10);
                                if (r)
                                        goto ret;
                        } else
@@ -1120,7 +1179,7 @@ static int message_stats_create(struct mapped_device *md,
        }
 
        id = dm_stats_create(dm_get_stats(md), start, end, step, stat_flags,
-                            n_histogram_entries, histogram_boundaries, 
program_id, aux_data,
+                            n_histograms, histograms, program_id, aux_data,
                             dm_internal_suspend_fast, dm_internal_resume_fast, 
md);
        if (id < 0) {
                r = id;
@@ -1135,7 +1194,8 @@ static int message_stats_create(struct mapped_device *md,
 ret_einval:
        r = -EINVAL;
 ret:
-       kfree(histogram_boundaries);
+       for (i = 0; i < n_histograms; i++)
+               kfree(histograms[i].boundaries);
        return r;
 }
 
-- 
2.43.5

_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to