From: Kevin Wolf <kwolf@redhat.com>
To: qemu-block@nongnu.org
Cc: kwolf@redhat.com, qemu-devel@nongnu.org
Subject: [PULL 04/14] block: change reqs_lock to QemuMutex
Date: Mon, 4 Sep 2023 16:36:33 +0200 [thread overview]
Message-ID: <20230904143643.259916-5-kwolf@redhat.com> (raw)
In-Reply-To: <20230904143643.259916-1-kwolf@redhat.com>
From: Stefan Hajnoczi <stefanha@redhat.com>
CoMutex has poor performance when lock contention is high. The tracked
requests list is accessed frequently and performance suffers in QEMU
multi-queue block layer scenarios.
It is not necessary to use CoMutex for the requests lock. The lock is
always released across coroutine yield operations. It is held for
relatively short periods of time and it is not beneficial to yield when
the lock is held by another coroutine.
Change the lock type from CoMutex to QemuMutex to improve multi-queue
block layer performance. fio randread bs=4k iodepth=64 with 4 IOThreads
handling a virtio-blk device with 8 virtqueues improves from 254k to
517k IOPS (+203%). Full benchmark results and configuration details are
available here:
https://gitlab.com/stefanha/virt-playbooks/-/commit/980c40845d540e3669add1528739503c2e817b57
In the future we may wish to introduce thread-local tracked requests
lists to avoid lock contention completely. That would be much more
involved though.
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-ID: <20230808155852.2745350-3-stefanha@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
include/block/block_int-common.h | 2 +-
block.c | 4 +++-
block/io.c | 24 ++++++++++++------------
3 files changed, 16 insertions(+), 14 deletions(-)
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
index 74195c3004..7a1e678031 100644
--- a/include/block/block_int-common.h
+++ b/include/block/block_int-common.h
@@ -1231,7 +1231,7 @@ struct BlockDriverState {
unsigned int write_gen; /* Current data generation */
/* Protected by reqs_lock. */
- CoMutex reqs_lock;
+ QemuMutex reqs_lock;
QLIST_HEAD(, BdrvTrackedRequest) tracked_requests;
CoQueue flush_queue; /* Serializing flush queue */
bool active_flush_req; /* Flush request in flight? */
diff --git a/block.c b/block.c
index 0af890f647..b79b1ce7fe 100644
--- a/block.c
+++ b/block.c
@@ -415,7 +415,7 @@ BlockDriverState *bdrv_new(void)
for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
QLIST_INIT(&bs->op_blockers[i]);
}
- qemu_co_mutex_init(&bs->reqs_lock);
+ qemu_mutex_init(&bs->reqs_lock);
qemu_mutex_init(&bs->dirty_bitmap_mutex);
bs->refcnt = 1;
bs->aio_context = qemu_get_aio_context();
@@ -5476,6 +5476,8 @@ static void bdrv_delete(BlockDriverState *bs)
bdrv_close(bs);
+ qemu_mutex_destroy(&bs->reqs_lock);
+
g_free(bs);
}
diff --git a/block/io.c b/block/io.c
index 4f32d6aa6e..525c94b16a 100644
--- a/block/io.c
+++ b/block/io.c
@@ -591,9 +591,9 @@ static void coroutine_fn tracked_request_end(BdrvTrackedRequest *req)
qatomic_dec(&req->bs->serialising_in_flight);
}
- qemu_co_mutex_lock(&req->bs->reqs_lock);
+ qemu_mutex_lock(&req->bs->reqs_lock);
QLIST_REMOVE(req, list);
- qemu_co_mutex_unlock(&req->bs->reqs_lock);
+ qemu_mutex_unlock(&req->bs->reqs_lock);
/*
* At this point qemu_co_queue_wait(&req->wait_queue, ...) won't be called
@@ -627,9 +627,9 @@ static void coroutine_fn tracked_request_begin(BdrvTrackedRequest *req,
qemu_co_queue_init(&req->wait_queue);
- qemu_co_mutex_lock(&bs->reqs_lock);
+ qemu_mutex_lock(&bs->reqs_lock);
QLIST_INSERT_HEAD(&bs->tracked_requests, req, list);
- qemu_co_mutex_unlock(&bs->reqs_lock);
+ qemu_mutex_unlock(&bs->reqs_lock);
}
static bool tracked_request_overlaps(BdrvTrackedRequest *req,
@@ -793,9 +793,9 @@ bdrv_wait_serialising_requests(BdrvTrackedRequest *self)
return;
}
- qemu_co_mutex_lock(&bs->reqs_lock);
+ qemu_mutex_lock(&bs->reqs_lock);
bdrv_wait_serialising_requests_locked(self);
- qemu_co_mutex_unlock(&bs->reqs_lock);
+ qemu_mutex_unlock(&bs->reqs_lock);
}
void coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req,
@@ -803,12 +803,12 @@ void coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req,
{
IO_CODE();
- qemu_co_mutex_lock(&req->bs->reqs_lock);
+ qemu_mutex_lock(&req->bs->reqs_lock);
tracked_request_set_serialising(req, align);
bdrv_wait_serialising_requests_locked(req);
- qemu_co_mutex_unlock(&req->bs->reqs_lock);
+ qemu_mutex_unlock(&req->bs->reqs_lock);
}
int bdrv_check_qiov_request(int64_t offset, int64_t bytes,
@@ -3002,7 +3002,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
goto early_exit;
}
- qemu_co_mutex_lock(&bs->reqs_lock);
+ qemu_mutex_lock(&bs->reqs_lock);
current_gen = qatomic_read(&bs->write_gen);
/* Wait until any previous flushes are completed */
@@ -3012,7 +3012,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
/* Flushes reach this point in nondecreasing current_gen order. */
bs->active_flush_req = true;
- qemu_co_mutex_unlock(&bs->reqs_lock);
+ qemu_mutex_unlock(&bs->reqs_lock);
/* Write back all layers by calling one driver function */
if (bs->drv->bdrv_co_flush) {
@@ -3100,11 +3100,11 @@ out:
bs->flushed_gen = current_gen;
}
- qemu_co_mutex_lock(&bs->reqs_lock);
+ qemu_mutex_lock(&bs->reqs_lock);
bs->active_flush_req = false;
/* Return value is ignored - it's ok if wait queue is empty */
qemu_co_queue_next(&bs->flush_queue);
- qemu_co_mutex_unlock(&bs->reqs_lock);
+ qemu_mutex_unlock(&bs->reqs_lock);
early_exit:
bdrv_dec_in_flight(bs);
--
2.41.0
next prev parent reply other threads:[~2023-09-04 14:38 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-09-04 14:36 [PULL 00/14] Block layer patches Kevin Wolf
2023-09-04 14:36 ` [PULL 01/14] block/vpc: Avoid dynamic stack allocation Kevin Wolf
2023-09-04 14:36 ` [PULL 02/14] iotests: adapt test output for new qemu_cleanup() behavior Kevin Wolf
2023-09-04 14:36 ` [PULL 03/14] block: minimize bs->reqs_lock section in tracked_request_end() Kevin Wolf
2023-09-04 14:36 ` Kevin Wolf [this message]
2023-09-04 14:36 ` [PULL 05/14] qemu-img: omit errno value in error message Kevin Wolf
2023-09-04 14:36 ` [PULL 06/14] block/iscsi: Document why we use raw malloc() Kevin Wolf
2023-09-04 14:36 ` [PULL 07/14] block: Be more verbose in create fallback Kevin Wolf
2023-09-04 14:36 ` [PULL 08/14] qemu-img: Update documentation for compressed images Kevin Wolf
2023-09-04 14:36 ` [PULL 09/14] vmdk: Clean up bdrv_open_child() return value check Kevin Wolf
2023-09-04 14:36 ` [PULL 10/14] block: remove AIOCBInfo->get_aio_context() Kevin Wolf
2023-09-04 14:36 ` [PULL 11/14] block-backend: process I/O in the current AioContext Kevin Wolf
2023-09-04 14:36 ` [PULL 12/14] block-backend: process zoned requests " Kevin Wolf
2023-09-04 14:36 ` [PULL 13/14] block: Remove bdrv_query_block_node_info Kevin Wolf
2023-09-04 14:36 ` [PULL 14/14] block: Remove unnecessary variable in bdrv_block_device_info Kevin Wolf
2023-09-06 15:13 ` [PULL 00/14] Block layer patches Stefan Hajnoczi
2023-09-07 8:17 ` Kevin Wolf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230904143643.259916-5-kwolf@redhat.com \
--to=kwolf@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).