Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2024 Swift

WWDC24 · 35 min · Swift

Explore Swift performance

Discover how Swift balances abstraction and performance. Learn what elements of performance to consider and how the Swift optimizer affects them. Explore the different features of Swift and how they’re implemented to further understand the tradeoffs available that can impact performance.

Watch at developer.apple.com ↗

Transcript all transcripts

Chapters

Code shown on screen · 39 snippets

An example C function, with self-evident allocation cpp · at 0:24 ↗
int main(int argc, char **argv) {
  int count = argc - 1;
  int *arr = malloc(count * sizeof(int));
  int i;
  for (i = 0; i < count; ++i) {
    arr[i] = atoi(argv[i + 1]);
  }
  free(arr);
}
An example Swift function, with a lot of implicit abstraction swift · at 0:50 ↗
func main(args: [String]) {
  let arr = args.map { Int($0) ?? 0 }
}
An example of a function call swift · at 4:39 ↗
URLSession.shared.data(for: request)
A Swift function that calls a method on a value of protocol type swift · at 6:30 ↗
func updateAll(models: [any DataModel], from source: DataSource) {
    for model in models {
        model.update(from: source)
    }
}
A declaration of the method where it's a protocol requirement using dynamic dispatch swift · at 6:40 ↗
protocol DataModel {
    func update(from source: DataSource)
}
A declaration of the method where it's a protocol extension method using static dispatch swift · at 6:50 ↗
protocol DataModel {
    func update(from source: DataSource, quickly: Bool)
}

extension DataModel {
    func update(from source: DataSource) {
        self.update(from: source, quickly: true)
    }
}
The same function as before, which we're now talking about the local state within swift · at 7:00 ↗
func updateAll(models: [any DataModel],
               from source: DataSource) {
    for model in models {
        model.update(from: source)
    }
}
Partial assembly code for that function, showing instructions to adjust the stack pointer swift · at 7:18 ↗
_$s4main9updateAll6models4fromySayAA9DataModel_pG_AA0F6SourceCtF:
    sub   sp, sp, #208
    stp   x29, x30, [sp, #192]
    
    ldp   x29, x30, [sp, #192]
    add   sp, sp, #208
    ret
A C struct showing one possible layout of the function's call frame cpp · at 7:59 ↗
// sizeof(CallFrame) == 208
struct CallFrame {
    Array<AnyDataModel> models;
    DataSource source;
    AnyDataModel model;
    ArrayIterator iterator;
    ...
    void *savedX29;
    void *savedX30;
};
A line of code containing a single variable initialization swift · at 10:50 ↗
var array = [ 1.0, 2.0 ]
Using the MemoryLayout type to examine a type's inline representation swift · at 11:44 ↗
MemoryLayout.size(ofValue: array) == 8
The variable initialization from before, now placed within a function swift · at 12:48 ↗
func makeArray() {
    var array = [ 1.0, 2.0 ]
}
Initializing a second variable with the contents of the first swift · at 15:42 ↗
func makeArray() {
    var array = [ 1.0, 2.0 ]
    var array2 = array
}
Taking the value of an existing variable with the consume operator swift · at 16:27 ↗
func makeArray() {
    var array = [ 1.0, 2.0 ]
    var array2 = consume array
}
A call to a mutating method swift · at 16:58 ↗
func makeArray() {
    var array = [ 1.0, 2.0 ]
    array.append(3.0)
}
Passing an argument that should be borrowable swift · at 17:40 ↗
func makeArray() {
    var array = [ 1.0, 2.0 ]
    print(array)
}
Passing an argument that will likely have to be defensively copied swift · at 18:10 ↗
func makeArray(object: MyClass) {
    object.array = [ 1.0, 2.0 ]
    print(object.array)
}
Part of a large struct type swift · at 19:27 ↗
struct Person {
    var name: String
    var birthday: Date
    var address: String
    var relationships: [Relationship]
    ...
}
A Connection struct that contains a property of the dynamically-sized URL type swift · at 21:22 ↗
struct Connection {
    var username: String
    var address: URL
    var options: [String: String]
}
A GenericConnection struct that contains a property of an unknown type parameter type swift · at 21:40 ↗
struct GenericConnection<T> {
    var username: String
    var address: T
    var options: [String: String]
}
The same GenericConnection struct, except with a class constraint on the type parameter swift · at 21:51 ↗
struct GenericConnection<T> where T: AnyObject {
    var username: String
    var address: T
    var options: [String: String]
}
The same Connection struct as before swift · at 22:27 ↗
struct Connection {
    var username: String
    var address: URL
    var options: [String: String]
}
A global variable of URL type swift · at 23:23 ↗
var address = URL(string: "...")
A local variable of URL type swift · at 23:42 ↗
func workWithAddress() {
    var address = URL(string: "...")
}
An async function swift · at 25:02 ↗
func awaitAll(tasks: [Task<Int, Never>]) async -> [Int] {
    var results = [Int]()
    for task in tasks {
        results.append(await task.value)
    }
    return results
}
A function that takes an argument of function type swift · at 28:21 ↗
func sumTwice(f: () -> Int) -> Int {
  return f() + f()
}
A C function roughly corresponding to the Swift function cpp · at 28:30 ↗
Int sumTwice(Int (*fFunction)(void *),
             void *fContext) {
  return fFunction(fContext)
       + fFunction(fContext);
}
A function call that passes a closure expression as a function argument swift · at 28:47 ↗
func sumTwice(f: () -> Int) -> Int {
  return f() + f()
}

func puzzle(n: Int) -> Int {
  return sumTwice { n + 1 }
}
C code roughly corresponding to the emission of the non-escaping closure cpp · at 29:15 ↗
struct puzzle_context {
  Int n;
};

Int puzzle(Int n) {
  struct puzzle_context context = { n };
  return sumTwice(&puzzle_closure, &context);
}

Int puzzle_closure(void *_context) {
  struct puzzle_context *context =
    (struct puzzle_context *) _context;
  return _context->n + 1;
}
The function and its caller again, now taking an escaping function as its parameter swift · at 29:34 ↗
func sumTwice(f: @escaping () -> Int) -> Int {
  return f() + f()
}

func puzzle(n: Int) -> Int {
  return sumTwice { n + 1 }
}
A closure that captures a local variable by reference swift · at 29:53 ↗
func sumTwice(f: () -> Int) -> Int {
  return f() + f()
}

func puzzle(n: Int) -> Int {
  var addend = 0
  return sumTwice {
    addend += 1
    return n + addend
  }
}
Swift types roughly approximating how escaping variables and closures are handled swift · at 30:30 ↗
class Box<T> {
  let value: T
}

class puzzle_context {
  let n: Int
  let addend: Box<Int>
}
A generic function that calls a protocol requirement swift · at 30:40 ↗
protocol DataModel {
    func update(from source: DataSource)
}

func updateAll<Model: DataModel>(models: [Model], from source: DataSource) {
    for model in models {
        model.update(from: source)
    }
}
A C struct roughly approximating a protocol witness table cpp · at 31:03 ↗
struct DataModelWitnessTable {
    ConformanceDescriptor *identity;
    void (*update)(DataSource source,
                   TypeMetadata *Self);
};
A C function signature roughly approximating how generic functions receive generic parameters cpp · at 31:20 ↗
void updateAll(Array<Model> models,
               DataSource source,
               TypeMetadata *Model,
               DataModelWitnessTable *Model_is_DataModel);
A function that receives an array of values of protocol type swift · at 31:36 ↗
protocol DataModel {
    func update(from source: DataSource)
}

func updateAll(models: [any DataModel], from source: DataSource)
A C struct roughly approximating the layout of the Swift type `any DataModel` swift · at 31:49 ↗
struct AnyDataModel {
    OpaqueValueStorage value;
    TypeMetadata *valueType;
    DataModelWitnessTable *value_is_DataModel;
};

struct OpaqueValueStorage {
    void *storage[3];
};
A contrast of the two Swift function signatures from before swift · at 31:50 ↗
protocol DataModel {
    func update(from source: DataSource)
}

func updateAll<Model: DataModel>(models: [Model],
                            from source: DataSource) {
    for model in models {
        model.update(from: source)
    }
}

func updateAll(models: [any DataModel], from source: DataSource) {
    for model in models {
        model.update(from: source)
    }
}
Specialization of a generic function for known type parameters swift · at 32:57 ↗
func updateAll<Model: DataModel>(models: [Model],
                            from source: DataSource) {
    for model in models {
        model.update(from: source)
    }
}

var myModels: [MyDataModel]
updateAll(models: myModels, from: source)

// Implicitly generated by the optimizer
func updateAll_specialized(models: [MyDataModel],
                           from source: DataSource) {
    for model in models {
        model.update(from: source)
    }
}

Resources