Slide 1

Slide 1 text

An Introduction to Swift Performance Danielle Tomlinson - @dantoml

Slide 2

Slide 2 text

What makes code slow?

Slide 3

Slide 3 text

Allocation

Slide 4

Slide 4 text

Stack

Slide 5

Slide 5 text

Heap

Slide 6

Slide 6 text

Reference Counting

Slide 7

Slide 7 text

func perform(with object: Object) { object.doAThing() }

Slide 8

Slide 8 text

func perform(with object: Object) { __swift_retain(object) object.doAThing() __swift_release(object) }

Slide 9

Slide 9 text

Dispatch

Slide 10

Slide 10 text

Inline (0ns)

Slide 11

Slide 11 text

Static (~1ns)

Slide 12

Slide 12 text

Dynamic (~5ns)

Slide 13

Slide 13 text

Objects

Slide 14

Slide 14 text

Classes

Slide 15

Slide 15 text

p: Index* Stack class Index { let section: Int let item: Int } let i = Index(section: 1, item: 1) Heap section: Int item: Int

Slide 16

Slide 16 text

i: Index* Stack class Index { let section: Int let item: Int } let i = Index(section: 1, item: 1) let i2 = i Heap section: Int item: Int i2: Index*

Slide 17

Slide 17 text

i: Index* Stack class Index { let section: Int let item: Int } let i = Index(section: 1, item: 1) __swift_retain(i) let i2 = i Heap section: Int item: Int i2: Index*

Slide 18

Slide 18 text

Structs

Slide 19

Slide 19 text

Stack

Slide 20

Slide 20 text

section: 1 item: 1 Stack struct Index { let section: Int let item: Int } let i = Index(section: 1, item: 1)

Slide 21

Slide 21 text

Stack struct Index { let section: Int let item: Int } let i = Index(section: 1, item: 1) let i2 = i section: 1 item: 1 section: 1 item: 1

Slide 22

Slide 22 text

name: StringA* id: StringB* Stack struct User { let name: String let id: String } let u = User(name: "Joe", id: "1234")

Slide 23

Slide 23 text

name: StringA* id: StringB* Stack name: StringA* id: StringB* struct User { let name: String let id: String } let u = User(name: "Joe", id: "1234") __swift_retain(u.name._textStorage) __swift_retain(u.id._textStorage) let u2 = u

Slide 24

Slide 24 text

Abstractions

Slide 25

Slide 25 text

Example (0.3s) : struct Circle { let radius: Double let center: Point func draw() {} } var circles = (1..<100_000_000).map { _ in Circle(...) } for circle in circles { circle.draw() }

Slide 26

Slide 26 text

Requirements Change

Slide 27

Slide 27 text

Protocols

Slide 28

Slide 28 text

Example (4s) : protocol Drawable { func draw() } struct Circle: Drawable { let radius: Double let center: Point func draw() {} } let drawables: [Drawable] = (1..<100_000_000).map { _ in Circle(...) } for drawable in drawables { drawable.draw() }

Slide 29

Slide 29 text

Why?

Slide 30

Slide 30 text

struct Circle { let radius: Double let center: Point func draw() {} } var circles = (1..<100_000_000).map { _ in Circle(...) } for circle in circles { circle.draw() }

Slide 31

Slide 31 text

protocol Drawable { func draw() } struct Circle: Drawable { let radius: Double let center: Point func draw() {} } var drawables: [Drawable] = (1..<100_000_000).map { _ in return Circle(...) } for drawable in drawables { drawable.draw() }

Slide 32

Slide 32 text

ProtocolWitnessTable draw() CircleDrawable ... draw() LineDrawable ...

Slide 33

Slide 33 text

protocol Drawable { func draw() } struct Circle: Drawable { let radius: Double let center: Point func draw() {} } var drawables: [Drawable] = (1..<100_000_000).map { _ in return Circle(...) } for drawable in drawables { drawable.draw() } draw() CircleDrawable ...

Slide 34

Slide 34 text

ExistentialContainer ValueBuffer ProtocolWitnessTable

Slide 35

Slide 35 text

ExistentialContainer radius struct Circle: Drawable { let radius: Double let center: Point func draw() {} } center

Slide 36

Slide 36 text

ExistentialContainer struct Line: Drawable { let origin: Point let end: Point func draw() {} } Origin End

Slide 37

Slide 37 text

Example (45s) : protocol Drawable { func draw() } struct Line: Drawable { let origin: Point let end: Point func draw() {} } let drawables: [Drawable] = (1..<100_000_000).map { _ in Line(...) } for drawable in drawables { drawable.draw() }

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

ValueWitnessTable ValueBuffer allocate: copy: destruct: deallocate:

Slide 40

Slide 40 text

In Practice Stack origin Line vwt pwt end LineDrawable copy: ... Heap drawable: func draw(drawable: Drawable) { drawable.draw() } let value: Drawable = Line() draw(local: value) // Generates func draw(value: ECTDrawable) { var drawable: ECTDrawable = ECTDrawable() let vwt = value.vwt let pwt = value.pwt drawable.vwt = value.vwt drawable.pwt = value.pwt vwt.allocateBuffAndCopyValue(&drawable, value) pwt.draw(vwt.projectBuffer(&drawable) }

Slide 41

Slide 41 text

Modelling Your Data

Slide 42

Slide 42 text

Generics

Slide 43

Slide 43 text

struct Stack { ... }

Slide 44

Slide 44 text

Enumerations

Slide 45

Slide 45 text

enum AccountStatus: String, RawRepresentable { case .banned, .verified, incomplete }

Slide 46

Slide 46 text

Domain Specific Models

Slide 47

Slide 47 text

Thanks! Office Hours: 16:30 in the Atrium. @dantoml