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. Paolo
signature.asc
Description: OpenPGP digital signature