6 ms·
The article discusses two Swift versions of the same program, one that uses UnsafeMutablePointer (which is basically direct C-style memory access), and one that
by austinz 12y ago
The article discusses two Swift versions of the same program, one that uses UnsafeMutablePointer (which is basically direct C-style memory access), and one that uses Swift's built-in Array type. The former runs well, the latter is slow.
If you look at the Objective-C code, BackingBuffer is a C struct containing a C array of Pixels (themselves each a 32-bit C struct).
The problem is that the best analogy to Swift's Array type is not the C array in Objective-C - it's the Foundation class NSArray. For the given use case, most Objective-C developers would eschew NSArrays and classes serving as data bags in favor of fixed-length C arrays containing C structs. C arrays don't perform bounds checking, they require you to manually decide when to allocate, copy, and free the backing memory, they require you to know how much space each piece of data requires and work with the data accordingly, and so forth.
The fact that NSArrays can't hold value types, only references to classes, complicates things a bit, but I doubt the Objective-C code would be anywhere as fast if the backing store was an NSArray holding NSValues or something similar. Comparing the Swift implementation using Arrays to the Objective-C implementation using C arrays is not really fair.
- mpweiher 12y agoSo what should he use instead?
- austinz 12y ago> UnsafeMutablePointer (which is basically direct C-style memory access)
- kybernetyk 12y agoUnsafeMutablePointer<UInt8> Which he somehow dismisses but is the corresponding thing to an unsafe C array. I'm not a big fan of Swift but this rant is rather unfounded. Sometimes you have to give up high level abstraction for performance. In Obj-C he was willing to do so by using an C array. In Swift on the other hand he insists on using the high level array implementation.
- lerno 12y agoWe've essentially been told to use Swift arrays as we would C arrays, so your analogy is flawed. Another premise for Swift is that it should be usable for low level, high performance programming but "safer than C". This is something we don't see in practice. Furthermore, using UnsafeMutablePointers in Swift makes the program a magnitude larger than the corresponding C program, with no additional gain in perf, readability or safety. It is a last resort, not something you should use all of the time. Consequently I find it hard to agree with you.
- jlarocco 12y agoIt's odd that you said "We've essentially been told ...". Will Apple reject apps using C arrays or something? In any case, I don't really see the problem here. Every feature of every language has some kind of performance trade off. And it's natural to expect higher level abstractions in higher level languages will have some amount of performance overhead versus lower level abstractions. In this case, there's no shortage of alternatives, so pick one and get on with it. If it ends up being too slow, go back and look at the alternatives and swap out Swift arrays for C arrays or NSArray or whatever.
- lerno 12y agoNo, but we have been told that the performance characteristics of the native Swift array should be the same as an array in C. Judging from what the compiler team at Apple regularly write in forums and on twitter, it seems that they consider the performance issues for arrays (actually, this happens in other circumstances as well) to be a very real issue. When you say "swap for a C array", then I suppose that you mean we allocate a chunk of memory like in C, then access it using unsafe methods (as there is no "C array" in Swift). Unfortunately, working with UnsafeMutablePointer and friends is extremely verbose and clumsy, which makes it an extremely bad experience.
- Glide 12y agoIsn't there toll free bridging between a Swift Array and an NSArray? It would make a lot of sense for the performance characteristics of the two being the same if that were the case. Yeah and swapping to a C array isn't that simple in Swift. It seems easier to just have objective c code and call that from Swift when needed.
- mikeash 12y agoI disagree. Swift arrays are analogous to both NSArray and C arrays. If they're so extremely slow then I'd consider that a bug in the compiler to hopefully be fixed as Apple improves things. There's no reason this code should be this slow. The fact that NSArrays can't hold value types doesn't complicate things "a bit," it destroys the analogy entirely. Swift arrays can hold a bunch of references, like NSArray, or it can hold a contiguous chunk of values, like C arrays. The second option may be slow in some circumstances now, but there's no fundamental reason it has to be.
- austinz 12y agoThe code isn't quite as terrible if compiled with optimizations on. I like your hypothesis elsewhere in the thread, that the optimization pass is probably removing unneeded array copying that hinder the performance of the debug build. Semantically, an Array is an automatically resizing, reference-counted, copy-on-write, bounds-checking sequence of elements, none of which I want if I'm building a buffer for pixel values. So there is a significant mismatch between my desired use case and the characteristics of Array. I really do think there should be a fixed-size non-copy-on-write collection type at some point added to the language. From an operational perspective, you're right, the analogy is quite leaky if you examine it closely.
- mikeash 12y agoNote that automatic resizing and reference counting won't hurt you in these cases. Bounds checking can, but eliminating bounds checks by proving that your accesses are always in-bounds at compile time is old hat by this point. Copy-on-write semantics are trickier to make fast, which is why I'm guessing they're the root cause here.