본문 바로가기

iOS/WWDC

[WWDC 2016] Understanding Swift Performance - Generic (3)

WWDC 2018 Understanding Swift Performance 를 정리한 포스트입니다.

더 자세한 내용을 원하시면 위 링크를 참조하시길 바랍니다.

 

1. [WWDC 2016] Understanding Swift Performance - Struct, Class (1)

2. [WWDC 2016] Understanding Swift Performance - Protocol (2)

2. [WWDC 2016] Understanding Swift Performance - Generic (3)

 

Generic Code

foo, bar 함수는 T: Drawable 제약조건의 Generic 을 가질 수 있습니다.

 

 

 

foo, bar 함수 매개 변수는 T를 사용합니다.

 

foo(local:) 를 실행하면 호출하는 쪽의 Generic Type T  Point Type으로 바인딩됩니다.

foo(local:) 내부에 bar(local:) 함수가 호출되면서 Parameter local 변수는 Point Type 을 갖게 됩니다.

 

 


하나의 참조 Type만 가지고 있기 때문에 Swift는 Existential Container를 사용하지 않습니다.


호출하는 측에서 사용되는 Type의 The Value Witness Table (VWT)과 Protocol Witness Table(PWT)을 함수에 대한 추가 인수로 전달할 수 있습니다.

 

drawACopy 함수가 실행되면서 매개 변수에 대한 로컬 변수를 만들 때

Swift는 The Value Witness Table (VWT)을 사용하여 힙에 필요한 버퍼를 할당(Allocate)하고 할당 소스에서 대상으로 복사(Copy)를 실행합니다.

 

local.draw() 실행할 경우도 마찬가지로 전달 된 Protocol Witness Table(PWT)을 사용하고 테이블에서 고정 오프셋의 draw 메서드를 찾은 다음 구현으로 이동합니다.

 

 

 

Swift는 로컬 매개 변수에 필요한 메모리를 스택에 valueBuffer를 할당합니다. 

 

 

Line과 같은 큰 값은 다시 힙에 저장되며 로컬 Existential Container 내부의 해당 메모리에 대한 포인터를 저장합니다.

 

Specialization of Generics

 Swift는 호출하는 측에서 사용되는 Type 으로 버전을 만듭니다.

(Static polymorphism: uses type at call-site)

 

 

drawACopy -> drawACopyOfAPoint 의 함수를 생성합니다.

(Creates type-specific version of method)

 

Point의 Line에서 drawACopy 함수를 호출하면 해당 함수의 두 가지 버전을 사용합니다. 

(Swift 가 생성해준다.)

Point 메소드의 drawACopy가 더 이상 참조되지 않으므로 컴파일러는이 메소드를 제거하고

Line 예제에 대해 유사한 최적화를 수행합니다.

 

 

local: Point 는 다른 곳에서 참조하기 않기 때문에 컴파일러에 의해서 최적화 될 수 있습니다. 

// before 
let local = Point()
local.draw()
drawACopyOfALine(Line(…))


// after
Point().draw()
drawACopyOfALine(Line(…))

 

Whole Module Optimization

전체 모듈 최적화 기회를 크게 향상시킬 수있는 기회가 있습니다. 

 

Point 의 정의를 별도의 파일로 옮긴경우

 

Whole Module Optimization 를 사용하면 컴파일러는 두 파일을 하나의 단위로 함께 컴파일하고

Point 파일의 정의에 대한 통찰력을 가지므로 최적화가 가능합니다.

 

 

 

 

Generic 을 사용하지 않고 일반적으로 사용될 때는 힙 할당의 비용 발생하는 것을 알 수 있습니다.

 

 

 

런타임에 Type을 변경할 수 없습니다.

(Type does not change at runtime)

 

Pair Line을 만들면 실제로 Line 메모리는 enclosing pairinline으로 할당됩니다.

(Storage inline)

 

추가 힙 할당이 필요하지 않습니다.

 

 

Struct Type 성능  

struct type의 값을 복사 할 때 힙 할당이 필요하지 않습니다.

(No heap allocation on copying)

 

구조체에 참조가 포함되어 있지 않으면 참조 횟수가 없습니다.
(No reference counting)

 

정적 디스패치 기능을 통해 컴파일러 최적화와 런타임 (실행 시간)을 단축 할 수 있습니다.
(Static method dispatch)

 

 

Class Type 성능

 

힙 할당 및 인스턴스 생성

(Heap allocation on creating an instance)

 

참조 카운트 오버헤드
(Reference counting)

 

Virtual Table을 통한 동적 디스패치
(Dynamic method dispatch through V-Table)

 

 

Unspecialized Generics—Small Value