• 검색 결과가 없습니다.

실제 응용 코드의 컴퓨팅 모델별 테스트

응용 NVIDIA GPU Xeon Phi 4 Gromacs 분야동역학 오픈소스 Xeon Phi: Native

NVIDIA GPU: CUDA 구현물 5 Lammps 분야동역학 오픈소스 Xeon Phi: Offload

NVIDIA GPU: CUDA 구현물 10 WRF 대기과학 오픈소스 Xeon Phi: Native/Symmetric

NVIDIA GPU: OpenACC 구현물

- 응용 코드 및 in-house 이식성 및 성능테스트 요약

OpenACC

- BMT를 통한 컴퓨팅 모델별 이식성 및 성능을 평가함으로서 차세대 컴퓨팅시스 - VASP, GROMACS는 Xeon Phi대비 각

15.93배, 1.79배 빠름

- LAMMPS(offload)는 CUDA 대비 1.3배 빠 (Charmm, Gayberne 포텐셜만 지원)

<부록: Xeon Phi에서의 병렬프로그래밍 모델에 따른 성능 비교>

※ C/C++언어로 병렬 프로그램 작성시 가장 흔하게 사용하는 세가지 프로그래밍 모델인 OpenMP, Intel Cilk Plus, Intel TBB 이용해서 Xeon Phi에서의 성능 비교를 수행

1. 3개 프로그래밍 모델 소개 1.1 OpenMP

OpenMP는 여러개의 프로세스가 공유된 메모리를 참조하는 환경에서 다중 스레드 병렬 프로그래밍을 위한 표준 스펙으로OpenMP 3.0의 출시 이후에는 작업의 관리 기능 또한 제공하고 있다. OpenMP의 주요 동기요인은 성능, 확장성, 이식성, 표준 성을 목표로 한다. 그리고 C, C++(#으로 시작), Fortran(90에서는 !$로 시작)을 지원 하고 있다.

OpenMP를 주로 사용하는 방법은 프로파일링을 통해 시간을 많이 차지하는 부분을 식별하고 해당 프로그램에서 사용되는 의존성, 데이터의 유효 범위를 예측한 다음 지시어의 설정을 통해 병렬 처리를 하여 성능 향상을 얻는 방식으로 진행된다.

․ OpenMP 구조

OpenMP의 구조

-Directives(컴파일러 지시자)

쓰레드 사이의 작업 분담, 통신, 동기화를 담당을 한다. 컴파일러가 지시자를 참고하 여 다중 쓰레드 코드를 생성하게 된다. Work-Sharing 지시자는 상세히 설명할 필요 가 있어서 아래에 새로운 단락으로 빼서 설명하고 여기서는 동기화, 데이터 유효 범위 지시자를 설명한다. OpenMP 프로그래밍은 컴파일러가 모두 알아서 처리하는 게 아니라 동기화 및 의존성 제거 등의 작업은 사용자가 직접 소스코드에 기술해

주어야 하는 어려움을 지니고 있다.

-Runtime Library

병렬화에 직접 참여는 하지 않지만 실행 환경에서 병렬 매개 변수(참여 스레드의 개수, 번호 등)의 설정과 조회를 통해 병렬화 정보를 변경 조회할 수 있다.

-Environment Variables

Runtime Library와 중복되는 부분이 많지만 우선순위는 동일한 지시자를 반복 사용 했을 경우 Runtime Library가 우선된다. 주요한 일은 실행 시스템의 병렬 매개 변수 (스레드 개수 등)를 설정해 실행시에 제어를 한다.

․ 프로그래밍 모델 -Fork-Join 모델

스레드가 병렬 구문를 만나면 스레드는 그 자신을 포함한 추가적인 스레드(0개 이 상의)로 이루어진 쓰레드 팀을 만든다(Fork). 병렬 구문를 만난 스레드는 팀의 마스 터 쓰레드를 호출 하게 되고(Join) 다른 스레드들은 팀의 slave 스레드라고 불리어진 다.

Fork-Join 방식의 개념도

-Work-Sharing 모델

같은 작업을 쓰레드별로 실행하는 것이 아니라 작업을 분할해서 쓰레드별로 나누어 서 실행하는 것을 말한다.

• for

바로 뒤에 오는 for 루프의 반복 실행을 쓰레드에 분배한다. 그리고 루프 끝에 암시 적 장벽(동기화)이 존재한다. 이를 피할려면 nowait 사용하면 된다.

데이터 병렬화시에 활용된다.

• sections

독립된 여러 개 작업을 각 스레드에 분산 실행한다. 그리고 sections 구문 끝에 암

시적 장벽(동기화)이 존재하고 장벽을 피하기 위해서는 nowait를 사용한다. 주로 기 능적 분할에 이용된다.

• single

병렬 영역 내부에서 하나의 스레드만을 이용해 작업 수행한다. single 지시어자 가 장 먼저 접근한 스레드에 작업 할당된다. single 구문 끝에 암시적 장벽(동기화)이 존재한다.마찬가지로 이를 피하기 위해서는 nowait를 사용하면 된다. 병렬 영역 내 에서의 입/출력 수행에 주로 사용된다.

• Task

OpenMP 버전 3.0 이상부터 추가된 지시자며, 수행할 작업을 한번의 호출로 진행되 는 작업이나 한번의 구문으로 실행 가능한 작업 단위 나눈다. 태스트 실행은 작업 스케쥴링이 적용된다.

1.2 Intel Cilk Plus

인텔 Cilk Plus는 C/C++ 기반의 병렬 프로그래밍 언어이다. 3개의 키워드로 태스크 /루프 병렬성을 기술할 수 있으며, 벡터 병렬성도 배열 표기법을 확장하여 표현한 다. 무엇보다 Cilk Plus의 런타임 스케줄러는 효율적으로 병렬 작업을 CPU를 할당한 다.

․ Cilk Plus의 태스크 병렬성 지원: cilk_for/spawn/sync

Cilk Plus는 크게 태스크 (혹은 루프) 수준 병렬성과 데이터 수준 병렬성(여기서는 벡터 형태로)을 지원하는 것으로 구분할 수 있다. 먼저, 태스크 수준 병렬성 지원에 대해 알아보자. Cilk Plus는 cilk_for, cilk_spawn, cilk_sync라는 3개의 키워드로 태스 크 병렬성을 표현한다.

Cilk 구문 이해를 위한 예제: cilk_spawn으로 두 병렬 작업을 생성하고 이들이 완료될 때까지 기다린 뒤 다음으로 진행

-cilk_spawn

함수 호출 구문 앞에 이 키워드를 쓰면, 뒤따르는 함수 호출이 호출자와 함께 동시 에 실행될 수 있음을 런타임 시스템에게 알린다. 그런데 반드시 항상 병렬 수행이 된다는 보장은 하지 않는다. 이 부분은 런타임 스케줄러가 알아서 판단한다. 보다 쉽게 설명하면 논리적인 병렬 작업이 생성됨을 알리는 것으로 프로그램의 논리적인 실행 흐름을 두 갈래로 나누는 것이다. 포크(fork)에 비유될 수 있다. 그렇지만 반드 시 물리적인 스레드가 생성되는 것은 아니다.

-cilk_sync

배리어(barrier) 연산으로 현재 수행중인 함수에서 cilk_spawn으로 생성한 병렬 작업 들이 모두 종료될 때까지 기다리게 한다. 그런 뒤에 다음 구문을 실행한다.

-cilk_for

for 구문의 병렬 처리 버전으로 for 구문의 순환이 서로 병렬로 처리될 수 있음을 기술한다.

위의 그림 예제는 cilk_spawn으로 두 병렬 작업을 생성하고 이들이 완료될 때까지 기다린 뒤 다음으로 진행한다.

1.3 Intel TBB

인텔 스레딩 빌딩 블록(Intel Threading Building Blocks)은 C++로 병렬 프로그램을 구 현할 때 사용할 수 있는 일종의 라이브러리이며, 풍부하고 완벽한 방법론을 제 공함으로써 스레드 처리에 대한 전문 지식이 없이도 멀티코어 프로세서 시스템의 성능을 향상시킬 수 있도록 도와준다. 스레딩 빌딩 블록은 단순히 기존의 스레드를 대체할 수 있는 라이브러리 를 제안하는 정도가 아니라 ‘태스크(task)’개념을 기반으 로 하는 높은 수준의 병렬처리 기술이라고 할 수 있으며 성 능(performance)과 확 장성(scalability)을 목표로 한다.

Intel TBB의 특징

인텔 TBB 태스크 스케줄러는 사용자를 위해 로드 밸런싱을 수행한다. TBB의 스케줄 러는 프로그램을 여러 작은 태스크로 나눈 후 최상의 확장성을 구현할 수 있도록 태스크를 스레드에 고르게 할당하며 구현하는 방식은 C++에서 이미 사용 중인 방 법을 확장하는 방식으로 구현된다. Intel TBB는 parallel_for, parallel_ while, parallel_reduce, pipeline, parallel_sort, parallel_scan 등 일부 함수와 템플릿을 컨커 런트 컨테이너 (concurrent container)와 함께 제공해 코드에서 병렬성을 개발할 때 생산성을 향상시킨다.

2. 3가지 프로그래밍 모델을 사용한 Intel Xeon Phi Coprocessor의 성능 벤치마크

성능평가를 위한 코드는 모두 C++로 작성되었고 실행파일은 MIC에서 native 방식 으로 가동한다. 각각의 코드를 실행시키려면 우선 ssh를 통해서 Xeon Phi에 각각의 실행 파일과 실행에 필요한 라이브러리를 함께 복사하는데 OpenMP 코드를 위해서 는 libiomp5.so, Cilk Plus 코드를 위해서 libcilkrts.so.5, TBB를 위해서 libtbb.so.2 라 이브러리를 MIC에 복사하며 라이브러리들의 위치는 export LD LIBRARY PATH=./:$LD LIBRARY PATH에 미리 설정되어 있어야 한다. 프로그램들을 컴파일 할 때, TBB 코드는 –ltbb, 오픈엠피는 –openmp 컴파일 옵션과 함께 컴파일 되어야 하며 제온파이에서 네이티브 모드로 프로그램을 실행시키기 위해서 icpc(icc) 14.0.2 버전에서 -O2 –mmic –no-offload 컴파일 옵션을 사용하였다. 모든 가속화 비율은 코드의 실행시간에 대비해서 계산되었다.

각 프로그래밍 모델의 병렬화 성능 비교를 위해서 세 가지 단순한 프로그램을 사용 했으며 각각은 1) 피보나치 수열 계산 알고리즘 2) Merge Sort 알고리즘 3) 행렬 곱셈 알고리즘 과 같다.

이 실험에서 중요한 부분 중 하나는 각각의 프로그래밍 모델로 제작된 어플리케이 션을 MIC에서 단독으로 실행하는 경우(싱글프로그래밍)와 동시에 실행하는 경우(멀 티프로그래밍)의 두가지의 결과를 비교하고 병렬화 성능의 지표중 어느 것이 멀티 프로그래밍 상황에서의 성능을 예측하기에 적합한지 확인하는 것으로 이를 확인하 기 위해 각각의 프로그램은 단독으로 실행되기도 하였고 멀티프로그램 환경에서 실 행되기도 하였다.

2.1 싱글 프로그래밍 환경

2.1.1 피보나치 수열 계산 알고리즘

첫 번째 테스트는 병렬 컴퓨팅 예제로 자주 사용되는 병렬 피보나치 수열 코드이 다. 병렬화 성능을 테스트 함에 있어서 피보나치 수열의 단순 재귀 패턴은 병렬화 하기 쉽고 부하 불균형이나 작업 부하등을 테스트 하기에 적합하다. 이 연구에서는 피보나치 수열의 47번째 숫자까지를 계산하기 위하여 피보나치 힙 방식의 수열 계 산 알고리즘을 사용하였다.

피보나치 힙 방식의 예: tree depth가 0,1,3인 세개의 나무가 있고 3개의 꼭지점이

파란 원으로 표시되어 있다. 이 힙의 잠재력은 3 tree + 2*vertice-number = 9

좋은 성능을 얻기 위해서는 병렬화 하는 작업의 크기가 너무 작거나 반복문이 지나 치게 많이 반복되는 것을 피해야 하기 때문에 컷오프 기준을 설정해야 하는데 생성 되는 피보나치 수열의 tree-depth에 따라 개의 작업이 생성되는데 컷오프 기준에 따라 tree-depth가 제한된다.

아래 그림에 각각의 프로그래밍 모델에 대한 성능 테스트 결과가 있다. (a) 는 컷오 프를 2048로 고정한 후 실행한 결과(tree-depth = 11)이며 그래프에서 볼 수 있듯

아래 그림에 각각의 프로그래밍 모델에 대한 성능 테스트 결과가 있다. (a) 는 컷오 프를 2048로 고정한 후 실행한 결과(tree-depth = 11)이며 그래프에서 볼 수 있듯

관련 문서