Skip to content

3부. 데이터는 왜 새는가: 메모리와 콜레싱

앞 장에서 일꾼들이 하나의 칠판에 몰릴 때 벌어지는 ‘직렬화(줄서기)’ 병목을 보았다. 이번에는 반대로 칠판은 넉넉하지만, 계산에 필요한 재료를 가져오는 과정에서 발생하는 병목을 살펴보자.

GPU의 연산 코어는 매우 빠르다. 하지만 계산할 데이터가 제때 도착하지 않으면, 빠른 계산기도 기다릴 수밖에 없다. 그래서 GPU 성능은 계산량만이 아니라 데이터의 모양에도 크게 좌우된다.

수많은 일꾼에게 데이터를 계속 공급하기 위해, GPU의 메모리(VRAM)는 데이터를 큰 단위로 묶어 가져온다. 필요한 값과 주변 값을 한 번에 묶어서 실어 오는 방식이다. 이때 메모리와 코어 사이를 오가는 데이터 묶음을 트랜잭션(Transaction)이라고 부른다.

데이터는 어떻게 새는가: 콜레싱의 실패

Section titled “데이터는 어떻게 새는가: 콜레싱의 실패”

이 방식은 조건이 맞을 때 아주 효율적이다. 만약 32명의 일꾼(워프)이 창고 안에 나란히 놓인 0번부터 31번까지의 재료를 차례로 요청한다면, GPU는 가까운 데이터들을 한 묶음으로 가져와 여러 일꾼에게 나눠줄 수 있다. 이처럼 줄을 맞춰 메모리에 접근하는 방식을 메모리 콜레싱(Memory Coalescing, 병합 접근)이라고 부른다.

문제는 요청이 조금만 어긋나도 시작된다. 이번에는 홀짝 데이터 액세스 상황을 가정해 보자. 이 상황에서는 일꾼들이 0번, 2번, 4번, 6번처럼 징검다리를 건너듯 재료를 요청한다. 요청 자체는 규칙적이고, 일정한 간격을 가진다.

다만 메모리에서 가져온 묶음 안에는 필요한 짝수 위치의 데이터와, 그 사이의 홀수 위치의 데이터가 함께 섞여 있다. 통로를 지나온 데이터 중 일부만 실제 계산에 쓰이고, 나머지는 그냥 지나간다. 간격이 더 벌어지거나 주소가 제각각 흩어지면 낭비는 더 커진다.

데이터를 나르는 통로의 크기, 즉 대역폭(Bandwidth)은 한정되어 있다. 그 통로를 실제로 쓰지 않는 데이터가 함께 차지하면, 같은 시간에 가져올 수 있는 유효 데이터의 양은 줄어든다. 이것이 접근 패턴이 나쁠 때 생기는 트랜잭션 낭비다.

병목은 용량보다 패턴에 가깝다

Section titled “병목은 용량보다 패턴에 가깝다”

흔히 그래픽 카드의 메모리에 병목이 생겼다고 하면, 저장 공간(VRAM)의 절대적인 용량이 부족하다고 생각하기 쉽다. 하지만 여기서 말하는 병목은 창고의 물리적인 크기보다 물건을 꺼내오는 접근 패턴(Access Pattern)에 가깝다. 창고가 충분히 커도 필요한 재료가 듬성듬성 놓여 있다면, 큰 단위로 움직이는 배달 시스템은 빈칸까지 함께 나르게 된다. 결국 같은 양의 데이터를 다루더라도, 배치된 모양에 따라 실제 데이터 이동의 효율이 달라진다.

이것은 GPU 메모리 구조의 설계 선택의 결과다. 많은 코어에 데이터를 빠르게 공급하려면 넓은 통로와 큰 묶음이 필요하다. 그 구조는 줄 맞춘 접근에는 강하지만, 듬성듬성하거나 흩어진 접근에서는 통로 일부가 낭비된다.

앞 장에서는 같은 칠판에 몰릴 때 병렬성이 줄서기로 접히는 모습을 보았다. 이번 장에서는 데이터가 놓인 모양이 나쁘면 메모리 통로가 낭비되는 모습을 보았다.

결국 병렬성은 코어 수 너머의 자리에 있다. 작업이 서로 다른 자리로 흩어지는지, 데이터가 한꺼번에 가져오기 좋은 모양으로 놓여 있는지가 함께 맞아야 한다.

다음 장에서는 이런 조건을 계산의 표현과 배치가 어떻게 바꿀 수 있는지, AXIOM이라는 사례를 통해 살펴본다.