On 7/13/26 2:36 AM, Andrey Zhadchenko wrote:
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;
+
+
multiple blank line here
+ 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]++;
+ }
+}
+
multiple blank line here
+
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;
}
--
Best regards, Vasileios Almpanis
Software Developer, Virtuozzo.
_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel