[새싹 iOS] 8주차_Reducing Dynamic Dispatch

임승섭·2023년 9월 6일
0

새싹 iOS

목록 보기
21/45

https://github.com/apple/swift/blob/main/docs/OptimizationTips.rst#reducing-dynamic-dispatch

Reducing Dynamic Dispatch


  • Swift는 옵젝C와 같이 아주 다이나믹한 언어이다
  • 옵젝C와는 다르게, swift는 필요에 따라
    removing or reducing the dynamism을 통해
    the ability to improve runtime performance를 개발자에게 제공한다

Dynamic Dispatch


  • 클래스는 기본적으로 메서드나 프로퍼티에 접근할 때
    dynamic dispatch를 이용한다

  • dynamic dispatch는 기본적으로
    indirect invocation through a vTable.

  • 만약 선언 시 dynamic 키워드를 사용하면,
    swift will emit calls via Obj-C message send instead.

  • 두 케이스 모두 direct function call 보다 느리다
    • It prevents many compiler optimizations
    • This is due to the compiler NOT knowing the exact function being called
  • 아래에서는 dynamic dispatch를 static으로 바꿀 수 있는 방법을 소개한다

Advice : Use 'final'

when you know the declaration does NOT need to be overridden


  • final 키워드는 클래스, 메서드, 프로퍼티의 선언을 제약한다
    • the declaration cannot be overridden
  • 이것은 imply that
    the compiler can emit direct function calls instead of indirect calls
  • 즉, "be called via a vTable" -> "be accessed directly"
// 1. 
final class C {		// C 내에서 선언한 것들은 재정의할 수 없다
	var array1: [Int]
    func doSomething() { ... }
}

// 2.
class D {	// array2는 재정의가 가능하지만, array1은 불가능하다 (연산 프로퍼티로써 재정의)
	final var array1: [Int]
    var array2: [Int]
}

// 1 - 1.
func usingC(_ c: C) {
	// Can directly access C.array without going through dynamic dispatch
	c.array[1]			
    // Can directly call C.doSomething without going through virtual dispatch
    c.doSomething()		
}

// 2 - 1.
func usingD(_ d: D) {
	// Can directly access D.array1 without going through dynamic dispatch
	d.array1[i] = ...
    // Will access D.array2 through dynamic dispatch
    d.array2[i] = ...
}

Advice : Use 'private' and 'fileprivate'

when declaration does NOT need to be accessed outside of file


  • private이나 fileprivate키워드는 선언 시
    visibility of the declaration을 그 파일 내로 제약시킨다

  • 이것은 컴파일러가 확신하게 한다
    all other potentially overriding declarations

  • Thus the absence of any such declarations enables the compiler to infer the final keyword automatically and remove indirect calls for methods and field accessses accordingly.

  • 어쨌든, 하나의 클래스만 정의되어 있는 file 내에서 private 키워드를 사용하면, 사실상 override 될 가능성이 없기 때문에 내부적으로 final 키워드를 유추할 수 있다. 결과적으로 static dispatch 형태로 실행된다

private class E {
	func doSomething() { ... }
}

class F {
	fileprivae var myPrivateVar: Int
}

func usingE(_ e: E) {
	e.doSomething()
}
// There is NO subclass in the file that declares this class
// The compiler can remove virtual calls to doSomething()
// and directly call E's doSomething method

func usingF(_ f: F) -> Int {
	return f.myPrivateVar
}


Advice : If WMO is enabled, use 'internal'

when declaration does NOT need to be accessed outside of module


WMO (World Meal Organization)

WMO (Whole Module Optimizations)

  • 기본적으로 swift는 각 파일들을 개별적으로 컴파일한다
    • 3000개의 파일이 있으면, 컴파일 3000번 한다
  • 덕분에 Xcode는 여러 파일들을 동시에 아주 빠르게 컴파일할 수 있따
  • However, compiling each file seperately prevents certain compiler optimizations
  • swift는 전체 프로그램을 하나의 파일인 것 처럼 컴파일 할 수 있고,
    프로그램 자체를 single compilation unit인 것 처럼 최적화할 수 있다
  • 요 방식으로 컴파일된 프로그램은 컴파일 타임이 오래 걸릴 수 있지만,
    but may run faster
  • Xcode build setting에서 'Whole Module Optimization'으로 설정할 수 있다

Advice

  • 위에서 보았듯이, WMO는 module의 source들을 compiler가 한 번에 compile할 수 있게 한다
  • 이것은 allows the optimizer
    to have module wide visibility when compiling individual declarations.
  • internal declaration은 현재 모듈 밖에서는 볼 수 없기 때문에,
    the optimizzer can then infer final by automatically discovering all potentially overriding declarations

0개의 댓글