MPI_BCAST 함수를 이용하여 소수 개의 노드 간 데이터를 주고 받을 때는 코드 작성이 쉽습니다. 하지만 노드가 많아지면 비효율적인 MPI_BCAST 함수 보다는 MPI_ALLGATHERV 함수를 사용하게 됩니다. (n-to-n 교환 시)
여기서 한 가지 주의할 점이 있습니다. 노드 간 교환하는 데이터가 전체 데이터 범위에서 어떻게 나뉘고 교환되는지가 중요 합니다.
2차원 배열을 예로 들면 x축과 y축이 있습니다. x축 범위를 전체로 잡고 y축 범위를 노드 별로 구간을 나눠 연산하고 교환한다면 MPI_BCAST 함수에서 문제 없습니다. 반대로, y축 범위를 전체로 잡고 x축 범위를 노드 별로 나눠 연산한다면??? MPI_BCAST 함수에서는 역시 문제 없습니다.
문제는 MPI_ALLGATHERV 함수에서 발생 합니다. 저도 무턱대고 MPI_BCAST 함수를 MPI_ALLGATHERV 함수로 바꾸고 데이터가 깨져서 원인을 찾는데 몇 시간을 고민해야 했습니다. 원인을 찾아보니 MPI_ALLGATHERV 함수의 내부 구현을 생각하면 알겠더군요.
MPI_ALLGATHERV 함수는 각 노드가 가지고 있는 데이터의 크기(size)와 그 데이터가 합칠 때의 위치(offset)를 알려주는데요. 배열의 메모리 구조를 보면 바깥 축(x축 보다는 y축, y축 보다는 z축)보다는 안 쪽 축의 데이터가 일렬로 배치된다는 거죠. array(1,1)부터 array(10,1)까지 메모리 상에 일렬로 배치되고 array(1,2)는 array(10,1) 다음 위치에 오게 됩니다.
MPI_ALLGATHERV 함수를 이용하여 데이터를 교환하게 되면 그 위치와 일련의 데이터 크기만 보내기 때문에 안 쪽 축에서 데이터가 잘리는 경우, 답이 없습니다. y축을 전체로 잡고 x축을 구간으로 나눠 교환하게 되면, 교환할 수 없다는 것이죠. x축을 전체로 잡고 y축(바깥 축)을 구간으로 나눠야 서로 주고 받는 데이터가 일련의 데이터로 송수신 되고 메모리에 자리잡게 됩니다.
MPI_BCAST 함수는 어떻게 무관하게 잘 될까요? MPI_BCAST 함수에 데이터 내에 크 범위를 지정할 수 있지만, MPI_ALLGAHTERV는 교환하는 데이터 전체의 시작 점(starting point)만 알려주는 것이기 때문입니다. MPI_BCAST 함수는 내부에서 데이터의 dimension을 인식합니다.
ARRAY(2:10,:) <- MPI_BCAST 함수는 이 것을 전송할 수 있습니다. 하지만 MPI_ALLGATHERV 함수는 할 수 없습니다.
대책이 없을까요? 비효율적은 MPI_BCAST 함수를 써야 하나요.
아니죠. 대책은 전치행렬을 구해서 이용하면 됩니다. FORTRAN에 transpose라는 내장 함수가 있습니다. 이를 이용하면 x by y 배열을 y by x로 바꿔줍니다. 이를 이용하면 MPI_ALLGATHERV 함수가 주고 받는 데이터가 안 쪽 축으로 분할 되어도 바깥 축으로 바꾸어 교환할 수 있습니다.
가루비누