From nobody Thu Dec 18 19:40:28 2025 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 1520607096769235.7757964951585; Fri, 9 Mar 2018 06:51:36 -0800 (PST) Received: from localhost ([::1]:45690 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1euJMu-0006fS-0B for importer@patchew.org; Fri, 09 Mar 2018 09:51:36 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:35858) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1euJKq-0005Gh-1y for qemu-devel@nongnu.org; Fri, 09 Mar 2018 09:49:29 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1euJKl-00081d-Qe for qemu-devel@nongnu.org; Fri, 09 Mar 2018 09:49:26 -0500 Received: from relay.sw.ru ([185.231.240.75]:39826) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1euJKl-00080y-I5; Fri, 09 Mar 2018 09:49:23 -0500 Received: from msk-vpn.virtuozzo.com ([195.214.232.6] helo=kvm.sw.ru) by relay.sw.ru with esmtp (Exim 4.89) (envelope-from ) id 1euJKh-0006KX-8t; Fri, 09 Mar 2018 17:49:19 +0300 From: Vladimir Sementsov-Ogievskiy To: qemu-devel@nongnu.org, qemu-block@nongnu.org Date: Fri, 9 Mar 2018 17:49:17 +0300 Message-Id: <20180309144918.44975-2-vsementsov@virtuozzo.com> X-Mailer: git-send-email 2.11.1 In-Reply-To: <20180309144918.44975-1-vsementsov@virtuozzo.com> References: <20180309144918.44975-1-vsementsov@virtuozzo.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-Received-From: 185.231.240.75 Subject: [Qemu-devel] [PATCH v3 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 | 34 +++++++++++++++++ block/accounting.c | 91 ++++++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 125 insertions(+) diff --git a/include/block/accounting.h b/include/block/accounting.h index b833d26d6c..ec3060ba7a 100644 --- a/include/block/accounting.h +++ b/include/block/accounting.h @@ -45,6 +45,36 @@ struct BlockAcctTimedStats { QSLIST_ENTRY(BlockAcctTimedStats) entries; }; =20 +typedef struct BlockLatencyHistogram { + /* The following histogram is represented like this: + * + * 5| * + * 4| * + * 3| * * + * 2| * * * + * 1| * * * * + * +------------------ + * 10 50 100 + * + * BlockLatencyHistogram histogram =3D { + * .nbins =3D 4, + * .boundaries =3D {10, 50, 100}, + * .bins =3D {3, 1, 5, 2}, + * }; + * + * @boundaries array define histogram intervals as follows: + * [0, boundaries[0]), [boundaries[0], boundaries[1]), ... + * [boundaries[nbins-2], +inf) + * + * So, for example above, histogram intervals are: + * [0, 10), [10, 50), [50, 100), [100, +inf) + */ + int nbins; + uint64_t *boundaries; /* @nbins-1 numbers here + (all boundaries, except 0 and +inf) */ + uint64_t *bins; +} BlockLatencyHistogram; + struct BlockAcctStats { QemuMutex lock; uint64_t nr_bytes[BLOCK_MAX_IOTYPE]; @@ -57,6 +87,7 @@ struct BlockAcctStats { QSLIST_HEAD(, BlockAcctTimedStats) intervals; bool account_invalid; bool account_failed; + BlockLatencyHistogram latency_histogram[BLOCK_MAX_IOTYPE]; }; =20 typedef struct BlockAcctCookie { @@ -82,5 +113,8 @@ void block_acct_merge_done(BlockAcctStats *stats, enum B= lockAcctType 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, enum BlockAcctType = type, + uint64List *boundaries); +void block_latency_histograms_clear(BlockAcctStats *stats); =20 #endif diff --git a/block/accounting.c b/block/accounting.c index 87ef5bbfaa..70a3d9a426 100644 --- a/block/accounting.c +++ b/block/accounting.c @@ -94,6 +94,94 @@ void block_acct_start(BlockAcctStats *stats, BlockAcctCo= okie *cookie, cookie->type =3D type; } =20 +/* 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 >=3D @it[1] + */ +static int block_latency_histogram_compare_func(const void *key, const voi= d *it) +{ + uint64_t k =3D *(uint64_t *)key; + uint64_t a =3D ((uint64_t *)it)[0]; + uint64_t b =3D ((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 =3D=3D NULL) { + /* histogram disabled */ + return; + } + + + if (latency_ns < hist->boundaries[0]) { + hist->bins[0]++; + return; + } + + if (latency_ns >=3D hist->boundaries[hist->nbins - 2]) { + hist->bins[hist->nbins - 1]++; + return; + } + + pos =3D bsearch(&latency_ns, hist->boundaries, hist->nbins - 2, + sizeof(hist->boundaries[0]), + block_latency_histogram_compare_func); + assert(pos !=3D NULL); + + hist->bins[pos - hist->boundaries + 1]++; +} + +int block_latency_histogram_set(BlockAcctStats *stats, enum BlockAcctType = type, + uint64List *boundaries) +{ + BlockLatencyHistogram *hist =3D &stats->latency_histogram[type]; + uint64List *entry; + uint64_t *ptr; + uint64_t prev =3D 0; + int new_nbins =3D 1; + + for (entry =3D boundaries; entry; entry =3D entry->next) { + if (entry->value <=3D prev) { + return -EINVAL; + } + new_nbins++; + prev =3D entry->value; + } + + hist->nbins =3D new_nbins; + g_free(hist->boundaries); + hist->boundaries =3D g_new(uint64_t, hist->nbins - 1); + for (entry =3D boundaries, ptr =3D hist->boundaries; entry; + entry =3D entry->next, ptr++) + { + *ptr =3D entry->value; + } + + g_free(hist->bins); + hist->bins =3D g_new0(uint64_t, hist->nbins); + + return 0; +} + +void block_latency_histograms_clear(BlockAcctStats *stats) +{ + int i; + + for (i =3D 0; i < BLOCK_MAX_IOTYPE; i++) { + BlockLatencyHistogram *hist =3D &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 *c= ookie, bool failed) { @@ -116,6 +204,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->type= ], + 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