GPU architecture
on
연말에 이런 저런 일로 머리가 복잡했던 이유로 새해 들어서 갑자기 뭔가 새로운 것을 배우려하거나 몰두해보려고 하니 시동이 잘 안 걸린다. 그래도 서두르면 그래도 이렇게 시동이 안걸린채로 의미없이 흘려버릴 시간을 줄일 수 있지 않을까 해서 스스로 채찍질 중이다.
난 그동안 GPU의 architecture가 사실 좀 궁금하긴 했다. 왜 이게 중요한지, 또 왜 이걸 사용하면 기존의 CPU보다 더 좋은 성능을 낼 수 있는지 등등에 대해서 말이다.
그냥 하나하나 살펴보고 싶다. 왜? 이것 보다 더 복잡한 architecture에 대해서도 알고 싶고, 또 GPU을 이용해서 뭔가를 해볼 때도 더 빨리 이해할 수 있고, 또 다른 일을 GPU의 architecture를 활용해서 할 수 있을지도 나름 가늠해볼 수 있으니까 말이다. 물론 가장 큰 목적은 GPU의 architecture의 좋은 점을 가져다가 다른 architecture에 어떻게 대응할 수 있을까, 어떻게 하면 GPU를 위해 만들어진 툴들을 특정 목적을 위해 변형된 architecture에 그대로 적용해 볼 수 있을까? 등등에 대해 목표를 두고 있다고 할 수 있겠다.
대개 인터넷에 흩어져있는 자원들을 읽어보면 제목은 거창하지만 내용은 아무것도 없는 것들만 보게 된다. 그냥 아무런 지식이 없는 이들을 위해서 그냥 용어만 정리해놓은 것도 마치 아키텍쳐에 대해서 알려주는 것처럼 적어놓은 글만 허다하다.
적어도 내가 알고 싶어하는 것은 다음과 같다.
- GPU는 CPU와 도대체 뭐가 다른가?
- GPU의 최소 단위의 구성 요소, 그리고 그들의 연결 방법
- 최소 단위간의 데이터 교환방법
- 이러한 구조가 어떻게 graphic processing에 이득을 주는지 하는 방법
GPU는 CPU와 도대체 뭐가 다른가?
GPU가 나오기 전의 컴퓨팅 세상에서는 intel MMX 같은 것들이 광고되고 했었다. MMX라는 것이 그냥 쉽게 SIMD instruction에 추가된 것이라고 보면 된다. 그러니까 명령어 하나로 병렬처리가 가능하게 만들어놓은 것인데, 말이 병렬이지 그냥 동일한 처리기능을 갖는 하드웨어를 복사해서 한꺼번에 여러 개 데이터를 동시에 처리할 수 있게 했다는 말이다. 어쨌든 이 기능을 이용해서 그래픽 데이터 처리 속도를 획기적(?)으로 개선했다.
지금의 GPU가 CPU에 대해서 크게 다른 점은 쉽게 말해서 3D rendering을 위해서 필요한 작업을 온전히 최적화된 하드웨어를 활용해서 독자적으로 처리할 수 있게 된 것이다. 더 쉽게 말해서 3차원 데이터를 넣어주면 rendering (shading) 작업을 수행해서 그 결과를 framebuffer에 써주는 작업을 일사천리로 해낸다는 것이다. 이 과정을 효과적으로 수행해내는 하드웨어의 아키텍쳐는 하드웨어 제조사마다 다르고 그 최적화 방법 또한 다 다르다. 그것은 일반 유저의 수준에서 이해할 필요는 없는 것이고, 개발자 수준에서 열려있는 것은 OpenGL 같은 HW independent한 API 정도가 되겠다. 그러니까 HW vendor는 rendering을 위한 작업들, 특히나 OpenGL의 특정 함수들을 빠르게 수행할 수 있도록 HW architecture를 설계하고 그것을 효과적으로 구동할 수 있는 드라이버(라이브러리)를 작성하는 것이다. 그러면 OpenGL 함수들을 사용해서 작성된 application들을 해당 업체의 하드웨어를 사용해서 구동시킬 수 있게 되는 것이다.
따라서, 세부적인 HW architecture는 구체적으로 알려진 바가 없다. 단지 공개되어있는 instruction을 통해서 ALU가 어떻게 구성되어있는지 등등만 추정해볼 수 있다. 어찌되었든 GPU는 이 ALU의 수가 굉장히 많고 SIMD를 구현하기 위해서 ALU는 개별적으로 구동시킬 수도 있고 (그러나 매우 이 과정은 pricy하고) SIMD로 구동해서 사용할 수 있다.
이 아키텍쳐 설계 방법에는 어떤 표준이나 요구사항이란 게 없다. 일단 만들어서 활용해 봤을 때 전체적으로 throughput이 어느 정도 나오냐가 중요할 뿐인 것이다. 그러니까 특정 application을 이미 설계된 architecture를 위한 instruction으로 porting을 하고 그 때 어느 정도의 cycle/power가 소모되는지 simulation을 통해서 성능을 확인할 수 있게 되는 것이다.
ALU라고 해서 단순히 덧셈/뺄셈만 지원하는 것이 아니라 floating point를 지원하게 되면 곱셈/나눗셈도 지원하고 그 외에 HW로 쉽게 구현할 수 있는 logic operations (and/or/neg/…)에 max/min 따위의 연산도 수행할 수 있다.
중요한 것은 어떤 일을 처리하기 위해서
- 얼마나 효과적인 연산을 지원하는가
- 각각의 최소단위들을 얼마나 효과적으로, 자유롭게 연결할 수 있는가
- 각각의 최소단위에서 넣어주고 나오게 되는 데이터들을 얼마나 빠르게 유통시킬 수 있는가
- pipelining은 얼마나 효과적으로 할 수 있느냐
등등을 얼마나 고려했느냐가 되겠다.
GPU의 최소단위는 무엇인가?
이 문제는 조금 개념적이라고 볼 수 있을 것 같다. 사실상 ALU 혹은 이와 비등한 단위를 최소 단위라고 할 수 있을텐데, 구조가 복잡해지게 되면서 일련의 복잡한 일을 수행하는 ALU의 array 혹은 pipeline을 최소 단위로 볼 수 있게 될 듯하다. 이것을 아예 thread라고 명명한 것 같다. 이를테면 SIMD에서 D가 data를 뜻하는데, 사실상 이것은 하나의 ALU로 mapping이 되었지만, thread는 이것보다 더 큰 개념으로 직렬로 연결된 혹은 보다 flexible하게 직병렬로 연결된 ALU의 set으로 보는 것이 맞을 것 같다. 그래서 SIMT라는 용어를 사용한다. 이를테면 하나의 thread가 하나의 3차원 좌표를 입력하면 shading된 결과를 얻는 것이라고 할 때 SIMT는 어떤 주어진 영역을 shading하는 명령이 될 수 있는 것이다.