4 ms·
Atomic reference counting is expensive mainly under contention, when the same object is used from multiple threads. Uncontended atomic operations are ~2-3x slow
by millstone 11y ago
Atomic reference counting is expensive mainly under contention, when the same object is used from multiple threads. Uncontended atomic operations are ~2-3x slower than their nonatomic analogs, which is still very fast.
Also I'd expect that GCs should experience a slowdown in the contention scenario, due to write barriers; is it so?
- cwzwarich 11y agoWhile uncontended atomic operations are a lot faster than contended ones, it's hard to avoid the contended case. If you pass a single piece of read-only data throughout your program you will be adjusting its reference count frequently, and those contended atomics will dominate your performance profile. In a concurrent card-marking write barrier you would generally set bytes rather than individual bits so that you can avoid the use of atomic instructions. You still have the problem of false sharing. If this were really a problem, you could emit a conditional write barrier that checks the existing value (with a racy unsynchronized load) before setting the byte. The usual use of a write barrier for generational GC will produce fewer stores than automatic reference counting anyways, because a write barrier is only emitted for potential stores of a reference to a younger generation in an older generation. Automatic reference counting requires reference count adjustments for function parameters and local variables.
- rbehrends 11y ago> Uncontended atomic operations are ~2-3x slower than their nonatomic analogs, which is still very fast. More like up to 20x slower; atomic reference counting has to hit the L3 cache at least. A quick benchmark seems to confirm that. Also, there are still some nasty corner cases with pointers that are shared between threads (because reading/writing a pointer and updating its associated reference count are not a single atomic operation). > Also I'd expect that GCs should experience a slowdown in the contention scenario, due to write barriers; is it so? Write barriers only come into play when pointers on the heap or in static memory are being modified. Reference counting means that you need to update the reference count whenever you assign references, even from one local variable to another (much of the work that Apple's done is to use compiler optimizations to get rid of those that are provably unnecessary). For example, having multiple threads traversing a tree in parallel can generate a lot of contention in the RC case, but none for a GC with a write barrier. Deferred reference counting is closer in performance to GC, but then you have to write most of the machinery of a tracing GC, too.