atomic read limiting

19 Dec 2020

Today I’m releasing capnproto-rust version 0.14. The main change is a new sync_reader feature that allows messages to be shared between multiple threads. With the new feature, you can, for example, wrap a capnp::message::Reader with lazy_static or once_cell and then read it from anywhere else in your program. Previously, doing so was not possible because the message traversal limit was tracked through a Cell, causing message::Reader to not be Sync. Now, when sync_reader is enabled, the traversal limit is tracked through an AtomicUsize, which can be safely shared between threads.

To minimize the performance impact, the new implementation uses Ordering::Relaxed when accessing the atomic counter. When I measured the performance on a few benchmarks, I was initially discouraged because fetch_sub() seemed to be slowing things down significantly. Fortunately, I found that splitting fetch_sub() into separate load() and store() steps recovered the lost time. (Such a split may cause the read limiter to undercount reads, but we are okay with that level of imprecision.) With the most recent version, I am unable to detect any speed difference between the new atomic implementation and the old Cell-based one.

I would have liked to unconditionally enable atomic read limiting, but unfortunately AtomicUsize is not available on all platforms. For example, rustc does not support any atomics on riscv32i-unknown-none-elf. (I am unsure whether that’s an inherent property of the platform, or whether it’s an implementation hole that could be filled in later.)

@appaquet deserves credit for submitting the pull request with this change and for patiently iterating on it with me.

-- posted by dwrensha

capnproto-rust on github
more posts