From nobody Mon Apr 29 03:54:20 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=virtuozzo.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517926328026491.26310030526577; Tue, 6 Feb 2018 06:12:08 -0800 (PST) Received: from localhost ([::1]:48129 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ej3yh-00071E-4F for importer@patchew.org; Tue, 06 Feb 2018 09:12:07 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43706) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ej3uE-000399-Vu for qemu-devel@nongnu.org; Tue, 06 Feb 2018 09:07:32 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ej3uA-0004F9-Pa for qemu-devel@nongnu.org; Tue, 06 Feb 2018 09:07:30 -0500 Received: from new-relay.sw.ru ([195.214.232.40]:48806) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1ej3uA-0004E3-HF; Tue, 06 Feb 2018 09:07:26 -0500 Received: from msk-vpn.virtuozzo.com ([195.214.232.6] helo=kvm.sw.ru) by new-relay.sw.ru with esmtp (Exim 4.89) (envelope-from ) id 1ej3u6-00081t-Uf; Tue, 06 Feb 2018 17:07:23 +0300 From: Vladimir Sementsov-Ogievskiy To: qemu-devel@nongnu.org, qemu-block@nongnu.org Date: Tue, 6 Feb 2018 17:07:21 +0300 Message-Id: <20180206140722.10110-2-vsementsov@virtuozzo.com> X-Mailer: git-send-email 2.11.1 In-Reply-To: <20180206140722.10110-1-vsementsov@virtuozzo.com> References: <20180206140722.10110-1-vsementsov@virtuozzo.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-Received-From: 195.214.232.40 Subject: [Qemu-devel] [PATCH 1/2] block/accounting: introduce latency histogram X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, vsementsov@virtuozzo.com, armbru@redhat.com, mreitz@redhat.com, nshirokovskiy@virtuozzo.com, den@openvz.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Introduce latency histogram statics for block devices. For each accounted operation type latency region [0, +inf) is divided into subregions by several points. Then, calculate hits for each subregion. Signed-off-by: Vladimir Sementsov-Ogievskiy --- include/block/accounting.h | 8 +++++ block/accounting.c | 83 ++++++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 91 insertions(+) diff --git a/include/block/accounting.h b/include/block/accounting.h index b833d26d6c..7fbfc86c43 100644 --- a/include/block/accounting.h +++ b/include/block/accounting.h @@ -45,6 +45,12 @@ struct BlockAcctTimedStats { QSLIST_ENTRY(BlockAcctTimedStats) entries; }; =20 +typedef struct BlockLatencyHistogram { + int size; + uint64_t *points; /* @size-1 points here (all points, except 0 and +in= f) */ + uint64_t *histogram[BLOCK_MAX_IOTYPE]; /* @size elements for each type= */ +} BlockLatencyHistogram; + struct BlockAcctStats { QemuMutex lock; uint64_t nr_bytes[BLOCK_MAX_IOTYPE]; @@ -57,6 +63,7 @@ struct BlockAcctStats { QSLIST_HEAD(, BlockAcctTimedStats) intervals; bool account_invalid; bool account_failed; + BlockLatencyHistogram latency_histogram; }; =20 typedef struct BlockAcctCookie { @@ -82,5 +89,6 @@ void block_acct_merge_done(BlockAcctStats *stats, enum Bl= ockAcctType type, int64_t block_acct_idle_time_ns(BlockAcctStats *stats); double block_acct_queue_depth(BlockAcctTimedStats *stats, enum BlockAcctType type); +int block_latency_histogram_set(BlockAcctStats *stats, uint64List *latency= ); =20 #endif diff --git a/block/accounting.c b/block/accounting.c index 87ef5bbfaa..a34ef09015 100644 --- a/block/accounting.c +++ b/block/accounting.c @@ -94,6 +94,86 @@ void block_acct_start(BlockAcctStats *stats, BlockAcctCo= okie *cookie, cookie->type =3D type; } =20 +/* block_latency_histogram_compare_func + * Compare @key with interval [@el, @el+1), where @el+1 is a next array el= ement + * after @el. + * Return: -1 if @key < @el + * 0 if @key in [@el, @el+1) + * +1 if @key >=3D @el+1 + */ +static int block_latency_histogram_compare_func(const void *key, const voi= d *el) +{ + uint64_t k =3D *(uint64_t *)key; + uint64_t a =3D *(uint64_t *)el; + uint64_t b =3D *((uint64_t *)el + 1); + + return k < a ? -1 : (k < b ? 0 : 1); +} + +static void block_latency_histogram_account(BlockLatencyHistogram *hist, + enum BlockAcctType type, + int64_t latency_ns) +{ + uint64_t *data, *pos; + + if (hist->points =3D=3D NULL) { + /* histogram disabled */ + return; + } + + data =3D hist->histogram[type]; + + if (latency_ns < hist->points[0]) { + data[0]++; + return; + } + + if (latency_ns >=3D hist->points[hist->size - 2]) { + data[hist->size - 1]++; + return; + } + + pos =3D bsearch(&latency_ns, hist->points, hist->size - 2, + sizeof(hist->points[0]), + block_latency_histogram_compare_func); + assert(pos !=3D NULL); + + data[pos - hist->points + 1]++; +} + +int block_latency_histogram_set(BlockAcctStats *stats, uint64List *latency) +{ + BlockLatencyHistogram *hist =3D &stats->latency_histogram; + uint64List *entry; + uint64_t *ptr; + int i; + uint64_t prev =3D 0; + + hist->size =3D 1; + + for (entry =3D latency; entry; entry =3D entry->next) { + if (entry->value <=3D prev) { + return -EINVAL; + } + hist->size++; + prev =3D entry->value; + } + + hist->points =3D g_renew(uint64_t, hist->points, hist->size - 1); + for (entry =3D latency, ptr =3D hist->points; entry; + entry =3D entry->next, ptr++) + { + *ptr =3D entry->value; + } + + for (i =3D 0; i < BLOCK_MAX_IOTYPE; i++) { + hist->histogram[i] =3D g_renew(uint64_t, hist->histogram[i], hist-= >size); + memset(hist->histogram[i], 0, hist->size * sizeof(uint64_t)); + } + + return 0; +} + static void block_account_one_io(BlockAcctStats *stats, BlockAcctCookie *c= ookie, bool failed) { @@ -116,6 +196,9 @@ static void block_account_one_io(BlockAcctStats *stats,= BlockAcctCookie *cookie, stats->nr_ops[cookie->type]++; } =20 + block_latency_histogram_account(&stats->latency_histogram, cookie->typ= e, + latency_ns); + if (!failed || stats->account_failed) { stats->total_time_ns[cookie->type] +=3D latency_ns; stats->last_access_time_ns =3D time_ns; --=20 2.11.1 From nobody Mon Apr 29 03:54:20 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=virtuozzo.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517926394740391.2127915526992; Tue, 6 Feb 2018 06:13:14 -0800 (PST) Received: from localhost ([::1]:48201 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ej3zj-0007nh-Qd for importer@patchew.org; Tue, 06 Feb 2018 09:13:11 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43726) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ej3uG-0003As-UK for qemu-devel@nongnu.org; Tue, 06 Feb 2018 09:07:34 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ej3uB-0004FN-07 for qemu-devel@nongnu.org; Tue, 06 Feb 2018 09:07:32 -0500 Received: from new-relay.sw.ru ([195.214.232.40]:48804) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1ej3uA-0004E5-Nh; Tue, 06 Feb 2018 09:07:26 -0500 Received: from msk-vpn.virtuozzo.com ([195.214.232.6] helo=kvm.sw.ru) by new-relay.sw.ru with esmtp (Exim 4.89) (envelope-from ) id 1ej3u7-00081t-1Q; Tue, 06 Feb 2018 17:07:23 +0300 From: Vladimir Sementsov-Ogievskiy To: qemu-devel@nongnu.org, qemu-block@nongnu.org Date: Tue, 6 Feb 2018 17:07:22 +0300 Message-Id: <20180206140722.10110-3-vsementsov@virtuozzo.com> X-Mailer: git-send-email 2.11.1 In-Reply-To: <20180206140722.10110-1-vsementsov@virtuozzo.com> References: <20180206140722.10110-1-vsementsov@virtuozzo.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-Received-From: 195.214.232.40 Subject: [Qemu-devel] [PATCH 2/2] qapi: add block latency histogram interface X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, vsementsov@virtuozzo.com, armbru@redhat.com, mreitz@redhat.com, nshirokovskiy@virtuozzo.com, den@openvz.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Set (and clear) histogram through new command block-latency-histogram-set and show new statistics in query-blockstats results. Signed-off-by: Vladimir Sementsov-Ogievskiy --- qapi/block-core.json | 62 ++++++++++++++++++++++++++++++++++++++++++++++++= +++- block/qapi.c | 31 ++++++++++++++++++++++++++ blockdev.c | 15 +++++++++++++ 3 files changed, 107 insertions(+), 1 deletion(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index 8225308904..4706a934d9 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -451,6 +451,63 @@ 'status': 'DirtyBitmapStatus'} } =20 ## +# @BlockLatencyHistogramInfo: +# +# Block latency histogram. +# +# @latency: list of latency points in microseconds. Equals to @latency par= ameter +# of last called block-latency-histogram-set. +# +# @read: list of read-request counts corresponding to latency region. +# len(@read) =3D len(@latency) + 1 +# @read[0] corresponds to latency region [0, @latency[0]) +# for 0 < i < len(@latency): @read[i] corresponds to latency region +# [@latency[i-1], @latency[i]) +# @read.last_element corresponds to latency region +# [@latency.last_element, +inf) +# +# @write: list of write-request counts (see @read semantics) +# +# @flush: list of flush-request counts (see @read semantics) +# +# Since: 2.12 +## +{ 'struct': 'BlockLatencyHistogramInfo', + 'data': {'latency': ['uint64'], + 'read': ['uint64'], + 'write': ['uint64'], + 'flush': ['uint64'] } } + +## +# @block-latency-histogram-set: +# +# Add latency histogram to block device. If latency histogram alredy exist= s for +# the device it will be removed and a new one created. Latency histogram m= ay be +# quered through query-blockstats. +# +# @device: device name to set latency histogram for. +# +# @latency: list of latency points in microseconds. The sequcence must be +# ascending, elements must be greater than zero. Histogram laten= cy +# regions would be +# [0, @latency[0]), ..., [@latency[i], @latency[i+1]), ..., +# [@latency.last_element, +inf) +# +# Returns: error if device is not found. +# +# Since: 2.12 +# +# Example: +# +# -> { "execute": "block-latency-histogram-set", +# "arguments": { "device": "drive0", +# "latency": [500000, 1000000, 2000000] } } +# <- { "return": {} } +## +{ 'command': 'block-latency-histogram-set', + 'data': {'device': 'str', 'latency': ['uint64'] } } + +## # @BlockInfo: # # Block device information. This structure describes a virtual device and @@ -730,6 +787,8 @@ # @timed_stats: Statistics specific to the set of previously defined # intervals of time (Since 2.5) # +# @latency-histogram: @BlockLatencyHistogramInfo. (Since 2.12) +# # Since: 0.14.0 ## { 'struct': 'BlockDeviceStats', @@ -742,7 +801,8 @@ 'failed_flush_operations': 'int', 'invalid_rd_operations': 'int= ', 'invalid_wr_operations': 'int', 'invalid_flush_operations': 'in= t', 'account_invalid': 'bool', 'account_failed': 'bool', - 'timed_stats': ['BlockDeviceTimedStats'] } } + 'timed_stats': ['BlockDeviceTimedStats'], + '*latency-histogram': 'BlockLatencyHistogramInfo' } } =20 ## # @BlockStats: diff --git a/block/qapi.c b/block/qapi.c index fc10f0a565..715ed17a6b 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -389,6 +389,24 @@ static void bdrv_query_info(BlockBackend *blk, BlockIn= fo **p_info, qapi_free_BlockInfo(info); } =20 +static uint64List *uint64_list(uint64_t *list, int size) +{ + int i; + uint64List *out_list =3D NULL; + uint64List **pout_list =3D &out_list; + + for (i =3D 0; i < size; i++) { + uint64List *entry =3D g_new(uint64List, 1); + entry->value =3D list[i]; + *pout_list =3D entry; + pout_list =3D &entry->next; + } + + *pout_list =3D NULL; + + return out_list; +} + static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk) { BlockAcctStats *stats =3D blk_get_stats(blk); @@ -454,6 +472,19 @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds,= BlockBackend *blk) dev_stats->avg_wr_queue_depth =3D block_acct_queue_depth(ts, BLOCK_ACCT_WRITE); } + + ds->has_latency_histogram =3D stats->latency_histogram.points !=3D NUL= L; + if (ds->has_latency_histogram) { + BlockLatencyHistogramInfo *info =3D g_new0(BlockLatencyHistogramIn= fo, 1); + BlockLatencyHistogram *h =3D &stats->latency_histogram; + + ds->latency_histogram =3D info; + + info->latency =3D uint64_list(h->points, h->size - 1); + info->read =3D uint64_list(h->histogram[BLOCK_ACCT_READ], h->size); + info->write =3D uint64_list(h->histogram[BLOCK_ACCT_WRITE], h->siz= e); + info->flush =3D uint64_list(h->histogram[BLOCK_ACCT_FLUSH], h->siz= e); + } } =20 static BlockStats *bdrv_query_bds_stats(BlockDriverState *bs, diff --git a/blockdev.c b/blockdev.c index 8e977eef11..dbf17aca0c 100644 --- a/blockdev.c +++ b/blockdev.c @@ -4176,6 +4176,21 @@ void qmp_x_blockdev_set_iothread(const char *node_na= me, StrOrNull *iothread, aio_context_release(old_context); } =20 +void qmp_block_latency_histogram_set(const char *device, uint64List *laten= cy, + Error **errp) +{ + BlockBackend *blk =3D blk_by_name(device); + if (!blk) { + error_setg(errp, "Device '%s' not found", device); + return; + } + + if (block_latency_histogram_set(blk_get_stats(blk), latency) < 0) { + error_setg(errp, "Invalid latency array"); + return; + } +} + QemuOptsList qemu_common_drive_opts =3D { .name =3D "drive", .head =3D QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head), --=20 2.11.1