

Swift Resistance Explored - mpweiher
http://owensd.io/2015/01/31/swift-resistance-explored.html

======
st3fan
I am also still exploring Swift, so forgive me if I got this wrong, but isn't
the problem here the following:

Your RenderGradient() takes a RenderBuffer struct. Structs are passed by
value. So two things happen in your RenderBuffer function:

1) You get a copy of the RenderBuffer, which means it and its contents (a lot
of Pixel instances - Arrays are passed by value too!) will be copied every
iteration

2) The work you do on the pixels in the RenderBuffer _copy_ has no effect: you
change the values of a copy and then ignore the copy. You don't return the
modified RenderBuffer it from RenderGradient() or do anything with the result
within RenderGradient().

So I think the reason you see such a big difference in this test between
optimization and no-optimization is that in the first case, with optimization,
the compiler knows that the work you do in RenderBuffer is a waste of time and
simply does not do it.

While in the debug build the compiler does not apply optimization so your
useless code is still executed.

You can confirm this by looking at the generated code. Or maybe simpler,
render the RenderBuffer in an actual buffer or image for a visual inspection.

~~~
owensd
Yes, the var should have been inout. It had an affect on the release build
performance (twice as fast), but not the debug build. I've updated the blog
post.

The performance problem is regarding all retain/releases though; not the copy
of the data. That's why the debug builds are not affected.

------
e28eta
I can understand the frustration. However I think it's a little premature to
cast aspersions on the whole language because it isn't good at this particular
test right now.

We still have ObjC. The two languages work together. (we also have C and asm).
Pick the right tool for the job, and have reasonable expectations about the
maturity and progress of Swift.

------
austinz
I wonder if creating a wrapper struct (let's call it Buffer) which combines an
UnsafeMutablePointer and an UnsafeMutableBufferPointer would improve the
language ergonomics while keeping the performance of the 'Swift*' version.

Buffer would have a constructor taking the number of items to store, and would
upon creation create a buffer using UnsafeMutablePointer.alloc(). It would
then use the UnsafeMutablePointer to build an UnsafeMutableBufferPointer. The
latter type allows subscript indexing (e.g. myBuffer[10]) and iteration using
for-in, which we could support by implementing a pass-through subscript() and
generate() function.

Then, when using the struct, we'd pass it using inout parameters to ensure
that it doesn't get copied.

This wouldn't fix the problem of Arrays being ludicrously unperformant, but it
would at least make using the C-style buffer less painful.

------
xenadu02
The Swift safe version has the benefit of not corrupting memory if you run off
the end of the array. In release builds that might account for the small perf
difference.

It is not accurate to claim this is comparing the Objective-C version to
Swift. It's comparing the C version.

------
st3fan
One thing that i want to add is that this whole exercise is actually a straw
man. You yourself start your post with

"Problem Statement : Design an algorithm that fills in a buffer of pixel data"

If that is the problem, then do that. Do not fill an array with Pixel _object_
references. It is not the same problem.

I am not denying that Swift has performance issues. I do think your test and
proof is artificial: nobody would use the 'Swift Safe' method to manipulate
pixel data. This is exactly why the unsafe features exists.

I think what you need to discover is how to use structs, classes and raw
buffers. None of those is a golden hammer. If you have performance problems
with one of those then that does not mean that it is flawed. It is likely
simply a bad choice for the problem at hand.

~~~
owensd
First off, a struct is not an object. Structs in Swift, like many languages,
are value types. They have the same packing structure in Swift as in C,
especially in the example that I gave.

You can read more about them here:
[https://developer.apple.com/library/ios/documentation/Swift/...](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-ID82)

I can write the same problem with components of the array as bytes if you
prefer, but then performance will be even worse. The root cause of the
performance issues is the array access and set. The more the do, the worse the
performance.

So what you are saying, is that no person would ever create an array of data
and expect to do anything with that data? And they would never do that in a
processing loop? Ok...

If you actually read the blog post, you can see that I already gave an example
using raw buffers (the UnsafeMutablePointer<Pixel>). Which means that every
index into the pointer moves 4 bytes. Again, using UnsafeMutablePointer<Byte>
is not doing anything other than creating a harder API surface to work with.

Also, the UnsafePointer types exist because without them, there would be no
way to interact with C code. And if I need to use the UnsafePointer types
everywhere I have arrays so that I can have reasonable performance in debug
and release builds, then there is a bigger problem that needs to be addressed.

~~~
st3fan
> So what you are saying, is that no person would ever create an array of data
> and expect to do anything with that data? And they would never do that in a
> processing loop? Ok...

No. I'm saying the memory layout of Array<Pixel> is undefined. You cannot
assume that it is a contiguous chunk of memory for example.

Therefore it is the wrong solution for a render buffer.

After reading
[https://developer.apple.com/swift/blog/?id=6](https://developer.apple.com/swift/blog/?id=6)
I am not entirely sure about this. Can you find a more clear definition?

