2부. 병렬성은 언제 접히는가: 직렬화
10,000명의 일꾼과 단 하나의 칠판
Section titled “10,000명의 일꾼과 단 하나의 칠판”우리는 앞서 GPU가 수만 개의 코어를 동원해 거대한 계산을 순식간에 끝내는 모습을 보았다. 압도적인 병렬성은 언뜻 보기에 모든 성능 문제를 해결해 주는 마법처럼 보인다. 하지만 병렬성에는 조건이 붙어 있다. 일꾼들이 서로 간섭하지 않고 흩어져 일할 수 있어야 한다는 것이다.
수만 명의 일꾼이 각자의 책상에서 각자의 독립적인 계산을 할 때는 모두 부드럽게 굴러간다. 하지만 각자 계산한 결과를 공장 벽에 있는 단 하나의 칠판에 합쳐서 적어야 한다고 상상해보자.
이때 GPU의 일꾼들은 한 묶음으로 함께 움직이는 자리에 있다. GPU에서 일꾼들은 보통 32명이 하나의 소대(워프, Warp)로 묶인다. 소대 내의 일꾼들은 확성기에서 떨어지는 단일 명령을 일제히 받아서 수행한다. 확성기에서 “계산 결과를 칠판에 적어!”라는 지시가 울려 퍼지면, 32명의 일꾼이 동시에 단 하나의 칠판을 향해 달려간다.
32명의 일꾼이 동시에 분필을 잡고 칠판의 같은 곳에 숫자를 덮어쓰려 한다면, 칠판은 순식간에 엉망이 되고 계산 결과는 완전히 망가질 것이다. 이 사태를 막기 위해 GPU의 공장장은 아주 고전적인 관리법을 꺼내 든다. 바로 ‘줄서기’다.
병렬성이 접히는 순간: 줄서기 (직렬화, Serialization)
Section titled “병렬성이 접히는 순간: 줄서기 (직렬화, Serialization)”공장장은 칠판 앞에 선을 긋고, 한 번에 한 명만 다가와서 글씨를 쓰도록 통제한다. 한 일꾼이 칠판에 자신의 숫자를 더하고 돌아갈 때까지, 나머지 31명의 일꾼은 뒤에 서서 멍하니 자기 차례를 기다려야 한다.
결과적으로 한 번에 다 같이 끝낼 수 있었던 작업이, 서로를 기다리는 순차적인 작업으로 속도가 곤두박질친다. 수십, 수백 개의 작업 차선으로 넓게 펼쳐져 있던 호방한 병렬성이, 단 하나의 자원 앞에서 ‘1열 종대’라는 비좁은 형태로 접혀버린 것이다. 이를 아키텍처 용어로 직렬화(Serialization)라고 부른다.
이 줄서기는 목적지가 같을 때 어김없이 발생한다. 동일한 변수에 갑자기 계산이 몰리거나, 창구가 제한된 메모리 영역에 물밀듯이 밀려들 때 GPU 코어들은 연산을 멈추고 하염없이 줄을 서게 된다. 결과적으로는, 병렬로 끝나야 할 일이 순서를 기다리는 작업으로 바뀌게 된다.
인터랙티브 슬롯
Section titled “인터랙티브 슬롯”강함의 조건이 깨졌을 때
Section titled “강함의 조건이 깨졌을 때”GPU는 보통 한 소대가 기다리는 동안 다른 소대를 밀어 넣어 빈 시간을 가린다. 하지만 모두가 같은 자원 앞에 줄을 서면, 그런 방식으로도 계산기를 계속 바쁘게 둘 수 없다. 병렬성의 핵심은 머릿수보다 충돌 없는 흩어짐에서 나온다. 각자가 자기 영역을 확보할 수 있을 때에야, 물량은 비로소 병렬의 힘이 된다.
같은 칠판에 글씨를 쓰려다 줄을 서며 병렬성이 접히는 현상을 보았다. 그렇다면, 칠판 대신 계산에 필요한 재료를 꺼내러 창고에 갈 때는 어떨까? 수만 명의 일꾼이 흩어진 물건을 여기저기서 가져오려 할 때, 이 병렬성은 구조적으로 또 다른 병목과 마주친다.
다음 장에서는 데이터를 나르는 길목에서 벌어지는 또 다른 교통체증, 메모리 접근에 관해 살펴본다.