Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Playgrounds 2017 - High Performance Swift

Playgrounds 2017 - High Performance Swift

This talk will look at whether Swift is a "High performance" language and what that means.

The talk will start by looking at some highly optimized C code and implement the same code in Swift, before looking at profiling information and assembly generation to understand where the differences between the two lie and what steps can be taken to close the gap.

The talk will conclude by looking at the many different types of abstraction in Swift, their relative costs, ways to minimize those costs and a look at some improvements coming to Swift that may lower or eliminate these abstraction costs in future.

Matt Gallagher

February 23, 2017
Tweet

More Decks by Matt Gallagher

Other Decks in Programming

Transcript

  1. MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT OVERVIEW ▸ Is

    Swift a high performance language? What is a high performance language? ▸ How do we optimize Swift at the lowest level? ▸ Understanding the relative cost of abstractions in Swift.
  2. MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT WHAT THIS TALK

    WILL NOT BE ▸ When to optimize or why ▸ General optimization concerns (minimizing allocations, cache efficiency, complexity analysis, etc) ▸ Maximizing CPU through multithreading or SIMD ▸ Using APIs like OpenCL, MPI
  3. MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT SWIFT TOPICS I

    WON'T COVER THOROUGHLY OR AT ALL ▸ Avoiding memory allocations in the Swift standard library ▸ Implications of copy-on-write types ▸ Swift String performance
  4. FAST. MODERN. SAFE. INTERACTIVE. Craig Federighi, introducing Swift at WWDC

    2014 MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT
  5. MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT COMPARED TO WHAT?

    ▸ Between 3.9x and 220x faster than Python ▸ Between 1.4x and 1.75x faster than Objective-C ▸ When looking at the relative performance of different languages, we usually look at C.
  6. MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT COMPARED TO C

    ▸ Why is C considered the baseline for performance? ▸ Abstractions.
  7. MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT WHY IS C

    THE BASELINE FOR PERFORMANCE? ▸ It has C ABI function calls with pass-by-value semantics ▸ It has pointers and function pointers ▸ It has arithmetic and logic operations
  8. MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT MT19937_64 MERSENNE TWISTER

    RANDOM NUMBER GENERATOR IN C unsigned long long genrand64_int64(struct mt19937_64* context) { int i; unsigned long long x; static unsigned long long mag01[2]={0ULL, MATRIX_A}; unsigned long long *mt = context->mt; if (context->mti >= NN) { /* generate NN words at one time */ for (i = 0; i < NN - MM; i++) { x = (mt[i] & UM) | (mt[i + 1] & LM); mt[i] = mt[i + MM] ^ (x >> 1) ^ mag01[(int)(x & 1ULL)]; } for (; i<NN - 1; i++){ x = (mt[i] & UM) | (mt[i + 1] & LM); mt[i] = mt[i + (MM - NN)] ^ (x >> 1) ^ mag01[(int)(x & 1ULL)]; } x = (mt[NN - 1] & UM) | (mt[0] & LM); mt[NN - 1] = mt[MM - 1] ^ (x >> 1) ^ mag01[(int)(x & 1ULL)]; context->mti = 0; } x = mt[context->mti++]; x ^= (x >> 29) & 0x5555555555555555ULL; x ^= (x << 17) & 0x71D67FFFEDA60000ULL; x ^= (x << 37) & 0xFFF7EEE000000000ULL; x ^= (x >> 43); return x; }
  9. MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT MT19937_64 MERSENNE TWISTER

    RANDOM NUMBER GENERATOR IN SWIFT public mutating func random64() -> UInt64 { var x: UInt64 = 0 if mti >= NN { for i in 0..<(NN - MM) { x = (mt[i] & UM) | (mt[i + 1] & LM) mt[i] = mt[i + MM] ^ (x >> 1) ^ mag01[Int(x & 1)] } for i in (NN - MM)..<(NN - 1) { x = (mt[i] & UM) | (mt[i + 1] & LM) mt[i] = mt[i - MM] ^ (x >> 1) ^ mag01[Int(x & 1)] } x = (mt[NN - 1] & UM) | (mt[0] & LM) mt[NN - 1] = mt[MM - 1] ^ (x >> 1) ^ mag01[Int(x & 1)] mti = 0 } x = mt[mti]; mti = mti + 1; x ^= (x >> 29) & 0x5555555555555555 x ^= (x << 17) & 0x71D67FFFEDA60000 x ^= (x << 37) & 0xFFF7EEE000000000 x ^= x >> 43 return x }
  10. MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT MT19937-64 IN C

    VERSUS A DIRECT SWIFT TRANSLATION C SWIFT 1.04s 0.62s Swift is 60-70% slower than C. Not too bad, right?
  11. MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT MERSENNE TWISTER IMPLEMENTATION

    RESULTS C INITIAL SWIFT NO ARRAY INDEX NO ARRAYS FINAL SWIFT 0.52s 0.66s 1.49s 1.04s 0.62s Swift is 20% faster than C
  12. IS SWIFT AS FAST AS C? ▸ Like C: ▸

    Swift has C ABI functions with pass-by-value semantics ▸ Swift has pointers ▸ Swift has basic arithmetic and logic operations ▸ If you use Swift to write C, performance will be identical ▸ Generally though, Swift will often be 50% slower because we're happy to allow safety checks and reference counting. MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT
  13. MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT ZERO OVERHEAD ABSTRACTIONS

    HAVE NO COST ▸ C doesn't have many abstractions. That's why it's considered high performance. ▸ The only hard part is ensuring appropriate functions can be inlined. ▸ Swift is the same: give it a chance to inline an abstraction it its cost may drop to zero.
  14. MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT SWIFT ABSTRACTIONS ▸

    Like C, Swift's primary abstraction the humble function. ▸ Exception in Swift, there's a lot of different kinds.
  15. MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT FUNCTION VARIATIONS EMPTY

    FUNCTION ONE PARAM REFERENCE PARAM OBJC PARAM INOUT REF PARAM 2.15ns 25.4ns 15.6ns 2.86ns 2.08ns func emptyFunction() func one(param: Result<Int>) func one(param: BasicClass) func one(param: ObjcSubclass) func one(param: inout BasicClass)
  16. MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT GENERIC VARIATIONS, 1BILLION

    INVOCATIONS ONE PARAM GENERIC PARAM GENERIC ENUM PARAM GENERIC INOUT PARAM LARGER INOUT PARAM 359ns 84.3ns 23.4ns 12.3ns 2.86ns func one(param: Result<Int>) // Same Result<T> passed func generic<T>(param: T) // Same Int generic param used func generic<T>(param: Result<T>) // Same Int generic param used func generic<T>(param: inout Result<T>) // Generic (Int, Int, Int) param used func generic<T>(param: inout Result<T>)
  17. MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT METHOD VARIATIONS, 1BILLION

    INVOCATIONS INOUT REF PARAM NON-FINAL FINAL DYNAMIC OBJ-C 6.69ns 5.82ns 2.13ns 3.23ns 2.15ns func one(param: inout BasicClass) class ObjcSubclass: NSObject { func nonFinalMethod() final func finalMethod() dynamic func dynamicMethod() @objc dynamic func objcMethod() }
  18. MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT GENERIC CONVERSIONS, 1BILLION

    INVOCATIONS NON-GENERIC GENERIC 309ns 4.87ns func paramCopyingFunction(array: inout Array<Int>, result: Int) { array[0] = result } func genericCopyingFunction<T>(array: inout Array<T>, result: T) { array[0] = result }
  19. MATT GALLAGHER, PLAYGROUNDS 2017: HIGH PERFORMANCE SWIFT SWIFT FUNCTION ABSTRACTIONS

    AND PERFORMANCE ▸ Understand "pass-by-ownership" conventions. Single owner types would help greatly – see the Swift "Ownership" manifesto and the pending "owned/shared/moveonly" keywords. ▸ Use inout or methods to reduce reference count overheads. ▸ Specialize your generics by keeping declarations and usage in the same module. ▸ Swift can't specialize or inline across compilation/module boundaries (this is a possibility for Swift 4).