MPI를 쓰지 않은 병렬처리

MPI는 병렬로 돌려야 할 일을 여러 개의 machine에 나눠서 처리할 때 유리한 조건을 가지고 있는데, 문제는 각기의 machine이 network으로 잘 연결되어있어야 하고 각각의 machine에서 MPI를 위한 daemon이 돌고 있어야 하는 등의 필수 요건들이 있다. 따라서, 관리자가 MPI를 위해서 특별히 배려를 해둔 경우가 아니면 사용할 수가 아예 없다고 봐야 한다.

내 경험으로 40대 가까운 Xeon workstation을 돌려봤는데 (내 기억으로 320개의 core를 돌렸었다), 병렬처리의 위력은 엄청난 거라 잘만 만들어놓으면 오랜 시간이 걸리는 일도 척척 매우 빠른 시간에 잘도 해낸다. 일을 시켜놓고 서버실에 들어가면 한꺼번에 수 많은 machine이 풀 로드로 돌기 때문에 그 팬 소음도 엄청나다.

이런 경우도 있지만, 하나의 서버에 CPU를 많이 얹어놓은 경우도 왕왕있다. 이들은 보드상에서 병렬처리를 위해 결합되어있는 것이라 사실상 하나의 machine인데 core의 개수가 수십 개에 이르는 경우가 대부분이다.

마찬가지로 이러한 경우에도 MPI를 쓸 수는 있지만, 그다지 효율적이진 못하다. 일부러 MPI를 설치해야 되고 하는 문제가 있으니까 말이다.

결론은 multi-threading이다. 이게 생각보다 어려울 것 같지만 쉽다. fork로 병렬의 thread를 열어놓고 각기 thread가 자기가 처리한 결과를 업데이트하게 해놓고 차근 차근 결과만 확인하면 된다. 그러나 kernel scheduler의 지배를 받기 때문에 내가 N개의 thread를 벌였다고 해서 항상 N개의 core를 decicated하게 사용하는 것은 아니다. 그러나 그럴 빈도는 높아진다고 볼 수 있다. 또 core의 개수가 많다고 해서 하나의 thread가 여러 개 core를 쓸 수 있는 것은 아니라 쉽게 말해 N개의 thread를 C개의 core가 달린 장비에서 일을 벌인다고 하면 C>N일 때는 N개의 core를 돌려서 얻을 수 있는 수준의 performance를 기대할 수 있지만 그보단 약간 못하고, C<N인 경우는 효율이 N이 크면 클 수록 감소하는 경향을 보인다.

MPI와 다른 것은 MPI는 개개의 core에서 독립된 application을 실행하는 개념인데, 이것은 하나의 application이 여러 개의 thread를 벌이는 것이라 어찌보면 multi-threaded application이 하나의 machine에서 병렬 처리를 하는 면에 있어서는 관리가 편리하다 볼 수 있다. 물론 multi-threading을 물리적으로 분리된 machine들에서 벌일 수는 없으니까 물리적으로 분리된 여러 개의 machine을 이용하면 MPI를 쓸 수 밖에 없을 것이다.

일반 PC에서 multi-threading을 통해서 모든 Core를 활용하는 병렬처리도 가능한데, CPU의 평균 사용율에 비해 엄청난 과부하가 걸리는 것이라 팬 소음은 감수해야할 것이다.

여기서 일반적인 방법론은, 총 M회의 반복된 일을 해야 한다고 했을 때

1) N개의 thread가 M/N회의 일을 하도록 하게 하는 방법

이 방법은 개개의 thread를 관리할 필요 없이 단순히 M/N회만 반복시키고 그 결과를 mother thread에 알려주는 것으로 끝이난다. 모든 thread가 동일한 속도로 실행되고 있다면 이 방법이 가장 간단한 방법일텐데, 그렇지 않고 thread 별로 걸리는 수행시간이 다르면 가장 늦게 끝나는 thread에 맞춰서 모든 작업이 끝나게 된다. 따라서 특정 thread가 원인 모를 이유로 hang되어있다면 전체 작업도 끝나지 않는다.

2) N개의 thread가 각자의 일을 하되 반복회수 M을 관리하게 하는 방법

thread별로 수행시간이 일정치 않으면 이 방법을 권한다. 총 M회만 반복해서 돌면 되기 때문에 공통 변수에 현재 남아있는 반복 수가 0이 아니면 thread가 반복해서 돌게 놔두는 것이다. 따라서 특정 thread에서 일을 마치지 못하고 있다하더라도 빨리 일을 마친 thread가 나머지 반복 회수를 채울 수 있게 한다. 모든 반복회수를 채웠다고 하면 특정 thread가 hang되어있다고 하더라도 강제 종료시키면 된다.

현재는 56 core machine을 가끔 활용하는데, 과거 280개의 core를 쓸 때보단 훨씬 쾌적하고 그 때보다 CPU 성능이 좋아졌으므로 처리시간도 만족스럽고 결과를 관리하기도 좋아졌다는 이점은 있다. 당시 MPI를 쓰라고 그렇게 권했지만 배우기 힘들다는 이유로 (글쎄 본인의 어플리 케이션에 5-6줄 code를 추가만 하면 되는데도 극구) 40대의 가까운 machine에 매번 접속해서 일을 시켜놓고, 그렇게 해서 얻어진 결과를 하나씩 하나씩 가져와서 정리하는 것으로 하루 일과를 떼우던 이들도 있었으니까, 병렬처리의 이점은 단순히 처리 시간을 줄이는 것 말고도 일을 시키고 결과를 관리하는 것에도 있다. 매번 골치 아픈 일을 일부러 하겠다는 그 고집을 어떻게 말리겠냐만.

하나 집고 넘어가야 할 multi-threaded application을 쓸 때의 문제는 외부에서 만들어진 library를 이용할 때에 있다. 이것이 multi-threaded 환경을 위해서 build된 것이 아니면 linking시에 문제를 일으킬 수 있다. 대개 multi-threaded 조건이 아닌 조건으로 build되어 정작 project를 가동해야 할 때 문제를 일으킨다. 그런 의미에서 타인이 만들어놓은 아무리 훌륭한 library라도 내가 써먹으려면 쉽지 않다는 것이 여기서 드러나게 된다. 코드의 재활용이니 하는 것들 다 좋은데 이런 문제들이 시간을 잡아먹는다는 말이다. 결국에 어쩔 수 없이 스스로 작성해서 돌릴 수 밖에 없는 경우가 왕왕 생긴다.