3 ms·
From what I've seen the ref counting can cause a big performance hit. Maybe this has improved in the last couple years?
by kevingadd 3y ago
From what I've seen the ref counting can cause a big performance hit. Maybe this has improved in the last couple years?
- GeekyBear 3y ago> From what I've seen the ref counting can cause a big performance hit. Apple has been writing OS components in Swift for a while now. It certainly doesn't seem to be producing the performance issues we saw when Google attempted to write components for Fuchsia in Go or Microsoft's effort to create new features for Longhorn in .NET.
- comex 3y agoBut it's mostly replacing Objective-C code which was already not particularly fast – as opposed to the C++ or C code used more often in performance- or memory-sensitive areas. My experience with Swift is somewhat limited, because every time I've tried to use it, I've run into glaring performance issues and had to switch language. It might be reasonably performant compared to Go or .NET, but it's nothing like Rust.
- trinix912 3y agoWhat kind of stuff were you doing in Swift to notice performance issues? I've been developing macOS and iOS apps for a while now and it doesn't seem much slower than Objective-C.
- aatd86 3y agoWas probably due to FFI for Go I'd assume. Do you have a reference somewhere I can read up?
- GeekyBear 3y agoIt was discussed here when they decided their networking stack in Go would need to be rewritten for performance reasons, and banned the future use of Go for Fuchsia system components. https://news.ycombinator.com/item?id=22409838 https://news.ycombinator.com/item?id=22409838
- stevefan1999 3y agoReference counting is slow because it has an additional increment/decrement operator on each lifetime of a scope. Add a little bit of salt to insult you need it to be atomic if you want it to run on SMP. This means for each time you have create/release the lifetime of an object you will make a lot of memory barriers, and create a lot of cache contention. But in practice the overhead is actually nought, and most of the time you rather deal with I/O bound problem more than an additional atomic increment operation. Modern processor is fast enough to deal with them in few cycles in around the order of 10 nanoseconds
- olliej 3y agoSwift's refcounting is atomic (as is objc's). As long as you're not under contention most benchmarks I've seen show negligible overhead (from the addition of atomicity, the refcount overhead is still there) for uncontended access. But IME if you do have many threads walking the same data structure you end up spending stupid amounts of time fighting the refcounting. This applies even if the data structure is immutable and has guaranteed lifetime as swift's type system doesn't seem to allow that to be expressed, and as a result it seems to do a lot of ref churn we'd consider unnecessary.
- plorkyeran 3y agoIME Swift’s refcounting is either incredibly inconsequential or a dealbreaker, with very little in between. They’ve done a very good job of optimizing it to the point where it’s barely measurable even in perf sensitive code… until you hit the scenarios where it completely murders performance and there’s nothing you can do about it. Hopefully the upcoming ownership functional will help in those cases.
- Someone 3y ago> Swift's refcounting is atomic (as is objc's) Most of the time it’s possible to avoid atomic instructions and still be thread-safe. https://dl.acm.org/doi/10.1145/3243176.3243195 https://dl.acm.org/doi/10.1145/3243176.3243195: “BRC is based on the observation that most objects are only accessed by a single thread, which allows most RC operations to be performed non-atomically. BRC leverages this by biasing each object towards a specific thread, and keeping two counters for each object --- one updated by the owner thread and another updated by the other threads. This allows the owner thread to perform RC operations non-atomically, while the other threads update the second counter atomically. We implement BRC in the Swift programming language runtime, and evaluate it with client and server programs. We find that BRC makes each RC operation more than twice faster in the common case. As a result, BRC reduces the average execution time of client programs by 22.5%, and boosts the average throughput of server programs by 7.3%.” I remember reading that this made it into Swift, but cannot find it, so I’m not sure anymore. And of course, the Swift compiler tries to avoid unnecessary refcount updates.
- dralley 3y agoApple has always been preferential to reference counting (see Objective C) and it seems like they may have spent a fair bit of effort optimizing Apple Silicon for it.
- GeekyBear 3y ago> it seems like they may have spent a fair bit of effort optimizing Apple Silicon for it According to information released when the M1 came out: retaining and releasing an NSObject takes ~30 nanoseconds on current gen Intel, and ~6.5 nanoseconds on an M1
- fulafel 3y agoIt's good to reduce the cache hot best case time of course but isnt the more fundamental sin of RC in the extra read/write memory traffic, cache footprint and cross core cache line ping pong when incrementing object refcount fields. (or if going with BRC, correspondingly there shouldn't be a advantages for this custom CPU feature)
- pjmlp 3y agoReference counting on Objective-C was plan B, after the failure of implementing a safe tracing GC in a language with C's semantics. So they went with plan B, having the compiler automate the retain/release messages used by the Cocoa framework. Everywhere else in Objective-C, the memory is still manually managed, or via memory pools.