Friday, April 3, 2015

Testing Swift's performance against C/Objective-C


When Apple first announced Swift, they claimed dramatic speed improvements. 

I was skeptical. I'm an old assembler programmer. I know how to write code that runs fast. 

When I write code that's churning through large amounts of data, I tend to use C arrays and pointer math, rather than trying to use NSArrays. It seems obvious that the overhead of everything being an object and message passing is going to slow things down.

Thus, I suspected that Apple's claims that Swift is faster than Objective-C was based on naive code written in Objective-C, where everything is an object.

Several years ago I wrote a prime number generator as a teaching aid for my son, who was starting to get interested in programming. It's mostly in C, with some Objective-C wrappers for displaying information and such-like.

I decided to implement the same algorithm in Swift and see which is faster. This algorithm makes heavy use of arrays. It creates an array of known prime numbers, and tests each candidate number to see if it can be evenly divisible by existing known primes. If not, it gets added to the list of primes. It ends up doing millions of array accesses, and an array append for each new prime. 

I ended up with a test project that lets you run the same algorithm in either Swift or Objective-C, and use either array objects or memory buffers in either language. (Swift has a collection wrapper for memory buffers that gives you array syntax.)

You can download the project from Github and try it yourself. It's called 


The bottom line is this:

With the standard Debug settings, where optimizations are turned off, Swift performance is horrible. Code that takes a few seconds in Objective C takes minutes in Swift.  (6 min 7 sec for Swift vs about 9.2 sec for Objective-C). For array-intensive algorithms, Swift in debug mode is all but unusable.

All my tests therefore use release mode, with optimizations of "Fastest" (or fastest+unchecked; see below.)

C code beats out the fastest Swift code I could come up with, but the differences are modest. In Xcode 6.2, using Swift 1.1, the Swift version takes about 1.45 times longer than the Objective-C code using C arrays.

If you turn off array index range checking with a compiler switch the Swift code gets a little faster, and if you use the Xcode 6.3 beta, it gets a little faster still. In that case the Swift code (using memory buffers with an array interface)  is very close to Objective-C/C. Swift takes about 1.08 x times longer than my C/Objective-C code. That's awfully close. However, turning off array bounds checking is dangerous, and I don't know of a way to do that for only one array object. As far as I know this change is for the entire project. It's probably possible to do change compiler settings for a single source file, but I don't know how to do that off the top of my head.

Things are much different if you use the array classes in both languages.

In that case, Swift is faster than Objective-C, and by a lot. To generate 2 million primes, Swift takes about 7.35 seconds, down to about 5.9 seconds if you use Xcode 6.3 and use the compiler setting that turns off array bounds checking. Objective-C using NSArrays takes around 31 seconds to do the same job. Objective-C with NSArrays takes about 4.3 times longer than Swift using it's Array class.

So the bottom line is that if you're using Array objects in both languages, Swift is much faster. If you're writing optimized code to squeeze the fastest performance out of each, though, C/Objective-C still has a slight edge.

No comments: