Why are fast functions so expensive?

Why are fast features so expensive?

I am writing an application using SpriteKit. In each frame I recalculate the position of the CameraNode in the function update()

. Let's call it //(cameraNodeCode)

. This current setting had little effect on the number of frames per second, it remained at 60.

override func update() {
    //(cameraNodeCode)
}

      

Since cameraNodeCode pretty big, I thought it would be better to simplify my code and turn it into a function: updateCameraNode()

. Now this was what I had:

func updateCameraNode() {
    //(cameraNodeCode)
}

override func update() {
    updateCameraNode()
}

      

When I tweak the code like this, the frames per second suddenly dropped to 20. I was very surprised because I didn't think the functions were so expensive to name. I decided to test my theory with this code:

func emptyFunction() {

}

override func update() {
    emptyFunction()
    emptyFunction()
    emptyFunction()
    emptyFunction()
    emptyFunction()
}

      

As I predicted, when I did this, the frames per second plummeted, down to 4.1 frames per second!

My questions:

  • Why is this happening? Is this, I think, and because just a function call is so expensive, or is there something I can't see?
  • Is there a way that I could still keep my code simple without having 20fps?

Update

The key information I forgot was that I was using Xcode playgrounds. I think this is a bug with SpriteKit and Playgrounds. I have error message files from Apple so I can see where this is getting me.

+3


source to share


2 answers


Speaking of Sprite-kit, I tested your code on my iPhone 7 in the new Hello World template:

import SpriteKit
class GameScene: SKScene {
    private var label : SKLabelNode?
    override func didMove(to view: SKView) {

        // Get label node from scene and store it for use later
        self.label = self.childNode(withName: "//helloLabel") as? SKLabelNode
        if let label = self.label {
            label.alpha = 0.0
            label.run(SKAction.fadeIn(withDuration: 2.0))
        }
    }
    func emptyFunction() {}
    override func update(_ currentTime: TimeInterval) {
        // Called before each frame is rendered
        //emptyFunction()
        //emptyFunction()
        //emptyFunction()
        //emptyFunction()
        //emptyFunction()
    }
}

      



If I haven't commented out the lines (remove //) inside the update method, nothing changes. I am always 60fps. Check your project to see which lines were causing this sharp drop in fps, or if you test your code against a simulator, try a real device. Hope it helps.

+3


source


Swift has three different dispatch methods with different characteristics:

  • Direct dispatch should be very fast. Also known as static dispatch.
  • The table manager is a little slower due to the method lookup in the witness table. Also called Dynamic Dispatch.
  • Dispatch is the most dynamic dispatch method. However, it is also the slowest of the three.

You can force the compiler to use static dispatch by adding final

to your method:

final func emptyFunction() {
}

      



It will also provide the compiler with additional optimization options, such as inline code. Remember to build with optimizations enabled, which is inappropriate for debug builds. Therefore, you must select a release configuration for performance testing. Debug builds for Swift projects are often notoriously slow.

For more information on method dispatch and keyword static

see this Swift blog post .

This excellent post explains the three kinds of method dispatch in Swift and when they are used.

+2


source







All Articles