삽질가루2009/06/08 11:12


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 함수가 주고 받는 데이터가 안 쪽 축으로 분할 되어도 바깥 축으로 바꾸어 교환할 수 있습니다.


가루비누
저작자 표시 비영리 변경 금지
Posted by cheru
TAG MPI, 포트란
하루가루2009/06/03 11:31



오랜만의 글쓰기다. 

협업이란 말을 CPU와 GPU의 관계에서 듣게 되다니 새롭다. 순차적 연산 구조인 CPU와 병행 연산 구조인 GPU가 모두 활용되는 프로그램이 작성된다면 뛰어난 성능을 보이리라 생각된다.

혹시 우리 프로젝트에도 이 기술을 적용할 수 있을까 해서 FORTRAN CUDA를 찾아봤다. 온라인으로 요청하면 제공받을 수 있는 것 같다. OpenMP와 MPI를 이용한 성능 향상의 한계를 CUDA가 한 단계 높혀주지 않을까 기대된다. 

문제는 내가 사용하는 환경들에서는 CUDA를 사용할 수 없다. GeForce 8100 이상의 그래픽 카드에서 CUDA를 지원하는데, 병렬 모델 분야에서 사용되는 컴퓨터에는 그래픽 카드가 별도로 탑재되지 않는다. 대부분 내장 그래픽 카드다. (ㅠㅠ) 그 대신 CPU 프로세서는 월등하다. Xeon CPU core가 여러 개 박혀 있어 OpenMP 적용하면 성능은 매우 좋아진다.

기상 예측, 수치 해석 모델 등에 활용되는 연산은 90% 이상 부동소수점 연산이고, 기상 모델에서 사용하는 데이터는 resolution에 따라 다르지만 큰 데이터는 4개의 축을 갖고 있다. 엄청 크다. 가정 집 PC에서 실행하면 ㄷㄷㄷ이다. 이를 OpenMP나 MPI로 적용하는 것은 많은 돈 뭉치를 core의 수 만큼 나눠 세어나가는 것이며 그 core의 참여 수에 따라 돈을 빨리 센다. GPU를 이용하면 이 core를 몇 십 배 쉽게 활용할 수 있어 보인다. 그리고 MPI와 달리 CPU와 GPU의 협업은 network를 이용하지 않기 때문에 비교도 되지 않을 것이다.

OpenMP의 후계가 CUDA와 같은 GPU 기반 병렬 연산 기술이 된다면 MPI는 어떻게 될까 생각된다. 다. 나는 CUDA에도 한계가 있다고 본다. 하나 혹은 두 개의 그래픽 카드를 갖는 한 머신에서 다룰 수 있는 연산은 한계가 있다. GPU core도 최대 수가 제한될 것 아닌가. 현재는 괜찮겠지만, 모델 프로그램의 데이터 resolution은 하드웨어 성능에 따라 프로그래머가 욕심 내고 있다. 4x5도 크기의 셀이 2x2.5로 조밀해지면서 기존 데이터보다 4배 이상 데이터가 커졌다. 

전 지구 모델을 예로 들면 경도와 위도를 144 x 91개로 나누는데 km로 따지면 엄청나지 않은가. 과학은 앞으로 이를 더 조밀하게 만들어 예측을 정확히 하고자 노력할 것이다. 위도와 경도가 각각 2배씩 조밀해지면 전체 데이터는 4배, 그 외 고도 등에 따라 또 증가할 것이다. 결국, GPU에서도 이 데이터를 다 처리하기 위해 load가 걸릴 것이고 이를 분산하는 기술이 적용되야 한다. MPI가 현재 OpenMP의 개선 한계를 처리해주듯이 GPU 연산의 부하도 MPI가 처리할 것이다. 

아... 이 글의 요지는 MPI를 열심히 마스터 해서 GPU와 협업 시키는 연구를 해보고만(!) 싶다는 것이다. 이번 방학 때 짬을 내서 간단하게 테스트 해보고 효과가 있다면 내년도 연구방향에 슬쩍 넣고, 그 전에 난 졸업하련다.


- 가루비누 -













저작자 표시 비영리 변경 금지
Posted by cheru
하루가루2008/11/21 00:01

병렬 프로그래밍을 하면서 간과하고 있었던 부분입니다.

싱글 환경은 ifort 인텔 포트란 컴파일러로 실행 파일을 만들고, 병렬 환경은 mpif90 파일이 pgf90 컴파일러로 매핑되어 실행 파일을 만들게 되었습니다. 이 두 실행 파일의 연산 결과가 달라서 제가 변경한 코드에서 발생한 에러인 줄 알고 코드 분석을 다시 들어갔습니다. 코드 단에는 문제가 없었습니다.

MPI 네트워크 환경의 문제인가? 생각하면서 테스트 프로그램을 간단하게 만들어 돌려보았지만 정상이었습니다.

그래서 병렬 연산 부분을 취소하고 mpif90(pgf90 컴파일러로 포팅된)을 이용하여 컴파일 하고 노드 1개로만 돌려보았습니다. ifort 컴파일러로 만든 싱글 환경의 실행 파일 결과와 다르더군요. 아차 싶었습니다. 이 부분을 몰라서 1주일 정도 고민고민, 삽질삽질, 분석분석의 연속이었습니다.

싱글 환경에서 pgf90 컴파일러로 실행 파일을 만들어 MPI 이용한 병렬 환경의 결과물과 비교했더니 동일 했습니다. 부동소수점 관련하여 연산이 달라지는 부분이 있는 것 같습니다. 이를 미처 몰라서 직선으로 올 거리를 많이 돌아왔습니다.

프로그램 만들면서 정말 흔하지 않게 겪게 되는데... 이번에 제대로 배우네요.

09.06.01 추가 내용
컴파일러에 따른 부동소수점 결과가 다를 수 있다는 것은 이 글 당시 추측입니다. 저도 그 이유를 확인해보지 않았습니다. 지금 생각해보면 컴파일러 별 컴파일에서 포함되는(제외되는) 부분이 있기에 그 부분이 연산되지 않아 발생한 것이라고도 생각할 수 있습니다. 단순한 부동소수점 연산은 동일합니다. 소수부가 엄청나게 긴 데이터를 다룰 경우는 저도 어떻게 될지 궁금합니다.


가루비누
저작자 표시 비영리 변경 금지
Posted by cheru