멀티 코어 프로그래밍

작년 연말에 GITISS에 올릴 기술 동향에 대한 글을 요청 받아서 기고 했던 글입니다. 이 글 역시 앞에 글들과 마찬가지로 가볍게 읽어 주시길~ ^^;

멀티 코어 프로그래밍



서론



현재 출시된 대부분의 신형 CPU들은 두 개 이상의 CPU를 내장한 멀티 코어 CPU가 주종을 이루고 있다. 이는 단일 코어에서 더 이상 코어 클럭을 이용해서 성능을 올리는 방법으로는 한계에 도달한 것이 그 이유이다. 이렇게 복수개의 코어를 사용하는 CPU의 등장은 게임 개발에도 큰 영향을 미치고 있는데 이는 PC 플랫폼에서보다  XBOX360[1], PS3[2] 등과 같은 비디오 게임 콘솔 플랫폼에서 더욱 두드러진다. 마이크로소프트사의 XBox360은 내부에3개의CPU가 각각2개의 하드웨어 쓰레드를 가지고 있어 총6개의 하드웨어 쓰레드가 작동하도록 되어 있으며Sony Computer Entertainment의PlayStation3는 하나의 코어에8개의SPE가 있는 형태로 구성이 되어 있다.


이러한 하드웨어 환경에서는 실제 하드웨어가 제공하는 최대한의 성능을 끌어내기 위해서는 제공하는 코어들을 이용해서 멀티 쓰레드를 사용하는 구조로 게임 엔진을 구성을 해야 한다.


이 글에서는 게임 엔진에서 멀티 코어 프로그래밍을 응용할 수 있는 부분에 대해서 살펴 보고 멀티 코어 프로그래밍의 모델, 그리고 멀티 코어를 이용하는 게임 엔진 설계시 고려해 야 할 점에 살펴 보게 된다.



멀티 코어 프로그래밍 모델



멀티 코어를 이용한 게임 프로그래밍은 사실 새로운 개념은 아니다. 이미CPU와GPU 두 개의 코어를 이용해서 프로그래밍하고 있으므로 실제로는 게임 프로그래밍의 경우 멀티 코어 프로그래밍을 하고 있다고 볼 수 있다. 여기에서는CPU의 멀티 코어에 대해서 살펴 보게 될 것이다. 우선 멀티 코어는 게임에 다양하게 이용할 수 있는데 예를 들어 게임 내의 길찾기에 응용하는 방법이 있다.

하나의 코어에서는 길찾기에 사용되는 네비게이션 메쉬를 읽어 들이고 길찾기를 위한 프리프로세싱을 수행하면서 동시에 응용 프로그램의 다른 코어에서는 이를 이용해서 계산된 결과를 가지고 게임의 길찾기를 수행하는데 사용할 수 있다.


길찾기의 또 다른 예로 동시에 여러 개의 에이전트에서 길찾기를 요청하는 경우에 게임 전체 프레임이 떨어지는 경우가 발생할 수도 있는데, 이러한 경우에 외부 스케쥴러를 이용하는 방법이 있다. 외부 스케쥴러에서 길찾기를 수행할 때 임의의 길찾기 요구에 대한 응답 시간이 매우 긴 경우가 발생할 수도 있는데 이 때 해당 프레임의 응답을 기다린 후에 처리하게 되면 프레임 드랍이 발생하게 되지만 다른 코어에서 외부 스케쥴러를 실행하여 길찾기를 수행하게 되면 프레임에 지장을 주지 않고 실행할 수 있게 된다.


그 외 아래 그림에 나와 있는 예로 애니메이션에 사용하는 방법도 있다.


그림에서 물리엔진, 애니메이션 엔진은 개별 서브 시스템으로 별도의 쓰레드로 작동된다.


이 외에도 멀티 쓰레드를 게임에 이용하는 방법으로는 물리 시뮬레이션이나 렌더링 시스템 등을 별도의 분리된 쓰레드를 이용해서 처리함으로써 병렬 처리의 이점을 취하는 동시에 각 서브 시스템 간의 의존성을 최소화 시키도록 설계하는데 이용하는 방법도 있다.



멀티 코어 게임 엔진 디자인



멀티 쓰레드를 이용하는 경우 다양한 이점이 있지만 이를 게임 엔진을 개발하는 것은 어려운데 그 이유는 다른 응용 프로그램과 비교할 때 게임 엔진은 인공지능, 물리 시뮬레이션, 네트워킹, 애니메이션, 렌더링 시스템등과 같은 다양한 서브 시스템으로 구성이 되어 있어며 이들 서브 시스템은 서로 결합되어 작동되는 것이 일반적이므로 훨씬 복잡한 구조를 가지고 있다. 즉, 서브 시스템 간의 의존도가 높아서 멀티 쓰레드를 이용해서 병렬 처리하는 것이 어렵다. 또 다른 이유로는 게임 엔진이 이벤트 중심의 애플리케이션이라는 점이다. 게임은 사용자의 입력이나 네트워크를 통해 전송되는 패킷, 게임 내에 정의된 시나리오, 물리 시뮬레이션 등에 의해서 수시로 변경되며 서로 상호작용해서 작동되는 것이 보통이다. 이러한 이벤트들은 여러 개의 서브 시스템에서 처리하여 그 결과를 이용하게 되는데 이렇게 각 서브 시스템간에 데이터 정보를 공유해야 하는 경우 서브 시스템들을 독립적으로 병렬 처리하는 것이 어렵다.


그리고 게임은 실시간으로 작동되어야 하는데 게임 엔진은 매 프레임을 순차적으로 처리해서 렌더링 하는데 현재의 프레임은 이전 프레임에 의존적이기 때문에 프레임들을 병렬 처리할 수가 없다는 것도 게임 엔진에 병렬 처리를 이용하기가 어려운 이유 중의 하나이다.


이러한 문제점들을 해결하기 위해서 게임 엔진의 병렬 처리를 위한 여러 가지 멀티 쓰레드 모델들이 있는데 이들 모델 중에서 현재 가장 많이 사용되고 있는 모델로는 아래에 나와 있는 [3]비동기 함수 병렬 모델 (Asynchronous parallel model)이 있다.

<비동기 함수 병렬 모델(Asynchronous parallel model)>


이 모델은 게임 루프를 가지지 않으며 각각의 서브 시스템들이 고유의 수행을 하고 가장 최근에 갱신된 결과를 서로 공유해서 데이터간 동기화를 수행하는 것이 특징이다.


그림의 렌더링 과정을 보면 렌더링시 실제 물리 갱신 서브 시스템의 결과를 기다려서 사용하는 것이 아니라 이전 물리 연산 결과를 사용하므로 렌더링 서브 시스템과 물리 시뮬레이션 서브 시스템의 분리와 병렬화가 용이하며 다른 모델들에 비해 더 많은 병렬화가 가능하여 프로세서의 개수가 적은 경우에도 쓰레드 스케쥴링에 의해서 안정적인 성능 향상을 할 수 있다는 장점이 있다. 대신에 각각의 서브 시스템 작업 간에 타이밍에 의한 문제가 발생할 수 있다는 단점이 있다.


이러한 비동기화 함수 병렬화 모델은 각각의 동시 작업 간에 동기화가 적은 경우 효율적이며 전체 응용 프로그램에서 직렬화된 부분이 많아도 성능에 영향을 받지 않는다. 따라서 이 모델을 사용해서 성능을 극대화시키기 위해서는 가능한 동시에 많은 작업을 수행하는 것이 중요하며 또한 서브 시스템 간의 타이밍을 맞추기 위한 작업의 크기가 균등해야 한다.


멀티 쓰레드를 위해 고려해야 할 게임 엔진의 또 다른 측면 중 하나로 게임 엔진에서의 객체 관리 시스템을 들 수 있다. 기존의 보편적인 게임 객체(Game Entity) 정의 방법은 상속을 이용한 정의가 주로 사용되었는데 이러한 방법은 상위 계층에 대부분의 기능들이 포함되는데다 개발이 진행되면서 객체의 종류가 변동됨에 따라 빈번한 설계 변경이 발생하고 변경하는 일 또한 힘들다.

<전통적인 상속 트리>


이러한 문제를 해결하는 좋은 방법 중에 하나는 [4]구성요소(Component)를 이용해서 객체를 구축하는 것으로 이 방법을 사용하면 새로운 게임 객체들을 추가하고 관리하는 일이 쉬울 뿐만 아니라 게임 객체를 각 서브 시스템별 구성요소로 구분하여 멀티 쓰레드 모델을 적용하기가 용이하다는 이점도 있다.


<구성 요소 기반 객체 정의>


위의 그림은 일반적인 네트워크 게임의 플레이어 게임 객체를 구성 요소에 기반하여 정의한 것이다. 플레이어 객체는 게임에서 사용자가 선택한 모델이므로 화면에 렌더링 되기 때문에Rendering 컴포넌트를 가지며 사용자의 입력을 받으므로Mouse Input 컴포넌트도 가진다. 또 게임 내의 다른 객체들과 충돌 등에 반응하여 상호 작용하기 위해서Actor Physics 컴포넌트가 필요하며, 네트워크 플레이를 위해서 패킷 등을 주고 받는 처리를 담당하는Network 컴포넌트와 애니메이션 처리를 위한Animation 컴포넌트도 정의되어야 한다.


이와 같이 구성 요소를 기반으로 객체를 정의하게 되면 새로운 게임 객체를 추가할 때 객체의 구성 요소를 정의하는 방법으로 추가하기 때문에 추가가 용이할 뿐 만 아니라 구성 요소를 멀티 쓰레드의 서브 시스템으로 구분되므로 멀티 쓰레드를 이용하는 데에도 용이하다.


그리고 이러한 구성 요소에 기반한 객체 시스템을 정의할 때 각 구성 요소 간의 의존도를 최소화 시키면서 객체간 필요한 데이터를 주고 받기 위해서 메시지 전달 방식을 사용하게 되는데 이렇게 메시지를 이용하여 구성 요소(서브 시스템)간에 데이터를 주고 받는 방식은 멀티 쓰레드를 이용한 프로그래밍 방식에 적합하다는 또 다른 이점이 있다.



결론



이 글을 쓰는 시점에서는PC 플랫폼의 경우 두 개의 코어를 가진 모델이 주종을 이루고 있는데 이러한 PC 플랫폼에서는CPU 타입의 차이 등으로 인해 멀티 코어 프로그래밍의 효과가 미미할지 모르지만 앞으로4개, 8개의 코어를 가진CPU가 등장하는 경우에는 코어를 어떻게 이용하느냐에 따라 성능 향상의 차이가 달라지게 되므로 향후에는 멀티 코어를 이용한 프로그래밍은 매우 중요한 기술이 될 것으로 예상된다.



참고 자료



[1]
XBox360, Microsoft, http://www.xbox.com

[2]PlayStatin3, Sony Computer Entertainment, http://www.playstation.com

[3] Multithreaded Game Engine Architectures, Gamasutra,

http://www.gamasutra.com/view/feature/1830/multithreaded_game_engine_.php?print=1

[4] Component Based Object Management, Bjarne Rene, Circle Studio Ltd, Game Programming Gems 5


하고 싶은 이야기는 이겁니다. 병렬 처리를 하게 되면 기본적으로 race conditioning과 같은 문제들을 해결해야 하는데, 멀티 코어를 고려해서 엔진을 설계할 때 구성요소 기반의 아키텍쳐를 가지고 가면 구성요소기반의 아키텍쳐가 가지는 고유의 장점 외에도 멀티코어에도 유리하다 것을 이야기하고 싶었던 겁니다. 컴포넌트들로 모듈간 디커플링 시키는 아키텍쳐 구조가 병렬 처리에서의 약점들도 커버해 주더라...이런 것을 이야기하고 싶었던 거죠. ^^; 최근에 Nebula3에서의 멀티 코어 시스템에 대한 글도 있으니 참고로 읽어 보시길 권합니다.


by kimsama | 2008/03/27 12:11 | MultiCore | 트랙백 | 덧글(2)

트랙백 주소 : http://kimsama.egloos.com/tb/1732518
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Commented by kimsama at 2008/03/27 13:26
멀티 코어 관련한 백그라운드 이야기나, 아키텍쳐에 대한 이야기들은 많이 했으니까, 앞으로는 기술적 관점에서 좀 더 구체적인 접근도 필요해 보입니다. 예를 들어 메모리 관리와 같은 문제 말입니다.
Commented by 준우 at 2011/02/18 13:47
안녕하세요. 여기에 추가적인 블로깅은 없나요? 너무 궁금해요 joonoo.chang@gmail.com

:         :

:

비공개 덧글

◀ 이전 페이지다음 페이지 ▶