1. 개요
연구 배경
GPU 실행에 맞춰 설계한 솔버를 CPU에서 실행하면 CPU 전용으로 최적화한 코드보다 성능이 낮을 수 있습니다. 자료 구조와 커널 분할 방식이 GPU 실행 모델을 기준으로 설계되기 때문입니다.
그러나 GPU가 없는 환경에서의 실행, GPU 커널의 정확성 검증, 개발 단계의 디버깅을 위해 CPU 실행 경로도 유지해야 합니다.
본 글에서는 먼저 OpenMP 병렬화를 통해 CPU 실행 성능을 얼마나 개선할 수 있는지 평가합니다.
하이브리드 병렬화의 검토 배경
OpenMP 적용 범위를 확대한 뒤에는 동일한 코어 수에서 순수 MPI와 MPI–OpenMP 하이브리드 병렬화의 성능을 비교했습니다. 하이브리드 구성은 MPI 랭크 수를 줄이는 대신 각 랭크에서 여러 OpenMP 스레드를 실행합니다.
두 방식은 같은 수의 코어를 사용하더라도 서로 다른 오버헤드를 발생시킵니다. MPI에서는 프로세스별 주소 공간이 분리되므로 서브도메인 경계에서 통신이 필요하고, 프로세스별 자료 구조도 각각 유지해야 합니다. OpenMP 스레드는 주소 공간을 공유하므로 프로세스 간 통신과 자료 중복을 줄일 수 있지만, 스레드 동기화, 거짓 공유(false sharing), NUMA 메모리 지역성 저하에 따른 비용이 발생합니다.
MPI 랭크 수를 줄이면 다음 두 가지 효과를 얻을 수 있다고 가정했습니다.
- 통신량 감소 — MPI 서브도메인 경계 수가 감소합니다.
- 랭크 국소 전처리기(rank-local preconditioner)의 성능 저하 완화 — 랭크당 서브도메인이 커지면 전처리기가 한 번에 처리하는 국소 문제의 크기가 증가합니다.
이러한 효과가 전체 성능 개선으로 이어지려면 랭크 내부의 OpenMP 병렬 성능이 MPI 병렬 성능에 근접해야 합니다. OpenMP 스레드의 계산 효율이 MPI 프로세스보다 현저히 낮으면 통신량 감소로 얻는 이점이 상쇄됩니다.
그러나 다수의 CFD 코드가 CPU 병렬화에 순수 MPI 방식을 사용한다는 점을 고려하면, 하이브리드 방식의 이점이 실제 계산에서도 유효한지는 별도의 검증이 필요합니다. 이에 따라 두 방식의 성능 차이와 그 원인을 실측을 통해 분석했습니다.
평가 방법
동일한 격자와 해석 조건을 사용하여 4, 8, 32, 128코어에서 순수 MPI, 순수 OpenMP, MPI–OpenMP 하이브리드 방식의 경과 시간(wall-clock time)을 비교했습니다.
평가 대상은 자체 개발 중인 압축성 유동 솔버 Wake CFD의 CPU 실행 경로입니다. 격자는 ONERA M6(306,577절점)와 NASA DPW CRM(3,600,000절점)을 사용했으며, 지배 방정식과 난류 모델은 각각 압축성 RANS와 Spalart–Allmaras 모델입니다.
하이브리드 구성은 npX×TY로 표기했습니다. 여기서 X는 MPI 랭크 수, Y는 랭크당 OpenMP 스레드 수를 의미합니다.
2. 구현 범위 및 환경
측정 환경
클러스터의 각 노드는 소켓당 16코어, 노드당 2소켓으로 구성됩니다. 최대 4개 노드, 총 128코어를 사용했습니다.
4코어와 8코어 측정은 10코어 단일 소켓 개발용 시스템에서 별도로 수행했습니다. 시스템 구성이 다르므로 서로 다른 시스템에서 얻은 절대 실행 시간은 직접 비교하지 않았으며, 동일한 시스템에서 측정한 순수 MPI와 하이브리드 방식의 상대 성능만 비교했습니다.
구현 범위
공정한 비교를 위해 주요 CPU 계산 구간에 OpenMP 병렬화를 먼저 적용했습니다. 이를 통해 OpenMP 구현 범위의 차이가 하이브리드 방식의 성능을 제한하지 않도록 했습니다.
| 구현 단계 | 성능 변화(8스레드, M6 306k) |
|---|---|
| 난류 및 격자점 루프 병렬화 + 에지(edge) 재번호화 | 55.8초 → 42.7초 (가속비 4.15 → 4.71×) |
| CPU 선형 솔버 OpenMP 병렬화 | 74.0초 → 41.8초 (−43%, 가속비 2.50 → 4.31×) |
암달의 법칙(Amdahl’s law)으로 추정한 직렬 실행 비율은 38%에서 약 13%로 감소했습니다. 따라서 이후 비교를 수행하기에 충분한 수준으로 OpenMP 병렬화가 적용되었다고 판단했습니다.
선형 솔버는 일부 연산만 병렬화했을 때 성능 개선이 제한적이었습니다. SGS 스윕(sweep)만 병렬화한 경우 8스레드에서 실행 시간이 12% 감소했습니다. 희소 행렬–벡터 곱(SpMV)과 벡터 연산까지 병렬화하면 33%, 각 Newton 단계에서 약 30만 개의 5×5 역행렬을 구성하는 대각 역행렬 계산까지 포함하면 43% 감소했습니다.
3. 측정 결과
3.1 코어 수에 따른 상대 성능 변화

| 코어 수 | 순수 MPI | 최적 하이브리드 구성 | 우세 구성 |
|---|---|---|---|
| 4 | 53.24초 | 57.71초 (np2×T2) | MPI(8% 빠름) |
| 8 | 35.93초 | 31.91초 (np4×T2) | 하이브리드(11% 빠름) |
| 32 | 9.76초 | 11.26초 (np8×T4) | MPI(15% 빠름) |
하이브리드 방식은 8코어에서 순수 MPI보다 11% 빨랐지만, 32코어에서는 15% 느렸습니다. 따라서 8코어에서 관측한 성능 우위를 코어 수 증가에 따른 일반적인 경향으로 해석할 수 없습니다.
단일 소켓 개발용 시스템에서 측정한 8코어 조건은 하이브리드 방식이 유일하게 우세한 구간이었습니다. 이 단일 측정 결과만으로 확장 성능의 추세를 판단한 초기 해석은 적절하지 않았습니다.
3.2 스레드 팀 크기에 따른 성능 변화
모든 문제 규모에서 OpenMP 스레드 수가 적은 구성이 더 높은 성능을 보였습니다. 다음은 CRM 3.6M 격자를 32코어에서 실행했을 때의 솔버 구간 측정 결과입니다.
| 구성 | 솔버 구간 | 순수 MPI 대비 실행 시간 |
|---|---|---|
| 순수 MPI np32 | 312.1초 | — |
| 하이브리드 np8×T4 | 348.8초 | +12% |
| 하이브리드 np4×T8 | 396.9초 | +27% |
| 하이브리드 np2×T16 | 501.2초 | +61% |
초기 하이브리드 설계의 목표는 소켓당 MPI 랭크 1개를 배치하는 np2×T16 구성이었습니다. 이 구성은 각 OpenMP 스레드 팀을 하나의 NUMA 도메인에 배치할 수 있지만, 비교한 세 가지 하이브리드 구성 중 실행 시간이 가장 길었습니다.
즉, 동일한 총 코어 수에서는 랭크당 OpenMP 스레드 수가 적을수록 성능이 향상되었습니다. 스레드 수를 1개까지 줄이면 순수 MPI 구성과 동일해집니다.
NUMA 도메인 간 메모리 접근이 성능을 제한한다는 가설은 측정 결과와 일치했습니다. 순수 OpenMP 구성에서 스레드 수를 16개에서 32개로 늘리면 실행 시간이 29.46초에서 30.78초로 증가했습니다. 그러나 MPI 랭크 수를 줄이고 큰 스레드 팀을 구성하는 방식보다, MPI 랭크 수를 늘려 각 스레드 팀의 NUMA 접근 범위를 제한하는 방식이 더 빨랐습니다.
3.3 전처리기 수렴성 개선 효과
MPI 랭크 수를 줄이면 랭크당 서브도메인이 커지고, 이에 따라 랭크 국소 전처리기의 수렴성이 개선될 수 있다는 두 번째 가설을 4노드 128코어에서 검증했습니다. 모든 구성에 동일한 SGS 전처리기를 사용했습니다.
| 구성 | 솔버 구간 | 상대 선형 반복 횟수 |
|---|---|---|
| 순수 MPI 128랭크 | 121.1초 | 1.00 |
| 하이브리드 32랭크×T4 | 127.6초 | 1.00 |
| 하이브리드 8랭크×T16 | 162.3초 | 1.00 |
세 구성의 상대 선형 반복 횟수는 모두 1.00이었습니다. 즉, 순수 MPI 구성에서도 수렴성 저하가 나타나지 않았으며 MPI 랭크 수를 줄여도 추가적인 개선은 없었습니다.
그 원인은 전처리기의 구현 방식에 있습니다. 블록 SGS는 행 범위를 스레드별로 분할한 뒤 각 블록 내부에서만 스윕을 수행합니다. 따라서 전처리기가 처리하는 유효 서브도메인 수는 MPI 랭크 수 × 랭크당 스레드 수이며, 총 코어 수가 같으면 순수 MPI 구성과 동일합니다. 이 특성은 성능 측정 전에 구현 구조를 분석하는 것만으로도 확인할 수 있습니다.
3.4 실행 시간과 강한 확장 효율의 관계
절대 실행 시간과 강한 확장(strong scaling) 효율은 서로 반대되는 순서를 보였습니다.

순수 MPI는 측정 범위에서 절대 실행 시간이 가장 짧았지만 강한 확장 효율은 가장 낮았습니다. 측정된 확장 효율이 더 큰 코어 수에서도 유지된다고 가정하면 약 512코어에서 순수 MPI와 하이브리드 방식의 성능이 역전될 것으로 추정됩니다.
다만 이 외삽은 두 개의 측정점에 근거한 낙관적인 추정입니다. CRM 3.6M 격자를 2,048코어로 분할하면 코어당 절점 수가 약 1,800개에 불과하므로, 성능 역전이 나타나기 전에 문제 크기에 따른 강한 확장 한계에 도달할 가능성이 큽니다. 따라서 본 결과의 유효 범위는 128코어 이하로 한정하며, 그 이상의 코어 수에서는 수천만 절점 규모의 격자를 사용한 추가 검증이 필요합니다.
4. 원인 분석
하이브리드 병렬화의 주된 목적은 MPI 통신량을 줄이는 것이었습니다. 그러나 본 연구에서 사용한 문제 크기와 코어 수 범위에서는 통신이 전체 성능을 지배하는 병목으로 나타나지 않았습니다. 순수 MPI의 병렬 효율은 32코어에서 44~50%, 128코어에서 64%로 측정되었습니다.
MPI 통신량 감소로 얻은 성능 이득보다 스레드 배리어, 거짓 공유, NUMA 메모리 지역성 저하로 인한 추가 오버헤드가 더 컸습니다. 모든 측정 규모에서 작은 스레드 팀이 더 높은 성능을 보였다는 결과가 이를 뒷받침합니다. 본 측정 범위에서는 랭크당 스레드 수가 증가할수록 실행 시간이 증가했으며, 스레드 수가 1개인 순수 MPI 구성이 가장 빨랐습니다.
전처리기 수렴성 개선 효과도 확인되지 않았습니다. 유효 서브도메인 수가 MPI 랭크 수 × 랭크당 스레드 수로 결정되므로, 총 코어 수가 같으면 MPI 랭크 수를 줄여도 전처리기가 처리하는 국소 문제의 크기는 증가하지 않습니다.
5. 성능 계측 시 고려 사항
성능 측정 과정에서 확인한 주요 계측 오류 요인과 그 영향은 다음과 같습니다. 계측 방법이 적절하지 않으면 병렬화 성능을 반대로 해석할 수 있습니다.
| 계측 오류 요인 | 측정 결과에 미치는 영향 |
|---|---|
솔버 구간을 clock()으로 측정 | clock()은 모든 스레드가 사용한 CPU 시간의 합을 반환하므로 스레드 수가 증가할수록 측정값이 커질 수 있습니다. 수정 전에는 병렬 실행이 더 느린 것으로 측정되었지만, 경과 시간 기준 실제 가속비는 4.88배였습니다. |
| OpenMP 스레드 바인딩 누락 | 스케줄러가 여러 스레드를 동일한 물리 코어의 하이퍼스레딩 형제 논리 코어에 배치할 수 있습니다. 본 측정에서는 이로 인해 실제 사용한 물리 코어 수가 절반으로 감소했습니다. |
| 하이브리드 실행 시 CPU 바인딩 누락 | --bind-to none을 사용하면 MPI 랭크별 CPU 친화도(affinity)가 분리되지 않아 여러 랭크가 동일한 물리 코어에 중첩 배치될 수 있습니다. 본 측정에서는 실행 시간이 31.91초에서 93.07초로 증가하여 약 2.9배의 차이가 발생했습니다. |
maxRSS를 이용한 메모리 측정 | 측정값이 최대 메모리를 사용한 단일 프로세스의 값이므로 노드에서 실행되는 모든 MPI 프로세스의 총 메모리 사용량을 나타내지 않습니다. |
ps -C 또는 ps comm으로 프로세스 식별 | 프로세스 이름이 15자로 제한되어 이름이 긴 두 실행 파일을 구분하지 못했으며, 이로 인해 측정값이 모두 0으로 기록된 사례가 있었습니다. |
| 전체 경과 시간만으로 솔버 성능 판단 | 초기화 시간의 차이가 솔버 실행 시간에 포함됩니다. 실제 3만 회 반복 계산에서 초기화 시간이 차지하는 비율은 0.4%였습니다. |
특히 clock()을 사용한 측정 오류는 결과 해석을 완전히 반대로 만들었습니다. 따라서 해당 계측 방식을 수정하기 전에 얻은 결과는 분석에서 제외했습니다.
6. 결론
본 연구에서 사용한 문제와 최대 128코어의 측정 범위에서는 순수 MPI가 MPI–OpenMP 하이브리드 방식보다 높은 성능을 보였습니다. 이러한 결과는 하이브리드 구현에 필요한 추가 개발 및 유지보수 비용을 고려하지 않고 실행 성능만 비교한 것입니다.
주요 CPU 계산 구간과 선형솔버에 OpenMP 병렬화를 적용한 뒤 4, 8, 32, 128코어에서 성능을 측정했습니다. 하이브리드 방식의 성능 우위는 8코어에서만 관측되었으며, 32코어 이상에서는 순수 MPI가 더 빨랐습니다. 또한 현재 전처리기 구현에서는 유효 서브도메인 수가 총 코어 수에 의해 결정되므로, MPI 랭크 수 감소에 따른 수렴성 개선 효과가 발생하지 않았습니다.
OpenMP 병렬화는 CPU 실행 경로의 직렬 실행 비율을 약 38%에서 13%로 낮추는 데 효과적이었습니다. 그러나 동일한 코어를 사용하는 최종 병렬 구성에서는 각 코어에 MPI 랭크를 배치하는 순수 MPI 방식이 대체로 더 높은 성능을 보였습니다.
본 결과는 CPU 기반 CFD 계산에서 순수 MPI 방식이 널리 사용되는 이유를 실험적으로 보여줍니다. 측정 범위에서는 랭크당 스레드 수가 증가할수록 스레드 동기화와 메모리 접근 관련 오버헤드가 증가했으며, 랭크당 스레드 수가 1개인 구성이 최적이었습니다.
유사한 결과는 선형대수 라이브러리 PETSc에서도 확인할 수 있습니다. PETSc는 MPI와 스레드를 결합한 하이브리드 방식을 검토했으나, 코드 복잡도 증가에 비해 성능이 MPI-everywhere 방식보다 낮은 경우가 많아 해당 지원을 제거하고 MPI 중심 방식을 사용하고 있습니다(Frustrated with MPI+Threads?, 2024). 또한 2016년 PETSc 미팅에서는 To thread or not to thread? Why PETSc favors MPI-only라는 제목으로 관련 내용이 발표되었습니다.
반면 대규모 병렬 환경에서는 MPI 랭크 수를 줄여 랭크당 더 큰 서브도메인을 유지하는 하이브리드 방식이 유리하다는 PETSc 기반 연구도 보고되었습니다(arXiv:1303.5275). 이는 3.4절에서 관측한 강한 확장 효율의 차이와 일관된 결과입니다. 따라서 순수 MPI와 하이브리드 방식의 상대 성능은 문제 크기와 병렬 규모에 따라 달라질 수 있으며, 본 글의 결론은 실제로 검증한 128코어 이하의 범위로 한정합니다.
