3. 고질적인 메모리 병목 현상
• CPU 속도는 계속해서 빨라졌지만 데이터를 가져오는 건 그다지 빨라지지 않았다.
너와 나의 속도 차이~
4. 지역성의 원리(Principle of Locality)
• 시간적 지역성 : 최근 참조된 메모리 주소는 가까운 미래에 다시 한번 참조되는 경향
• ex) 반복문, 방금 사용한 명령어와 데이터에 반복해서 접근
• 공간적 지역성 : 최근 참조된 메모리 주소의 이웃이 가까운 미래에 참조되는 경향
• ex) 배열 순회
• 오늘날의 컴퓨터는 이 지역성을 고려하여 메모리 병목 현상을 최소화 한다.
5. 메모리 구조
• 대부분의 데이터는 메모리에 적재되고, 그 중 많이 참조되는 데이터는 캐시로 가져온다.
레지스터
캐시
메인 메모리
디스크
속도 및 가격 용량
6. CPU Core
L2 Cache
Main Memory
10 cycles 250 cycles
메인 메모리가 L2 Cache에 약 25배 정도 느리다.
– Intel Xeon 5500 -
7. 캐시 미스와 프로그램 성능
• 캐시 미스가 발생할수록 프로그램은 느려진다.
CPU Core
Cache
Memory
(RAM)
데이터 줘
여기 있다
응 없어(Cache miss)
느리지만 줄게
20. OOP의 문제점
① 게임 엔티티를 포인터로 접근
캐시 미스 발생
② 게임 엔티티의 컴포넌트를 포인터로 접근
캐시 미스 발생
③ 컴포넌트를 업데이트한다.
④ 모든 엔티티에 대해 같은 작업을 반복한다.
따라서 사실상 위와 같은 의미를 지닌다.
21. DOD 적용
• 각 컴포넌트 별로 배열을 생성하여 객체를 담는다.
AI
렌더링
물리
AI AI AI
물리 물리 물리
렌더링 렌더링 렌더링
각 컴포넌트 객체를 배열로 생성하면 메모리 상에서 일렬로 생성된다.
데이터를 캐시로 옮길 때 주변 데이터도 블록 단위로 함께 옮겨지므로 캐시 미스가 줄어든다.
23. OOP VS DOD TEST
• DOD 방식 : 9.4320ms
• Entity에 컴포넌트 배열을 데이터로 가지고 있음 :
• Entity가 컴포넌트 배열을 포인터로 접근 :
TEST CODE : https://github.com/munificent/game-programming-patterns/blob/master/code/structure-of-arrays/component_update/main.cpp
속도 배
컴토넌트 배열 순회 9.4320ms
엔티티 배열 순회 ( 엔티티에 컴포넌트 배열을 포함) 15.5460ms 1.65x
엔티티 배열 순회 ( 엔티티에 컴포넌트 배열을 포인터로 접근) 15.7990ms 1.68x
Order by entity 22.4630ms 2.38x
Order by components 13.0540ms 1.38x
랜덤 컴포넌트 배열 순회 89.5480ms 9.49x
랜덤 엔티티 배열 순회 149.9980ms 15.90x
처음 방법이 DOD 방식이고 맨 아래가 일부러 캐시 미스를 발생시킬 때 속도 차이이다.
위의 표는 한 가지 타입의 컴포넌트로 테스트 했고 네 가지 타입으로 테스트하면 최대 50
배 정도의 성능 차이가 발생했다.
24. DOD 적용 사례
Parallelizing Conqueror's Blade
Culling the Battlefield
: Data Oriented Design in Practice
Data-Oriented Design and C++
26. 얘들아 나 유니티 코펜하겐
갔다왔어. 거기서 DOTS
발표하더라올ㅋ 그래봤자 유니티…
니들은 언리얼 성님 못따라
간다
- 평화로운 스터디 중 어느 날 -
27. - 코로나 사태로 쉬던 중 -
아 심심해 뭐할꺼 없나…
그때 알콜코더님이 말씀하신
발표나 볼까?
이건 발표 해야만 해
헐?!
이럴수가
28. Unity DOTS
• Data-Oriented Tech Stack
그냥 DOD라 하면 없어 보이잖아?
• 핵심 기능
ECS Model
Job System
Burst Compiler
29. ECS Model
• Entity Component System
Entity = ID
Component = Data
Component System = Behavior
Entity A Entity B Entity C
System
Translation
Rotation
LocalToWorld
Renderer
Translation
Rotation
LocalToWorld
Renderer
Translation
Rotation
LocalToWorld
L2W = T * R
30. ECS Model
AI Data
Rendering Data
Physics Data
Rendering Data Rendering Data Rendering Data
AI Data
Physics Data
AI Data
Physics Data
AI Data
Physics Data
Entity는 개념적으로만 컴포넌트를 소유하고 실제로는 ID만 가지고 있다.
Entity
0
Entity
1
Entity
2
Entity
3
AI Component Array
Physics Component Array
Render Component Array
Update AI Data
AI Component System
Update Physics Data
Physics Component System
Update Rendering Data
Rendering Component System
31. Entity
Entity 실제 구현부를 보면 Index(ID)와 Version 관련 변수를 소유하고 있을 뿐,
Component를 직접적으로 소유하고 있지 않다.
32. Archetype N
Archetype
• 컴포넌트의 조합에 따라 Archetype으로 분류된다.
Entity A, B는 Archetype M인 컴포넌트 조합을 소유한 반면,
Entity C는 Archetype N인 컴포넌트 조합을 소유한다.
Entity A Entity B Entity C
Translation
Rotation
LocalToWorld
Renderer
Translation
Rotation
LocalToWorld
Renderer
Translation
Rotation
LocalToWorld
Archetype M
33. Memory Chunks
• 컴포넌트 배열은 Archetype 별로 생성된다.
• 하나의 배열에 모든 컴포넌트를 담지 않고 16K 바이트로 쪼개어 담는다.
ArcheType
16K Chunk
Position Array
Rotation Array
Renderer Array
16K Chunk
Position Array
Rotation Array
Renderer Array
16K Chunk
Position Array
Rotation Array
Renderer Array
ArcheType
16K Chunk
Position Array
Renderer Array
16K Chunk
Position Array
Renderer Array
16K Chunk
Position Array
Renderer Array
34. World
• World는 하나의 EntityManager 객체와 System Group을 포함하는 개념이다.
World
Entity Manager
System Group
World
Entity Manager
System Group
World
Entity Manager
System Group
35. Job System
• 사용자가 쓰기 쉽도록 구현된 멀티쓰레딩 라이브러리
Parallelizing the Naughty Dog Engine Using Fibers(2015) - GDC Vault
36. Job System : Terms
Job : 실행할 작업
Worker Thread
Fiber : Job을 실행하기 위한 Context ( User provided stack, register)
Worker Thread
Worker Thread : Job을 실행할 유닛
Worker Thread
37. Job System : Execute Job
CPU
core
core
core
core
Worker Thread
Worker Thread
Worker Thread
Fiber Pool
Job Queue
※Worker Thread는 코어에 고정됨 ( 쓰레드 간의 컨텍스트 스위칭이 발생하지 않는다.)
Job 실행하기 위해 먼저 Fiber Pool에서
Fiber 하나를 Worker Thread에 가져온다.
40. Job System : Synchronization
CPU
core
core
core
core
Worker Thread
Worker Thread
Worker Thread
Wait List
1
실행 중 대기 상태가 된 Job은 Wait List에 옮겨져
Wait List의 카운터가 갱신될 때까지 대기한다.
(Fiber와 함께 옮겨져 실행에 필요한 Context은 보존된다.)
45. Race Condition
0Thread A + 1
0 + 1Thread B
0Shared variable 1 1
read read write write
메인 쓰레드의 데이터에 대한 레퍼런스를 Thread A, B가 동시에 접근하는 경우 경쟁 상태가 발생한다.
non-mutually
exclusive
operations
cause error
interrupted read/write
46. Job Safety
Unity DOTS : Job System
0 + 1Thread A
1 + 1Thread B
Data (In) 1
read read writewrite
operations
mutually
exclusive,
non-interrupted
Shared Data (Out) 1
0
2
Schedule
dependency
Blittable
NativeContainers
data copy
data copy
47. Job Safety
• 잡 시스템은 메인 스레드의 데이터에 대한 레퍼런스를 잡에 보내지 않고, 데이터의 복
사본을 보낸다.
• 이 복사본은 해당 잡 안에서만 사용하므로 경쟁 상태가 발생하지 않는다.
• 잡은 NativeContainer에 결과를 저장하여 데이터를 공유할 수 있다.
• 잡 간의 실행 순서는 실행 예약(schedule)을 통해 정한다. (Schedule dependency)
48. Burst Compiler
• 최적화된 Native code를 생성해주는 컴파일러
• 모노 컴파일러로 컴파일한 코드는 C++에 비해 최대 10~30배 정도 느리다.
• 버스트 컴파일러는 IL 코드를 C++로 만들고 이를 Native code로 변환한다.
Behind the Burst Compiler
50. 기존 유니티 방식
• MonoBehavior 기반 클래스에 데이터와 행동을 정의
MonoBehaviour
• Data
• Behavior
MonoBehaviour
• Data
• Behavior
MonoBehaviour
• Data
• Behavior
MonoBehaviour
• Data
• Behavior
51. Pure ECS
• 순수 ECS는 ComponentData 구조체에 데이터를 정의하고 시스템에서 행동을 정의
IComponentData
• Data
IComponentData
• Data
IComponentData
• Data
IComponentData
• Data
ComponentSytem
• Behaviour
52. Hybrid ECS
• Hybrid ECS는 MonoBehavior 기반 클래스에 데이터만 정의하고 시스템에서 행동을 정의
MonoBehaviour
• Data
MonoBehaviour
• Data
MonoBehaviour
• Data
MonoBehaviour
• Data
ComponentSytem
• Behaviour
53. Component System 실행 순서
• Component System은 Initialization, Simulation, Presentation 단계 중 어디에 위치할
지 선택할 수 있다. (Default : Simulation)
각 단계 별로 System Group을 소유하고 있으며,
개발자가 정의한 System의 실행 순서는 원하는 대로 지정할 수 있다.
그러면 그에 맞게 Component System의 OnUpdate 함수가 호출 된다.
Initialization Simulation Presentation
54. Component System 실행 순서
참고로 Monobehavior 객체의 Update 함수 호출 시기는 위와 같다.
Initialization Simulation Presentation
FixedUpdate()
Update() LateUpdate()
55. 정리
• Data Oriented-Design은 현대 하드웨어에 친화적인 디자인 패턴
• 유니티는 DOD를 적용하기 위해 Dots 도입
ECS
Jobsystem
Burst Compiler
• 아직은 과도기이고 적용 사례가 빈약하지만 향후 기대