멀티코어로 가면 클라이언트에선 뭐가 바뀔까

더 이상 CPU 클럭이 올라가는 걸로 성능이 올라가기는 힘들어졌고, 그에 따라 개인용 컴퓨터 레벨에서도 여러 개의 CPU  혹은 CPU 코어를 사용한 머신들이 보급되기 시작했다. 그렇다면 프로그래머가 선택할 길은 무엇일까?

일단 그나마 내가 알고있는(…) 게임 쪽 얘기를 하자면, 이미 2년 이상 전부터 멀티코어 기술을 (처음에야 하이퍼스레딩 얘기도 있었지만) 이렇게 적용하면 어떨까하는 얘기를 하긴했었다.

주류 3D 게임 시장의 경우 — 약간 하드코어하다고 해야하나 — 기본적으로 게임에는 세 가지 기능이 구현된다.

  • 물리엔진
  • 게임 로직
  • 렌더링

이렇게 세 가진데, 저 중에 두 개 정도를 하나의 코어에 묶고, 나머지 하나를 다른 코어에 묶어서 각각이 병렬로 동작하는 구조를 제안한 곳들이 있다 — 인텔이라거나 에픽 소프트라거나.

그런 경우에 게임은 이런 식으로 진행된다. 개별 게임 상태 ((플레이어의 위치, 방향, 속도, … 다른 NPC와 사물의 위치, 방향, 속도 … 등의 논리적인 값들)) 를 S라고 부르고 렌더링된 화면을 R이라고 하면, 두 개의 스레드가 독립된 두 개의 CPU 코어 위에서 실행되면서 S, R을 각각 업데이트 하게 된다. 그리고 이 두 가지를 변경 시키는데보통은 렌더링이 물리연산과 논리에 종속적이니 S -> R순으로 업데이트되는데 보통 다음과 같은 방법이 제안된다.

  • 시간 t0 : S0 생성 (게임 시작)
  • 시간 t1: S0 -> S1 업데이트 | S0 가지고 R1 렌더링(화면 출력)
  • 시간 t2: S1 -> S2 업데이트 | S1 가지고 R2 렌더링

간단한 컴퓨터 구조론을 알고있으면 이해가 가겠지만 아주 단순한 형태의 파이프라인이 사용된다. 다만 사용된 기술은 이렇게 고전적인(…그리고 다른 응용 — 대용량 응용프로그램 서버라거나 — 에서 이미 사용된 것이지만) 것이고, 다른 분야에서는 오래된 것이지만 중요한 것은 저렇게 "쪼개는 것"이 쉽지 않다는 것.

게임 로직처럼 "데이터 -> 처리 -> 렌더링 ((혹은 일반적으로 말해서 출력)) " 하는 형태로 움직이는 프로그램의 경우

  1. 처리의 개별단위를 파악하고 — 위의 내용도 게임 로직과 물리 엔진을 추가로 분해할 수 있다
  2. 각 개별단위에 CPU 코어를 할당하고
  3. 각 코어 간의 데이터 교환이 부하없이 ((많은 수의 lock이 사용되거나 하면 오히려 적은 수의 코어 쓰느니만 못한 경우가 왕왕 생긴다)) 통신할 수단을 찾고

데이터 -> 출력까지 연결되게 해주면, 수정된 프로그램이 멀티 코어에서 "높은 성능을 내면서" 동작하게 된다. 그렇지만 1은 무지 어렵다. 해당 분야의 대가에게서나 저 "결"이 보이는 문제에 가깝다. 즉 일반론이 나오는게 아니라 도메인 지식을 써서 찾게 되는 경우가 흔하다.

그리고 2의 CPU 코어 할당 문제도 어렵지만 존재하는 해결책이 있다(공짜점심). 클라이언트의 경우 ((혹은 개인용 컴퓨터에서 동작하는 류의 프로그램은 다 비슷하게 생각해도)) 개별 PC에 코어가 몇 개 있는지 사전에 알 방법이 없다. 게다가 이미 존재하는 CELL processor처럼 코어 간에 속도 차이/기능 차이가 있는 경우도 있고, 이런 경향은 확대될테니 여기에 일일이 적응하는 것은 힘들 것이다. 그래서 intel TBB의 range 쪼개는 방식이라거나 WinFX에서 제안된 스레드보다 고수준의 "태스크 개념" 같은 걸 사용해서 저런 파이프라이닝 구조를 만들어주면 자동으로 현재 클라이언트 PC 상태에 맞춰서 코어가 할당되게 된다. 즉, 고수준의 작업 단위를 정의하고, 이게 CPU 코어 수보다 많을 수만 있으면 됨.

그리고 3. ((4는 3이 해결되고 1/2만 잘되면 별거없다)) 사실 쉬운게 없긴한데. 예제로 든 게임 엔진(로직/물리엔진/렌더링)의 경우엔 데이터가 넘어가는 것 자체가 자연스러운데, 현실 세계의 많은 응용은 피드백을 가지고 있거든(…).  위에서 쓴 것처럼 hard-realtime이 아닌 것 — 게임은 적당한 응답성만 보장되면 된다 — 의 경우엔 저렇게 시간을 쪼개서 한단계씩 전진하는 방법을 쓸 수 있고, 이 경우엔 피드백도 자연스럽게(어느정도는) 해결된다.

요약하자면,

  • 지금 만들어야하는 것에서 쪼갤 부분을 찾고, (이건 답이 안보인다)
  • CPU 코어 할당은 라이브러리를 써서 해결시키고,
  • 저부하의 데이터 교환을 위한 메시지 큐를 쓸 것 ((단방향이고 생성된 다음엔 값으로 취급할 수 있으면 이렇게 해도 된다. 시간 t1에서 렌더링 엔진이나 게임 로직이 보기에 직전 시간에 만들어진 게임 상태는 "상수 취급"할 수 있어야 한다. 그리고 이런 방법 자체도 네트웍이나 논리 회로 시뮬레이션에서 쓰는 기법에 가깝다. 만류귀종?))

ps. 원래 GPGStudy 포럼에서 본 "클라이언트가 멀티코어에 어떻게 해야할까요"하는 질문글에 대한 답변으로 생각했던 것인데, 해당 글을 못찾아서 포럼엔 못 쓰고 블로그에 쓰려다보니 점점 더 길어졌다(…).

이상한 점 잘못된 점에 대한 태클, 질문 대환영. 댓글을 달아 봅시다(…).

Jinuk Kim
Jinuk Kim

SW Engineer / gamer / bookworm / atheist / feminist

Articles: 935

3 Comments

  1. 저도 멀티 코어로 렌더링 하는 것에 관심이 많은데 논문이 나올 정도의고급한 주제는 아닌 거 같더군요 orz

    그나저나 멀티 코어가 되어가면서 GPU쪽이 힘들어질 거 같다는 얘길 들었는데 이건 어떻게 생각하시나요?

  2. 멀티코어가 되서 코어 수가 남으면 GPU가 CPU안으로 다시 들어가지 않을까라고 추정하는 사람들이 있다. GPU를 요즘 연산 장치로 바꾸는 경향도 있는데 (예를 들어 GPU로 fluid dynamics simulation이라거나), 이런 것은 멀티코어가되면 없어지거나 의미가 적어지겠지.
    당장 지금만해도 소켓 2개에 쿼드코어 박고 8코어 데스크탑을 쓸 수 있는데. (그리고 올 하반기엔 8-코어 개인용 CPU가 출시…)

    PS3에 들어간 셀 프로세서 처럼 일반적인 의미의 CPU 코어 + 제한된 목적으로만 동작하는 코어로 구성된 CPU들도 나오고 있고. (이 경우엔 일종의 SIMD 처리랑 4 bytes flaoting point 연산에 최적화되어있고)

    반대로 독립된 그래픽 가속 박스를 연결해서 쓸 수 있게 되지 않을까 하는 사람들도 있는데 이 경우엔 GPU의 미래가 좋다고 생각하는 사람들이지.

    결론: 미래는 불확실하고, 양쪽 주장하는 사람들이 “어떤 응용을 들고나올 수 있는가”의 문제 아닐까

Leave a Reply