Overcoming Swift Resistance Explored

This post is a response to David Owens' Swift Resistance Explored post.

First I want to acknowledge that Swift Debug builds are hideously slow. This isn't news to me or anyone who has seen my talk on Swift optimisation. To be clear this is a problem which Apple have said that they are working on but I still don't think it is an absolute block on any real development because there are fairly simple workarounds.

If you want to see the code under discussion it is all in my repository here with a log of my development. The first commit is the Zipfile that David made available in his blog post, the rest is my testing and development of the Swift version.

These are my performance figures (for 100 runs so it isn't directly comparable to David's):


Obj-C

Swift

Optimised

0.077 (1.8)

0.042 (1)

Debug

0.38 (9.1)

13.7939 (327)

Optimised Performance

I don't know if it is computer differences, if David hasn't tried the code I sent him last night or if one of us is doing it wrong but we are currently in straight disagreement about which is faster in an optimised build, Swift in -O or Objective-C in -Os.

On my computer the Objective C version takes 80% longer than the Swift version. In his post David says "it’s still twice as slow as the ObjC version in RELEASE mode." which is essentially the opposite result to the one I get.

Debug Performance

Yes this is hideous in Swift. In the test Objective-C's debug (-O0) builds were nine times slower than the optimised Swift and the debug Swift (-O) build was 327 times slower than the optimised Swift (36 times slower than the debug Objective-C). As I mentioned above factors of over a hundred are no surprise to me but it is something that can deal with for now and Apple have said that they are working on it.

Where I would dispute with David is his view that this is an absolute showstopper than cripple's Swift's usefulness. There are ways to manage without the debugger, it still works with the assembly if needed anyway and as I illustrate there are workarounds for the issue.

Workaround - Framework the bottlenecks

However in the repo I show the workaround of moving performance critical code to a library or framework that can be built optimised while the bulk of the complexity and logic in the project is run without optimisation for simplicity of debugging. You can even set up a separate monolithic target for the release when you can afford a long build time and do not need to debug the result having already set everything up and tested it.

Using this for this test results in the same performance figures as the optimised build but it is really cheating as the critical code is optimised and there isn't much more code under test. [Update: And the same approach is obviously possible in Objective-C too.]

This approach is useful not just for performance critical issues but if your project grows big enough that the Swift builds are taking too long you can break it into frameworks so only frameworks with changed files are rebuilt

I am getting runtime warnings like this at the moment if anyone has any suggestions I would be grateful [See comment from Pierre Lebeaupin, seems an issue with Swift commandline applications at the moment]:

Summary of Disagreements

  1. Which is faster in Optimised builds.
  2. How important Swift's hideously slow unoptimised code is.

We also definitely differ on our prioritisation between optimised and unoptimised (debug) performance but that is just a matter of what we are working on at the moment and where a whole range of different views are completely valid and useful.




3 responses
I am getting runtime warnings like this at the moment if anyone has any suggestions I would be grateful: As far as I can tell, it's because you have the "Embedded Content Contains Swift Code" set to "yes" in the PerformanceCritical framework target, which you're only supposed to set on app targets according to https://developer.apple.com/library/ios/qa/qa18... …except that when I set it to "no", it no longer runs. Ah, apparently for command-line tool targets the Swift support gets statically linked, which means code from the dynamic library can't get at it, and I can't find any way to include Swift support in the dynamic library so that only the dynamic lib can see it. So my conclusion (given that Swift in static libraries does not seem to be supported at the moment, either) is that command-line tools cannot have a library dependency that includes Swift code. That sucks.
Thanks for that. Useful to know it is just an issue developing command line applications rather than general.
Not sure if it's just the command line. I'm having a very similar problem right now compiling from Xcode.