From b741ae74170643de0fec3005c717e3a397c3e034 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 9 Mar 2018 19:52:11 +0300 Subject: block/accounting: introduce latency histogram Introduce latency histogram statics for block devices. For each accounted operation type, the latency region [0, +inf) is divided into subregions by several points. Then, calculate hits for each subregion. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20180309165212.97144-2-vsementsov@virtuozzo.com> Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Signed-off-by: Eric Blake --- block/accounting.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) (limited to 'block/accounting.c') diff --git a/block/accounting.c b/block/accounting.c index 87ef5bb..70a3d9a 100644 --- a/block/accounting.c +++ b/block/accounting.c @@ -94,6 +94,94 @@ void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie, cookie->type = type; } +/* block_latency_histogram_compare_func: + * Compare @key with interval [@it[0], @it[1]). + * Return: -1 if @key < @it[0] + * 0 if @key in [@it[0], @it[1]) + * +1 if @key >= @it[1] + */ +static int block_latency_histogram_compare_func(const void *key, const void *it) +{ + uint64_t k = *(uint64_t *)key; + uint64_t a = ((uint64_t *)it)[0]; + uint64_t b = ((uint64_t *)it)[1]; + + return k < a ? -1 : (k < b ? 0 : 1); +} + +static void block_latency_histogram_account(BlockLatencyHistogram *hist, + int64_t latency_ns) +{ + uint64_t *pos; + + if (hist->bins == NULL) { + /* histogram disabled */ + return; + } + + + if (latency_ns < hist->boundaries[0]) { + hist->bins[0]++; + return; + } + + if (latency_ns >= hist->boundaries[hist->nbins - 2]) { + hist->bins[hist->nbins - 1]++; + return; + } + + pos = bsearch(&latency_ns, hist->boundaries, hist->nbins - 2, + sizeof(hist->boundaries[0]), + block_latency_histogram_compare_func); + assert(pos != NULL); + + hist->bins[pos - hist->boundaries + 1]++; +} + +int block_latency_histogram_set(BlockAcctStats *stats, enum BlockAcctType type, + uint64List *boundaries) +{ + BlockLatencyHistogram *hist = &stats->latency_histogram[type]; + uint64List *entry; + uint64_t *ptr; + uint64_t prev = 0; + int new_nbins = 1; + + for (entry = boundaries; entry; entry = entry->next) { + if (entry->value <= prev) { + return -EINVAL; + } + new_nbins++; + prev = entry->value; + } + + hist->nbins = new_nbins; + g_free(hist->boundaries); + hist->boundaries = g_new(uint64_t, hist->nbins - 1); + for (entry = boundaries, ptr = hist->boundaries; entry; + entry = entry->next, ptr++) + { + *ptr = entry->value; + } + + g_free(hist->bins); + hist->bins = g_new0(uint64_t, hist->nbins); + + return 0; +} + +void block_latency_histograms_clear(BlockAcctStats *stats) +{ + int i; + + for (i = 0; i < BLOCK_MAX_IOTYPE; i++) { + BlockLatencyHistogram *hist = &stats->latency_histogram[i]; + g_free(hist->bins); + g_free(hist->boundaries); + memset(hist, 0, sizeof(*hist)); + } +} + static void block_account_one_io(BlockAcctStats *stats, BlockAcctCookie *cookie, bool failed) { @@ -116,6 +204,9 @@ static void block_account_one_io(BlockAcctStats *stats, BlockAcctCookie *cookie, stats->nr_ops[cookie->type]++; } + block_latency_histogram_account(&stats->latency_histogram[cookie->type], + latency_ns); + if (!failed || stats->account_failed) { stats->total_time_ns[cookie->type] += latency_ns; stats->last_access_time_ns = time_ns; -- cgit v1.1