
How Swift could potentially be faster than Objective-C - mnem
https://www.mikeash.com/pyblog/friday-qa-2014-07-04-secrets-of-swifts-speed.html
======
mpweiher
Very potentially.

The things that can be "faster" are typically not the bottlenecks in
Objective-C programs, as the fine article rightly mentions in passing.

On the other hand, a lot of the really slow parts of recent Objective-C
"enhancements" are now mandatory in Swift, for example the Automatic Reference
Counting (ARC) support, which is actually a big part of the 100x and more
slowdowns.

Another issue is that you have copying semantics by default. The claim is that
this can make things faster, but for common objects like arrays and
dictionaries it first makes things a _lot_ slower (once they fix the
completely borked array semantics).

In all of these cases, you have very slow defaults that you must trust the
compiler to make fast again. The claim is that the semantics make it easier
for the compiler to optimize. This is true, but so far practical experience
appears to be that these two don't balance, that is the compilers don't get
enough extra information for optimization to compensate for the loss in
performance you get from the semantics being expensive by default.

Except in well-chosen benchmarks.

In fact, even in FP languages that have much tighter semantics and therefore
much better opportunities for the "sufficiently smart" compiler to do its
magic, you tend to see people dropping down to nasty imperative code
(effectively C in all but name) to get decent performance.

Swift's semantics are less tight, so I think it's going to depend even more on
the programmer writing fast, imperative code, "C in all but name". Again,
there are a few things that help the _compiler_ here, but again I doubt they
will generally be able to compensate.

I think the biggest issue with Swift performance is that it is focused on
helping the _compiler_ , rather than the _programmer_. The performance model
is, at least so far, highly non-linear and non-intuitive. This will hopefully
get better, but the semantics I've touched on make it difficult, they are
inherently highly non-linear and inherently difficult to predict.

~~~
mikeash
When you say 100x slowdowns with ARC, are you talking about Swift or
Objective-C? If the latter, do you have a concrete example of that happening?
My experience has been that ARC is typically negligible, worst case a
relatively small factor, and can be quite a bit faster due to things like
autorelease elision if you hit the right situation.

As for "very slow defaults that you must trust the compiler to make fast
again", that applies to just about every language that wants to be fast at
all. C compilers generate awful code when the optimizer is turned off.

~~~
mpweiher
For the 100x slowdowns, I am talking about Swift, though if you want to see a
20x slowdown in Objective-C, look here:
[http://blog.metaobject.com/2014/06/compiler-writers-gone-
wil...](http://blog.metaobject.com/2014/06/compiler-writers-gone-wild-arc-
madness.html)

Yes, the optimizer can take care of it some times, most of the time, ..., but
phew!

While C compilers also generate pretty bad code when optimizations are off,
it's nothing near this staggeringly awful. Unless you manage to write a
longish loop that it can figure out, which is unlikely outside of benchmarks,
my experience is you get around 2x or so for straight-line code that's pretty
rare these days. This is 20x to 100x and more.

The 2x roughly matches Probsting's Law[1], which says that advances in
compiler optimizer tech. double performance every 18 years. That's not a lot,
and does not justify trusting the compiler this much. In short, making the
semantics slow and trusting the sufficiently smart compiler [2] to fix it has
_never_ worked in the past, and I don't see any evidence why this time should
be different.

[1]
[http://www.cs.virginia.edu/~techrep/CS-2001-12.pdf](http://www.cs.virginia.edu/~techrep/CS-2001-12.pdf)

[2]
[http://c2.com/cgi/wiki?SufficientlySmartCompiler](http://c2.com/cgi/wiki?SufficientlySmartCompiler)

~~~
mikeash
Are you measuring a 20x slowdown with optimizations turned off? That's the
only way I can reproduce your results. That's a completely meaningless
comparison if so.

~~~
mpweiher
Well, no, it's not meaningless in the context of TFA:

[http://blog.metaobject.com/2014/06/compiler-writers-gone-
wil...](http://blog.metaobject.com/2014/06/compiler-writers-gone-wild-arc-
madness.html)

------
thegeomaster
This is basically the speed advantages of C++ applied to Swift, a more
powerful language. C++ also uses vtables and compilers often inline calls to
methods if the method/type can be determined at compile time.

The argument as to why it can be faster than plain C is very weak, though. It
says that if C programmers don't use the restrict keyword, equivalent Swift
code can be faster. This is right, but ignores the fact that careful and
competent C programmers _will_ put restrict in all the places where
performance matters. It's very hard to be faster than plain C, because it has
a long, long history, and as a result, the compilers have been steadily
improving for a long time. It is also less powerful allowing you to be closer
to the actual assembly code that is to be generated.

But with increasingly better hardware, the speed gains of plain C are
diminishing. Yes, you can be very fast, but is it worth the trouble of
expressing yourself in such a low-level language?

Also, since you can't type-pun (alias) in Swift, you can't do some things that
can be done using plain C, so it is unclear how it can be faster.

~~~
stephencanon
> Also, since you can't type-pun (alias) in Swift, you can't do some things
> that can be done using plain C, so it is unclear how it can be faster.

Type-punning is never necessary in C; it can always be replaced with one or
more calls to memcpy( ), which the compiler can elide (clang, at least, is
quite good at this optimization). I don't see any reason why this approach
wouldn't work with Swift.

~~~
pcwalton
LLVM isn't as good at memcpy optimization as you might think. The
MemCpyOptimizer pass isn't ordered very well in the pipeline and can't make
use of the SSA infrastructure that the rest of LLVM uses.

Source: I'm fighting this right now in rustc and plan to fix it by just making
the frontend emit fewer memcpys.

~~~
stephencanon
It's been a few years since I've seen clang/llvm fail to elide a memcpy used
in place of type punning (it's an idiom that I use very frequently as a
library writer, and care a lot about). If you have examples of cases where
llvm fails to do this optimization, _please_ file a bug report and I will be
delighted to lean on the right folks to get it fixed. You shouldn't need to
work around it.

------
joliv
A very relevant article:
[http://c2.com/cgi/wiki?AsFastAsCee](http://c2.com/cgi/wiki?AsFastAsCee)

------
clayallsopp
Interestingly, Swift (as of now) can be orders of magnitude slower than
C/Objective-C: [http://stackoverflow.com/questions/24101718/swift-
performanc...](http://stackoverflow.com/questions/24101718/swift-performance-
sorting-arrays)

I hope/expect the out-of-box performance will improve over time, but I guess
it shouldn't be taken as fact that Swift will always be faster than its
predecessor.

------
tedchs
Nice reinforcement of "performance tricks" almost always equaling "get the
computer to avoid doing extra unneeded work that it used to be programmed to
do".

------
moomin
To be honest, right now _Haskell 's_ looking like a higher performance
language than Swift.

~~~
xooyoozoo
Because of actual semantic analysis or some microbenchmark you saw somewhere
running on a beta, unstable compiler?

------
personZ
_and even claimed to be faster than C for certain cases_

-a promise made for pretty much every language ever. Just need a couple of compiler tune ups. Not trying to be critical, that just gave me a chuckle.

 _On most architectures (including x86-64, ARM, and ARM64), the first few
parameters to a function are passed in registers_

To add to this, the Microsoft 64 calling convention is that the first four
integer parameters (which includes pointers), and the first four floating
point values, are passed in registers. The System V AMD64 ABI (used by Linux
and others) passes the first 6 integer and the first 6 floating point
parameters in registers.

ARMv8 convention is that the first 8 integer/pointer values, and the first 8
floating point values (so up to 16 values) are passed via registers.

This isn't all win, of course -- if your code was using those registers, to
hold local variables for instance, it needs to save and restore them, or
simply avoid them. In most cases it would be the latter given the abundance of
registers.

The whole aliasing bit was just weird and detracts from the piece. Anyone who
is doing pointer-based-operations in base C is using restrict as appropriate.

~~~
pjmlp
>and even claimed to be faster than C for certain cases -a promise made for
pretty much every language ever. Just need a couple of compiler tune ups. Not
trying to be critical, that just gave me a chuckle.

I remember the days when C was just yet another systems programming language
deemed too slow for any serious work.

EDIT: Always nice to be downvoted by hipsters that lack coding experience from
the days C was UNIX only.

~~~
csl
> I remember the days when C was just yet another systems programming language
> deemed too slow for any serious work.

I've heard that remark several times. Which languages were faster than C back
then, except assembly? Fortran? Algol? BCPL?

~~~
pjmlp
Assembly of course. All higher level languages were still 2nd place to
Assembly and had similar execution times across the board.

------
chton
These aren't exactly secrets, are they? Vtables and similar optimizations have
been used in Java and .Net compilers for a long time. For a good explanation
in C# you can read [http://netmatze.wordpress.com/2013/04/06/dynamic-dispatch-
in...](http://netmatze.wordpress.com/2013/04/06/dynamic-dispatch-in-c/)

~~~
mikeash
Well no, they're certainly not actual secrets. I used the word for two
reasons: first, to convey that which mechanisms are actually used in Swift
aren't well known yet, and secondly and much more importantly, to make the
title alliterative.

~~~
chton
Alliteration is always a good reason :) I shouldn't have been so short with
you. I've just seen one to many articles where Swift is made to be seen as
Apple's godly gift to software development, without any references to similar
languages. Not that yours is that ofcourse, it just triggered that frustration
a bit :)

~~~
mikeash
I understand and share your frustration. This article is my attempt to counter
the "Swift is super fast because rainbows and unicorns" attitude floating
around.

~~~
chton
A knight for the good cause, then :)

~~~
mikeash
And for the record, I didn't see your comment as "short". You explained some
good context, and I just thought I'd explain my word choice in turn,
especially since I could joke about it.

~~~
chton
Record noted. Now I find it unfortunate that the title here was changed, we
went through all this text for nothing :)

~~~
mikeash
Hey, the original title is still on my blog, still counts!

------
CountHackulus
So it's not really the secrets of Swift's speed, it's more like not doing what
made Objective-C slow.

~~~
gress
Objective-C isn't slow. It's a strict superset of C, so anything that C can do
fast, Objective-C can do just as fast. If you say Objective-C is slow, you are
also saying C is slow.

Objective-C provides a message passing mechanism that trades speed for
convenience. It turns out that programmers often choose convenience over speed
because of time pressure.

~~~
erichocean
Going further, writing just C code to replicate what the Objective-C runtime
actually does (dynamic dispatch) is also slower than Objective-C and it's
hand-tuned, written-in-assembler runtime at those same tasks.

So, Objective-C (at least on Apple's operating systems) is as fast as C AND
faster than C at a few highly specific things.

