1.47k likes | 1.99k Views
고 급 병 렬 프 로 그 래 밍 . 목 표. KISTI 가 현재 보유하고 있는 IBM 시스템에서 순차 및 병렬 프로그램의 성능을 최적화 시키기 위해 필요한 배경 지식을 습득하고 최적화와 관련해서 사용할 수 있는 도구의 사용법을 익히도록 한다. 차 례. I. 고급 병렬 프로그래밍 개요 4 II. IBM 시스템에서 성능 최적화 31 III. 병렬 프로그래밍 관련 도구 106 IV. 참고 자료 및 부록 145. 제 I 장. 고급 병렬 프로그래밍 개요
E N D
고 급 병 렬 프 로 그 래 밍
목 표 KISTI가 현재 보유하고 있는 IBM 시스템에서 순차 및 병렬 프로그램의 성능을 최적화 시키기 위해 필요한 배경 지식을 습득하고 최적화와 관련해서 사용할 수 있는 도구의 사용법을 익히도록 한다.
차 례 I. 고급 병렬 프로그래밍 개요 4 II. IBM 시스템에서 성능 최적화 31 III. 병렬 프로그래밍 관련 도구 106 IV. 참고 자료 및 부록 145
제 I 장 • 고급 병렬 프로그래밍 개요 • 병렬 프로그램의 성능최적화 • 일반적인 프로그램의 튜닝 • 가이드라인 • 하이브리드 병렬 프로그래밍
순차 프로그램의 실행시간 병렬 프로그램의 실행시간(n개 프로세서) 24 8 ts tp S(n)= = S(4)= = 3 병렬 프로그램의 성능최적화 (1/5) • 성능향상도(speed-up) S(n) • 순차 프로그램에 대한 병렬 프로그램의 성능향상 정도 • 실행시간(elapsed time)은 벽시계시간(wall clock time) 기준 • 실행시간이 24시간소요되는 순차 프로그램을 병렬화, 4개 프로세서를 사용해서 8시간 만에 결과를 얻을 수 있게 된 경우의 성능향상도
ts fts + (1-f)ts/n 1 f+ (1-f)/n S(n)= = ts tp = Sideal = 1 f 병렬 프로그램의 성능최적화 (2/5) • Amdahl’s Law • ‘병렬프로그램의 성능향상도는 순차 프로그램에서 병렬화 가능한 부분의 비율에 의해서 결정된다.’ • 이상(ideal) 성능향상도 Sideal tp = fts + (1-f)ts/n 여기서, f는 병렬화 불가능한 부분이며 0 ≤ f ≤ 1 만일, 프로세서를 충분히 많이(n ∞) 사용한다면,
20 80 Serial 1 0.2 + (1-0.2) / 4 = 2.5 S(4)= 20 20 Parallel process 1 process 2 process 3 cannot be parallelized process 4 can be parallelized 병렬 프로그램의 성능최적화 (3/5) • 이론 성능향상도 • f = 0.2, n = 4
20 80 Serial 20 20 parallel process 1 cannot be parallelized process 2 can be parallelized process 3 communication overhead process 4 Load unbalance 병렬 프로그램의 성능최적화 (4/5) • 실제 성능향상도 • 실제의 경우 통신부하, 부하분산 불균형이 성능향상도에 영향을 미침
ts tpx n S(n) n E(n)= = [ x 100 (%) ] 병렬 프로그램의 성능최적화 (5/5) • 병렬 프로그램의 효율(efficiency) E(n) • 프로세서 사용 개수에 따른 병렬 프로그램의 성능 효율 • 4개의 프로세서로 3배의 성능향상이 있는 경우 0.75 혹은 75%의 병렬 프로그래밍 효율 • 병렬 프로그램의 성능 향상을 위한 가이드라인 • 순차 프로그램에서 병렬화 될 수 있는 부분을 증가시킴 • 병렬 프로세스들의 부하분산을 고르게 함 • 통신에 소요되는 시간을 최소화 시킴
일반적인 튜닝 가이드라인 (1/14) • 코드의 핸드 튜닝 • 지역변수와 전역변수 • 전역변수는 변수의 범위(scope) 특성 때문에 컴파일러의 최적화 방해 • 최대한 자동변수(automatic variable)과 같은 지역변수를 많이 사용 • 포인터 • 최적화 과정에서 포인터를 쫓는 것은 어렵거나 불가능하기 때문에 대부분의 메모리 관련 최적화를 방해 • 수식의 표현 • Fortran 컴파일러는 동일 수식은 잘 인지하지만, 교환법칙을 이해하지는 못함 • x = a + b + c + d • y = a + c + b + d • 가능하면, 동일한 수식을 표현할 때의 변수들은 동일 순서로 배열
일반적인 튜닝 가이드라인 (2/14) • 형 변환 • 정수와 실수 간의 형 변환을 강제하지 말 것 • 루프 변수로 부동소수를 사용하지 말 것 • 루프의 튜닝 • Do 루프의 크기를 관리하기 쉽게 유지 • 데이터를 순차적으로 접근 – 스트라이드(stride) 1 • 이동 불가능한 루프 안의 IF문 수를 최소화 • 루프 안에서의 서브루틴/함수 부르기를 피할 것 • 배열의 subscript(특히 루프 변수) 단순화 • 정수형 루프 변수 사용 • 루프 안에서 피해야 할 구문 • - GOTO, STOP, PAUSE, RETURN 같은 흐름 관련 구문 • - 루프의 최적화를 방해하는 데이터의 EQUIVALENCE 구문 • - LOGICAL*1, BYTE, INTEGER*1, INTEGER*2, REAL*16, COMPLEX*32, CAHRACTER, INTEGER*8 같은 최적화 불가능한 데이터 형을 피할 것
일반적인 튜닝 가이드라인 (3/14) • 성능에 치명적인 루프에서 피해야 할 것들 • 큰 스트라이드의 데이터 접근 • 적은 수의 반복계산을 수행하는 루프 • I/O 문의 포함 • 루프 튜닝의 예 • IF 문의 제거 • 경계조건 IF 테스트 • 반복적인 내재(intrinsic) 함수의 계산 • 나눗셈을 역수의 곱셈으로 치환 • 2의 승수의 배수를 갖는 배열 문제
일반적인 튜닝 가이드라인 (4/14) • IF 문의 제거
일반적인 튜닝 가이드라인 (5/14) • 경계조건 IF 테스트
일반적인 튜닝 가이드라인 (6/14) • 반복적인 내재(intrinsic) 함수의 계산
일반적인 튜닝 가이드라인 (7/14) • 나눗셈을 역수의 곱셈으로 치환
일반적인 튜닝 가이드라인 (8/14) • 2의 승수의 배수를 갖는 배열 문제
일반적인 튜닝 가이드라인 (9/14) • 튜닝된 코드의 사용 • 이미 튜닝된 작업에 시간을 허비하지 말 것 • 배열연산, 선형 대수 방정식의 풀이, BLAS 함수, FFT, convolution 등과 같은 표준 함수들을 코드에서 사용한다면 대응되는 ESSL 함수를 사용하도록 코드를 수정 • 성능 모니터링 • POWER3, POWER4 프로세서는 하드웨어 성능 모니터링 장치 포함 • 프로세서의 동작이나 명령의 처리와 관련된 자세한 정보를 담은 카운터에 대한 접근을 OS 차원에서 제공 • Performance Monitor API 패키지 $ lslpp –l bos.pmapi.* • Performance Monitor API와 HPM Toolkit을 이용해서 프로그램의 성능 모니터링에 필요한 관련 카운터의 정보를 얻을 수 있음
일반적인 튜닝 가이드라인 (10/14) • PM API 테스트 $ xlc -O3 -c -o pm_subroutines.o pm_subroutines.c $ xlf -O3 -o pm_test pm_subroutines.o -lpmapi -L/usr/pmapi/lib pm_test.f * Counter 1 – L3, 2 – memory, 3 – L3.5, 4 – L2, 5 – L2P1S, 6 – L2P2S, 7 – L2P1, 8 – L2P2
일반적인 튜닝 가이드라인 (11/14) • I/O를 위한 튜닝 • 가능한 한 I/O를 제거하거나 줄여라 • I/O가 프로그램의 병목(bottleneck)이라면 우수한 하드웨어나 소프트웨어를 사용하는 것이 최선의 튜닝 방법 • High-performance storage arrays, 스트라이핑, asynchronous I/O • Asynchronous I/O • 계산과 I/O가 동시에 실행될 수 있도록 OS(AIX)가 지원 • Asynchronous I/O를 위해서는 프로그램의 수정이 필요 함 • Fortran – OPEN() 문에서 ASYNC 인자를 이용, asynchronous read/write를 위한 wait 필요 • C – asynchronous I/O는 unbuffered I/O에서만 지원, Fortran의 경우보다 복잡함 • Direct I/O : 장치와 어플리케이션 버퍼들의 사이 중간(intermediate) 버퍼링을 하지 않고 I/O 데이터를 전송
일반적인 튜닝 가이드라인 (12/14) • Fortran I/O • I/O 서브시스템에 대한 호출 횟수를 줄임 • DIMENSION A(N,N) • Case 1. Best. N*N개 값의 1개 레코드 • WRITE(1) A • Case 2. N개 값의 N개 레코드 • DO I = 1, N • WRITE(1) (A(J,I), J = 1, N) • ENDDO • Case 3. Worst. 1개 값의 N*N개 레코드 • DO I = 1, N • DO J = 1, N • WRITE(1) A(J,I) • ENDDO • ENDDO • 순차적으로 읽거나 쓸 때 길이가 긴 레코드를 이용, 적어도 100KB이상 2MB 혹은 그 이상 단위의 I/O가 효율적
일반적인 튜닝 가이드라인 (13/14) • Formatted 대신 Unformatted I/O 사용 : binary decimal 변환의 오버헤드 감소 • Sequential 대신 direct file 사용 : Fortran 레코드 길이와 오버플로우 체크를 피함 • 계산과 I/O 작업을 겹쳐서 수행하기 위해 asynchronous I/O를 사용 • AIX는 자동적으로 여유 메모리를 파일 I/O의 버퍼로 사용 큰 크기의 임시 파일을 sequential하게 쓰고 처리 과정의 추후 단계에서 그 파일을 다시 읽어야 할 필요가 있다면, direct access 파일로 만들고 끝부분의 레코드를 먼저 읽도록 시도. 이상적으로는 역순으로 읽어라 메모리 버퍼에 남아 있는 파일 부분에 대해서 디스크를 읽지 않고 I/O 작업 가능 • 핫스팟(hot spot) 찾기 – 프로파일링 • 프로파일링 • 프로그램의 실행 중 전체 코드에 걸쳐서 CPU 시간이 어떻게 사용되었는지를 알려 줌 • 프로그램을 가장 효과적으로 튜닝할 수 있는 서브루틴이나 루프를 밝혀 줌
일반적인 튜닝 가이드라인 (14/14) • 특정 프로파일링은 프로그램의 특정 실행과 연관되어 있으며, 같은 프로그램이라도 입력 파일에 따라서도 다른 프로파일링 결과를 나타냄 • 프로파일링 도구 • prof, gprof : 프로시져 수준의 프로파일링 • tprof: 10 milliseconds 단위로 프로그램의 실행을 가로챌 수 있는 AIX trace 장치 사용, 결과 trace 테이블로부터 소스 코드의 라인별 10 milliseconds 틱(tick)의 수를 표시 • tprof • -g 옵션을 추가하고 프로그램 컴파일 • tprof 명령을 이용해서 프로그램을 실행 • $ tprof –p myprog –x “myprog params” • __myprog.all : 프로그램을 실행시키는데 관여한 모드 프로세스 정보 및 각 프로세스와 연관된 시간 틱 수 등 표시 • __t.myprog.f : -g 옵션을 사용한 경우만 생성, 소스 코드의 라인별 틱 수를 표시 • xprofiler • prof, gprof, tprof의 기능을 포함한 XGUI 프로파일러
하이브리드 병렬 프로그래밍 (1/7) • 동기와 필요성 • 성능 향상을 위해서 • 노드 내에서의 MPI 사용으로 인한 통신의 초기 지연 방지 • 다중 프로세스 실행으로 인해 발새하는 노드 내에서의 불필요한 데이터 복사 방지 • 노드간의 MPI 콜로 인한 통신 지연 감소 • 전체적인 메시지 패싱 작업 감소 • 메모리 사용을 줄이기 위해서 • 다중 프로세스 실행으로 인해 노드 내에서 중복되는 데이터 복제 방지
하이브리드 병렬 프로그래밍 (2/7) • 하이브리드 병렬 프로그래밍 과정
병렬화 접근 방식의 형태 Fine Grained main program ! MPI initialization .... ! CPU intensive loop !$OMP PARALLEL DO do i=1,n !work end do .... end Coarse Grained main program !MPI initialization !$OMP PARALLEL .... do i=1,n !work end do .... !$OMP END PARALLEL end 하이브리드 병렬 프로그래밍 (3/7)
하이브리드 병렬 프로그래밍 (4/7) • 병렬화 접근 방식에 따른 특성 • Fine Grained • 적용하기 용이 • OpenMP 지시어를 사용하게 되고, 그에 따라 fork-join 되기 때문에 스레드 생성 및 동기화 인해 발생하는 부하가 성능 저조에 영향 • Coarse Grained • 상대적으로 복잡하므로 적용하는데 많은 시간이 소요 됨 • 스레드 생성으로 인한 부하가 적음
하이브리드 병렬 프로그래밍 (5/7) • Fine Grained 접근 방식
하이브리드 병렬 프로그래밍 (6/7) • Coarse Grained 접근 방식 • MPI 코드에서 시작 • 각 MPI 테스크가 시작 부분에서 스레드들을 한번 생성 • 초기화 같은 순차 작업이나 MPI 콜들은 MASTER 혹은 SINGLE 지역에서 수행 • 메인 배열은 전역변수 • 작업 분배 : 각 스레드는 그 스레드 번호(omp_get_thread_num())에 따라 배열 데이터의 조각을 담당. 1차원 블록 분배. • OMP DO를 사용치 않음 • 변수 및 함수의 유효 범위(scope)와 동기화(synchronization)에 주의
하이브리드 병렬 프로그래밍 (7/7) • 적용 경우 • MPI로 확장성이 우수하지 않는 경우 • 동적 부하 분산(dynamic load balancing)을 이용할 수 있는 경우 • Fine-grained 병렬성을 갖고 있는 경우 • 중복된 데이터를 갖고 있는 경우 • 노드 내 통신에 적합한 MPI가 없는 경우 • 현실적 제약 • 성능 향상이 크지 않거나 저하 • 프로그래밍이 어려움
제 II 장 • IBM 시스템에서성능 최적화 • POWER4 프로세서를 사용하는 KISTI IBM 시스템에서의 최적화 방법 • POWER4 시스템을 위한 튜닝, 컴파일러를 이용한 최적화, 병렬 프로그래밍 테크닉
POWER4 시스템 (1/11) • IBM POWER 프로세서의 발전 • POWER1 • 1990년, 25MHz, 8KB I-캐시, 64KB D-캐시, FMA, 50MFlops • POWER2 • 1993년, 55-66.5MHz, 1996년 P2SC 135~160MHz, 256KB D-캐시, 이중 FPU/FXU, 하드웨어 제곱근, 650MFlops • PowerPC • 1993년, IBM+Motorola+Apple, POWER instruction+SMP, 601/603/604/604e로 발전, POWER3/4의 기반 • RS64 • 1997년, 64비트, 24-way SMP, 상용(1FPU), 750MHz, Copper/SOI기술 • POWER3 • 1999년, P2SC+PowerPC, FP성능+SMP+64비트, 200/375/450MHz, 16-way SMP, Copper/SOI기술, ASCI White, 서울대
POWER4 시스템 (2/11) • IBM POWER4 프로세서의 특징 • 2001년 발표 • 2 마이크로프로세서 코어 • MCM (Multi-Chip Module) : 4 칩 / 8 코어 • SCM (Single-Chip Module) : 1 칩 / 2 코어 • CPU 속도: 1.1 / 1.3 / 1.7 / 2.0 GHz • 32웨이 SMP 가능: 4 MCM • 64비트 • 캐시: L1 (코어) / L2 (칩) / L3 (모듈)
POWER4 시스템 (3/11) • POWER4 프로세서 칩
POWER4 시스템 (4/11) • POWER4 프로세서 코어
POWER4 시스템 (5/11) • POWER4 프로세서 실행 파이프라인
POWER4 시스템 (6/11) • POWER4 메모리 체계의 구조와 용량
POWER4 시스템 (7/11) • MCM과 POWER4 메모리 체계의 연결
POWER4 시스템 (8/11) • MCM과 MCM 사이의 연결
POWER4 시스템 (9/11) • 메모리 체계와 MCM들 사이의 연결
POWER4 시스템 (10/11) • 하드웨어 데이터 프리패치(prefetch) • 캐시 미스(miss)의 영향 • 각 메모리 구성 요소로부터 1워드(word) 로드(load) 소요 시간 L1 : 1 CPU 사이클, L2 : ~12 CPU 사이클 L3 : ~100 CPU 사이클, 메모리 : ~300 CPU 사이클(latency 포함)
POWER4 시스템 (11/11) • POWER4 시스템 I/O 구조
수치 어플리케이션을 위한 튜닝 (1/2) • 수치 어플리케이션을 위한 튜닝 과정 • I/O가 프로그램의 중요 부분이라면 이 부분을 따로 튜닝하는 것이 중요하며 계산 부분의 튜닝과는 별개의 과정임 • 최고의 컴파일러 최적화 옵션을 사용 • 프로파일링을 통해서 프로그램에서의 핫스팟 찾기 • 이 과정은 매우 중요하며, 프로그램에서 자주 실행되지 않는 부분을 튜닝하는데 시간을 허비하지 말 것 • 가능하면 MASS 라이브러리나 ESSL 혹은 다른 성능에 최적화된 라이브러리를 사용 • 일반적으로 사용하는 프로그램의 작성과 관련된 튜닝 가이드라인을 따라서 프로그램을 튜닝 • POWER4 시스템에 적합하도록 핸드 튜닝
수치 어플리케이션을 위한 튜닝 (2/2) • 수치 어플리케이션의 핸드 튜닝 • 부정적 요인을 피하기 • 수치 연산 장치보다 느린 메모리 시스템의 부정적 효과를 피하거나 최소화 시키기 위한 방편 • 스트라이드 최소화 • 데이터 프리패칭의 흐름이 잘 이루어지도록 튜닝 • 캐시의 세트조합성(set associativity) 구속을 회피 • 데이터 캐시 블로킹(blocking) • 긍정적 요인을 이용 • 특히, 부동소수점 연산장치와 같은 수치 연산 장치의 활용 효율을 극대화 시키기 위한 방편 • 안쪽 루프의 언롤링(unrolling) : 루프의 반복 당 독립 연산의 수를 증가시켜 파이프라인을 채움 • 바깥쪽 루프의 언롤링 : 로드(load), 스토어(store)에 대한 연산 명령어의 비율을 증가시켜 루프의 성능이 데이터의 이동보다 연산에 의존토록 조정
캐시 메모리를 위한 튜닝 (1/17) • 레벨 1, 2, 3 캐시 • L1 명령어 캐시 • 64KB / 프로세서 • 수치 어플리케이션의 경우 보통 처리해야 할 데이터의 양이 명령어의 흐름이 차지하는 것보다 훨씬 크기 때문에 L1 명령어 캐시는 큰 영향을 미치지 않음 • 엑티브(active) 루프가 너무 많은 명령어를 포함하지 않도록 주의 • 엑티브 루프 : Fortran의 DO루프, C의 for루프 • L1 데이터 캐시 • 32KB / 프로세서 • FIFO(first-in-first-out) 교체 알고리즘의 2웨이 세트 조합성 • L2 캐시, L3 캐시 • L2 : 1440KB / 칩, L3 : 128MB/MCM • 캐시의 일관성(coherency)은 L2 레벨에서 시스템 전체에 걸쳐 유지
캐시 메모리를 위한 튜닝 (2/17) • 일반적인 캐시 고려 사항 • L2 캐시에서 L1 캐시로의 대역폭(bandwidth)은 부동소수점 연산장치에 데이터를 원활히 공급해 주기에 충분 • 성능관점에서 L1 캐시와 L2 캐시의 가장 큰 차이점은 지연(latency) • L1 캐시와 부동소수점 레지스터(register) 사이의 지연 : ~4 cycles • L2 캐시와 부동소수점 레지스터 사이의 지연 : ~14 cycles • 조밀(dense) 행렬 연산에 대한 추천 • L2 캐시에 대한 데이터 블로킹 • L1 캐시에 대한 데이터 접근 조직화 • L1 데이터 캐시의 구조 • 캐시 라인(cache line) • 개념상 메모리 혹은 캐시를 128바이트 단위의 연속으로 나눈 것 • 메모리와 캐시 사이에서의 데이터 전송 단위
캐시 메모리를 위한 튜닝 (3/17) • 세트 조합성(set associativity) • 2웨이 세트 조합성을 갖는 128개의 합동(congruence) 클래스 구조 • 2 x 128 x 128바이트 = 32KB
캐시 메모리를 위한 튜닝 (4/17) • POWER4 프로세서의 L1 데이터 캐시의 세트 조합성 관련 특성 • 합동(congruence) 클래스 : L1 데이터 캐시 구조 그림에서의 동일 칼럼을 이루는 캐시 라인들의 집합 • 2웨이 세트 조합성, 128 합동 클래스 • 메모리와 캐시 사이의 로드/스토어는 같은 합동 클래스 상의 캐시 라인들 사이에서만 허용 • 메모리 상의 128바이트 크기 메모리 라인은 2곳의 캐시 라인 중 한 곳으로만 로드 가능 • 실질적으로 유효한 L1 데이터 캐시의 크기를 감소시키는 효과 • 16KB의 배수로 메모리 요소를 접근할 경우 POWER4 프로세서 L1 데이터 캐시 활용 면에서 최악의 상황 초래
캐시 메모리를 위한 튜닝 (5/17) • 스트라이드 최소화 • 스트라이드 값이 1 혹은 작음으로 인한 데이터의 순차 접근은 캐시의 활용 및 하드웨어 프리패칭 흐름 관점에서 이득 • 데이터가 캐시 라인에 로드되면 16개의 배정도(double precision) 워드(word) 혹은 32개의 단정도(single precision) 워드가 한 개의 캐시 라인을 차지, 데이터 접근 단위를 나타내는 스트라이드 값이 배정도의 경우 16, 단정도의 경우 32인 경우 한 개의 캐시 라인에서 한 개의 워드만을 접근해서 사용하게 되고, 추후 동일 캐시라인 내의 데이터를 접근하려 할 때 캐시 미스(miss) 발생 확률 높음 • 데이터에 대한 스트라이드 1 혹은 –1의 순차접근만이 8개의 하드웨어 프리패칭 흐름 중 하나를 가동할 수 있음 • Fortran의 경우 열 우선순서 접근, C의 경우 행 우선 순서 접근이 유리함
캐시 메모리를 위한 튜닝 (6/17) • 스트라이드 최소화 예 • Fortran DO J = 1, N DO I = 1, N A(I,J) = A(I,J) + B(I,J)*C(I,J) ENDDO ENDDO • C for (i=0; i<n; i++) for (j=0; j<n; j++) { a[i][j] += b[i][j]*c[i][j]; }