Slide 1

Slide 1 text

Swift Performance Tips for Busy iOS Developers @BradBroulik | [email protected] BradBroulik.blogspot.com

Slide 2

Slide 2 text

2 Performance Timeline (Past) Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec Management demands 2X performance boost by Q4 Developers play video games for 8 months Developers install the latest CPUs Management thanks developers for doubling performance Moore’s Law

Slide 3

Slide 3 text

3 Performance Timeline (Present) Jan Feb Mar Apr May Jun Management demands 2X performance boost by Q2 Developers optimize their code utilizing every technique possible (GCD, caching, code optimizations, etc) Management thanks developers for doubling performance Moore's Law is Dead. Now What?

Slide 4

Slide 4 text

4 Dimensions of Performance Slower Dimension Faster Heap Allocation Stack More Reference Counting Less Dynamic Method Dispatch Static Is this instance allocated on the stack or heap?

Slide 5

Slide 5 text

5 Stack allocation Stack a: Person Int Int x: Person Int Int

Slide 6

Slide 6 text

6 Heap allocation Person Int Int Stack Heap 2 (reference) (reference) a: x:

Slide 7

Slide 7 text

7 Dimensions of Performance Slower Dimension Faster Heap Allocation Stack More Reference Counting Less Dynamic Method Dispatch Static When I pass this instance around how much reference counting am I going to incur?

Slide 8

Slide 8 text

8 Reference counting (less) Stack a: Person Int Int x: Person Int Int

Slide 9

Slide 9 text

9 Person Int Int Stack Heap 2 (reference) (reference) a: x: Reference counting (more) 1 2

Slide 10

Slide 10 text

10 Dimensions of Performance Slower Dimension Faster Heap Allocation Stack More Reference Counting Less Dynamic Method Dispatch Static When I call a method on this instance is it statically or dynamically dispatched?

Slide 11

Slide 11 text

11 Which is faster? Swift Objective-C

Slide 12

Slide 12 text

12 Optimizing Swift Performance Swift can optimize via Static Dispatch Swift Objective-C Which is faster?

Slide 13

Slide 13 text

13 Which is faster? map for-in forEach

Slide 14

Slide 14 text

14 (lower is better) Seconds 0.0 4.3 8.5 12.8 17.0 Convert 1,000 UUIDs to Strings 15.89 0.12 0.07 forEach map for-in Avoid for-in Gist: Swift forEach vs map vs for-in performance test map for-in forEach

Slide 15

Slide 15 text

15 Which is faster? isEmpty) count)

Slide 16

Slide 16 text

16 •isEmpty is more efficient because it only evaluates the first element; count > 0 evaluates all elements when the collection does not conform to RandomAccessCollection. •Want to enforce this practice in your code base? SwiftLint has a static analysis rule for it. Prefer isEmpty (lower is better) Milliseconds 0.0 0.5 1.0 1.5 2.0 1 million items in Set 1.41 0.26 isEmpty count Gist: Swift isEmpty vs count performance test isEmpty) count)

Slide 17

Slide 17 text

17 Regular class) Final class) Which is faster?

Slide 18

Slide 18 text

18 Slower Dimension Faster Heap Allocation Stack More Reference Counting Less Dynamic Method Dispatch Static •All methods become statically dispatched when a class is final •final may be set per method as needed •private methods are implicitly final •final expresses developer intent more clearly Prefer final classes Final class) Regular class)

Slide 19

Slide 19 text

19 struct B) struct A) Which is faster?

Slide 20

Slide 20 text

20 Prefer enums over Strings Slower Dimension Faster Heap Allocation Stack More Reference Counting Less Dynamic Method Dispatch Static •enums are allocated on the stack; String characters are allocated on the heap. •enums do not incur a reference count; Strings incur a reference count. •enums are type safe; Strings are not. •Interested in automatically converting your localizable strings, asset names, or storyboard names to enums? SwiftGen has accomplished this task nicely on my projects. struct B) struct A)

Slide 21

Slide 21 text

21 struct) class) Which is faster?

Slide 22

Slide 22 text

22 Prefer structs over classes •structs are allocated on the stack; classes are allocated on the heap. •structs do not incur reference counting (when their properties are all value types) •structs implicitly use static dispatch •structs prevent unintended sharing •A structs member wise initializer is a nice convenience Slower Dimension Faster Heap Allocation Stack More Reference Counting Less Dynamic Method Dispatch Static struct) class)

Slide 23

Slide 23 text

23 struct) Bonus: Which is faster? class)

Slide 24

Slide 24 text

24 Bonus: Which is faster? (lower is better) Seconds 15.0 15.5 16.0 16.5 17.0 50,000 copies 16.57 15.71 class struct Gist: Swift struct vs class (with many strings) struct) class)

Slide 25

Slide 25 text

2 25 Struct with many strings Person String String String Person String String String Class 2 Class 2 Class Stack Stack Heap a: y: Optimizing Swift Performance 1 2 3 4 5 6

Slide 26

Slide 26 text

26 Class with many strings Person String String String Stack Heap 2 (reference) (reference) b: z: 1 2

Slide 27

Slide 27 text

27 Prefer Structs over Classes (until you reach their point of diminishing returns) •structs do not incur reference counting (when their properties are all value types) •Caution: A struct property will incur reference counting and heap allocation if the property has a reference type for underlying storage (string characters are stored on the heap). Therefore, structs have a point of diminishing returns in regards to reference counting that multiplies proportionally by their number of properties which are reference types. A struct containing more than 1 reference type begins to incur a higher reference count than a comparative class.

Slide 28

Slide 28 text

28 Inheritance Extensions Which is faster?

Slide 29

Slide 29 text

Inheritance Extensions 29 Inheritance uses dynamic dispatch Uses static dispatch Dynamic dispatch definitions Static dispatch definitions Which is faster? Protocol extension method dispatch flow chart

Slide 30

Slide 30 text

30 Prefer extensions over inheritance •Protocols allow us to define methods with either static or dynamic dispatch; inheritance uses dynamic dispatch. •Methods defined within protocol extensions use static dispatch and methods defined within protocol types are dynamically dispatched •Protocol extensions are not bound to single inheritance •Protocol extensions may be applied to both classes or structs •Unfortunately, protocols can not inherit stored properties but classes can Slower Dimension Faster Heap Allocation Stack More Reference Counting Less Dynamic Method Dispatch Static

Slide 31

Slide 31 text

31 Which is faster? Protocol Type Generic

Slide 32

Slide 32 text

32 Which is faster? Protocol Type Generic Dynamic dispatch definition Uses static dispatch Uses dynamic dispatch

Slide 33

Slide 33 text

33 Generic Specialization compiler optimized

Slide 34

Slide 34 text

34 Prefer Generics over Protocol Types Understanding Swift Performance •Generic methods will be optimized via generic specialization during Whole Module Optimization •Generic specialization creates a type-specific version of method that enables static dispatch. A type-specific method will be created per type in use. •If generic implementation is a struct you also get allocation on the stack and no reference counting (when struct contains no references) •And you still get all the benefits of polymorphism Slower Dimension Faster Heap Allocation Stack More Reference Counting Less Dynamic Method Dispatch Static

Slide 35

Slide 35 text

35 Parse JSON on a Background Thread Concurrent Programming with GCD in Swift 3 Main Thread Dispatch Queue User Interface Data Transform Data

Slide 36

Slide 36 text

36 Concurrent Programming with GCD in Swift 3 Group Data Data Result Grouping work requests

Slide 37

Slide 37 text

37 Enable Whole Module Optimization Optimizing Swift Performance Builds take longer but the generated binary will run faster because the compiler makes more aggressive generic specialization and will automatically enable static dispatch when no overrides exist

Slide 38

Slide 38 text

38 Dimensions of Performance Slower Dimension Faster Heap Allocation Stack More Reference Counting Less Dynamic Method Dispatch Static Ask yourself these questions when reading or writing Swift code: 1. Is this instance allocated on the stack or heap? 2. When I pass this instance around how much reference counting am I going to incur? 3. When I call a method on this instance is it statically or dynamically dispatched? Understanding Swift Performance

Slide 39

Slide 39 text

39 Performance Timeline (Future) Jan Feb Mar Apr May Jun Management demands performance boost by Q2 Swift developer enables Whole Module Optimization Management thanks developers for improving performance Swift developers play video games for 2 months

Slide 40

Slide 40 text

Slides: bit.ly/swift-performance Thank You! @BradBroulik | [email protected] BradBroulik.blogspot.com