[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-block] [Qemu-devel] Block layer complexity: what to do to keep

From: Paolo Bonzini
Subject: Re: [Qemu-block] [Qemu-devel] Block layer complexity: what to do to keep it under control?
Date: Fri, 1 Dec 2017 18:03:24 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.4.0

Just my 2 cents on the language topic, as in general I agree completely
with Stefan.

On 01/12/2017 15:08, Stefan Hajnoczi wrote:
> Rust's threading model is 1:1.  Besides mutexes it also has channels
> (looks similar to Go and communicating sequential processes-style
> channels).
> It is probably not feasible to make each I/O request a thread (i.e. 1M
> IOPS means creating/destroying 1M threads/sec).  There would have to be
> some machinery like a request queue and a thread pool to process
> requests.  That way requests can be held before those that are ready to
> be executed can run as threads.  Hmm...this sounds similar to what we
> have.

Yes, we would probably use coroutines anyway even if using Rust
(wrapping them in a Rust library).

There could still be important gains in readability and type-safety, for
example if the type checker could guarantee that internal qcow2
functions are called with a lock taken.  I'm afraid however that this
would require much stronger Rust knowledge than we can acquire quickly,
and that we would end up with just as much technical debt (without even
realizing it).

Luckily, several benefits don't require a full rewrite or language switch:

- readability from RAII-style code.  If this is important enough, we
could actually use GCC __attribute__((cleanup)) or, heaven forbid,
slowly introduce C++ in QEMU's code base.

- compile-time checks.  For this we can also use clang's
-Wthread-safety.  (GCC doesn't have it yet).

- lack of templates/generics; for example commit 2bb5c936c5 ("curl: do
not do aio_poll when waiting for a free CURLState", 2017-05-16)
open-codes a "CoQueue that's protected by a QemuMutex rather than a
CoMutex"; templates would provide an elegant solution without code
duplication.  Generics could also be used to decouple abstract data
types from the block layer and to unit-test them easily (e.g.
Graph<BlockDriverState, BdrvChildRole>), but: 1) it may be just my very
limited knowledge of the BDS graph code; 2) we couldn't do this anyway
without first understanding the deficiencies of our C implementation
(for example with respect to missing bdrv_ref/unref).

In all cases, the lessons that we learn fixing the C code or slowly
including a little bit of C++ _could_ help with a later larger-scale switch.

> The important thing is this:
> Coroutines with a single event loop (current model in QEMU) are simpler
> than threads.  Why?  Because coroutine code is atomic with respect to
> other coroutines in the same event loop.  Only yield points or nested
> event loops allow other coroutines to execute.  That means less explicit
> synchronization is necessary.
> When the block layer goes multiqueue this advantage will be lost and
> coroutine code will have to synchronize explicitly just like threaded
> code.  Coroutines will remain lighter weight than threads and will allow
> M:N threading to be configured via IOThreads.
> I'm not hopeful that dropping coroutines helps and I don't see that Rust
> brings anything new to the table here.  I do like other aspects of Rust
> and am open to using it for new code.

Same here.  Just like fixing the C code provides a good foundation for a
language switch, some more battle-tested code could be converted from
QEMU to Rust, in order to get familiar with it and probe whether the
benefits are real.  Maybe the memory API could be a good candidate; it
certainly would benefit from generics.


Attachment: signature.asc
Description: OpenPGP digital signature

reply via email to

[Prev in Thread] Current Thread [Next in Thread]