1

I've come across an interesting Swift performance problem, and was looking for some suggestions, analysis on why this is happening.

I have an algorithm that required hundreds of thousands of array accesses in a loop. I find that if I reference the array as an instance property (from inside the same class instance), the performance is very poor. It seems that the array is being de-referenced at each iteration. That seems strange given that the arrays are members of the same class doing the work. Wouldn't self.x not require x to be dereferenced over and over again? The equivalent Java code doesn't have the same performance problem.

In the below example, test3 takes 0.5 seconds and test4 takes 0.15 seconds.

Do I really have to go through all my code and assign locally scoped arrays every single time I do something?

Any tips/ideas would be welcome. I have the compiler optimization set to Fast-O.

Simon

EDIT: The answer is spelled out in this article here: https://developer.apple.com/swift/blog/?id=27

Hope it helps. Long story short, private/final for the class scoped variables will remove the need for the unwanted indirection to access the array.

class MyClass {

    var array_1 = [Int64] (count: 16 , repeatedValue: 0)
    var array_2 = [Int64] (count: 16 , repeatedValue: 0)


    func runTest3() {
        // test #3
        //
        let start = NSDate().timeIntervalSince1970
        for i in 0 ... 10000000 {
            if (array_1[ i%16 ] & array_2[ i%16 ] ) != 0  {
                // whatever
            }
        }
        let passed = NSDate().timeIntervalSince1970 - start
        print("3 time passed: \(passed)")
    }

    func runTest4() {
        // test #4
        //
        let start = NSDate().timeIntervalSince1970
        let localArray_1 = self.array_1
        let localArray_2 = self.array_2
        for i in 0 ... 10000000 {
            if (localArray_1[ i%16 ] & localArray_2[ i%16 ] ) != 0  {
                // whatever
            }
        }
        let passed = NSDate().timeIntervalSince1970 - start
        print("4 time passed: \(passed)")
    }
}
13
  • 1
    I compiled this with -O and got less than 0.01 seconds for each one. It probably depends what you do inside the loop. Commented Apr 17, 2016 at 21:37
  • If you do ...let localarray = self.array.. Swift doesnt copy the array, he just "points" to the memory and keeps the record of changes to the array (kind of like git is working) so it is save to use it this way Commented Apr 17, 2016 at 21:46
  • Yes, the localArray method is safe enough, it just prevents the self.??? dereference happening every iteration. Commented Apr 17, 2016 at 21:53
  • @jtbandes - I have -O set in Swift Compiler Code Generation, but I get this: 3 time passed: 0.44688892364502 4 time passed: 0.0145220756530762 Commented Apr 17, 2016 at 21:54
  • Do you have any code replacing "whatever"? Commented Apr 17, 2016 at 21:55

1 Answer 1

2

https://developer.apple.com/swift/blog/?id=27

Private/Final for the class-scoped variables removes the performance problem. Reasons in the above article. Thanks everyone for the help.

Sign up to request clarification or add additional context in comments.

3 Comments

Looks like your link leads to this same question and not the post you've intended.
@TimurKuchkarov - Ooops, thanks for picking that up. Fixed the link now. Late Sunday night brain freeze there. Cheers
This answer may be misleading users. As long as Whole Module Optimization is turned on (and it should be for Release mode), there is little need to mark methods final/private for performance reasons. These markings are to express your intent to other programmers. Please see the last section of the linked blog post about how WMO addresses this issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.