본문 바로가기
카테고리 없음

Intel® VTune™ Amplifier XE 2011을 이용하여 OpenMP 성능 분석을 해보자.

by Leo 리오 2012. 8. 10.
반응형

Intel® VTune™ Amplifier XE 2011을 이용하여 OpenMP 성능 분석을 해보자.







Amplifier Lightweight Hotspots로 측정하면




Elpased Time: 3.781sec

CPU time: 3.536sec

정도가 걸린다.

실제로 10번시행해 낸 평균은 3.675sec




TimeLine을 보면 Thread하나만 열심히 도는것을 볼 수 있다.



Amplifier Hotspots 으로 측정해 본 결과



IDCT_new 가 66.2%

decode_macroblock이 33.8%이다.


내가 병렬화 하려는 부분은 IDCT_new이다.








#pragma omp parallel for 를 추가.


물리코어가 4개이기 때문에 worker thread 3개가 생성 되어 총 4개의 쓰레드 들이 돌것이다.




Elpased Time: 3.926sec

CPU time: 9.997sec

정도가 걸린다.

실제로 10번시행해 낸 평균은 2.351sec



4개의 Thread들이 일한다.


3.657 -> 2.351 로 빨라졌다.

그런데 33.8 + 66.2/4 = 50.35 이다.

그럼 원하는 idle한 speed up은 두배

그러나 3.657/2.351 = 1.55배의 speed up만 되었다.



Concurrency 분석을 해보자.




먼가 나온다.


Thread Concurrency란 

얼마나 많은 쓰레드가 따로 따로 일을 하였는지 를 나타내준다.

Concurrency가 안 나올수 있는 이유는 여러가지겠지만,

1. 메모리나 변수를 공유하게되면 다른 쓰레드의 사용을 기다림.

2. load invalance 각각의 쓰레드들이 하는 일의 양이 달라 다른 쓰레드가 끝날 때까지 기다림.

이렇게 크게 두가지가 있을것이다.



확대하여보면 이렇게 4번째 쓰레드만 따로 노는 것을 볼 수 있는데,

아마 성능측정하는 모니터링 쓰레드랑 겹쳐서 그런것 같다.










#pragma omp parallel for num_threads(3) 를 사용해 3개의 쓰레드만 봐보자.



Elpased Time: 2.112sec

CPU time: 5.820sec

정도가 걸린다.

실제로 10번시행해 낸 평균은 1.946sec




신기하게도 더 빨라졌다. (나중에 다시 4개로 해보니 1.967sec가 나옴)

그 이유는 나중에 찾아보기로하고.

33.8 + 66.2/3 = 55.87

3.675sec * 55.87 / 100 = 2.053sec 을 기대하는데

결과가 1.946sec이니 거의 완벽한 speed up을 가져왔다고 볼 수 있다.


Concurrency를 다시 보면



CPU Time을끄고

앞쪽을 보면 


2번 의 파란 부분이 하나의 OpenMP로 병렬화된 for loop이다.

여러개의 작업이 세개의 쓰레드로 나눠져서 일을 했다.


3번을 보면 OMP(OpenMP) 구간에 빈곳이있는데 

메인쓰레드인 0번쓰레드와 2번쓰레드는 작업이 끝났는데 

두번째 1번 쓰레드가 작업이 끝나지 않아서 쉬고 있는것을 볼 수 있다.


1번을 보면main Thread의 OMP구간에서 두개의 쓰레드를 생성하고

그 생성된 쓰레드가 Serial 구간에선 쉬었다가 (main 쓰레드만 일하고)

다시 OMP구간에 들어오게되면 일을 하는 것을 확인 할 수 있다.

쓰레드를 생성하는데 오버헤드가 있기 때문에 한번 생성해 놓은 쓰레드를 

계속 재활용(?)하는것을 볼 수있다.




노란색 화살표가 Transitions 를 나타내는데

위 그림의 첫번째 OMP구간에선 2번쓰레드가 늦게 끝나서 메인쓰레드가 기다리고 있다.

그런데 두번째 OMP구간을 보면 MainThread가 가장 늦게 끝났기 때문에 Transitions화살표가 없다.



기본 OMP의 스케줄링은 static이다.

예를 들어, 30개의 작업이 있고 쓰레드가 3개면 1~10 >> T0,  11~20 >> T1, 21~30 >> T3

이런식으로 딱 n분의 1되어 매핑되게된다.

그러다보면 빡쎈일을 한 쓰레드가 몰아 받을 가능 성이 생기게된다.

그럼 이걸 없앨 수있는 가장 간단한 방법은?

하나씩주면 되는거다.

5개씩 일을 주고 먼저 끝난쓰레드에 일 하나씩 배정해 주면 되지 않을까?


그게 스케줄링이다.


 static

 #pragma omp for schedule(static, chunk_size)

각 스레드에 덩어리로 지정한 크기의 작업량으로 할당된다.

chunk_size가 지정되지 않은 경우에는 총 작업량을 thread의 수로 나누어 분할한다.

작업량이 나누어 떨어지지 않으면 배분되지 않응 나머지 작업은 먼저 작업을 끝낸 thread가 수행하게 된다.


 dynamic

 #pragma omp for schedule(dynamic, chunk_size)

작업을 수행할 준비가 완료된 대기 상태의 tharead로 부터 작업 할당 요청을 한다.

chunk_size를 지정하지 않을 경우 default 는 1이다.


 guided

 #pragma omp for schedule(guided, chunk_size)

dynamic과 방식은 같지만 차이점은 배분하는 덩어리 크기가 점차 줄어든다는 것이다. 최초 할당하는 덩어리 사이즈는 지정한 값이지만 각 thread에 처음 할당된 작업이 완료되면 덩어리 크기에서 일정한 비율로 줄어든 크기만큼 재 할당 된다.

 

 auto

 #pragma omp for schedule(auto) 

컴파일러가 가장 적합하다고 판단하는 스케줄링으로 설정된다. 

OpenMP 3.0 이상에서 사용 가능하다.


 runtime

 #pragma omp for schedule(runtime)

스케줄에 대한 결정은 프로그램이 실행 될 때까지 연기되며, chunk_size는 run-sched-var 내부 제어 변수값으로 설정된다.

만일 설정된 값이 없으면

 #pragma omp for schedule(static)과 동일하게 동작한다. 




#pragma omp parallel for num_threads(3) schedule(guided) 를 써보자.


Elpased Time: 2.186sec

CPU time: 5.725sec

정도가 걸린다.

실제로 10번시행해 낸 평균은 1.954sec



그렇게 큰 성능 향상은 없었지만

스케줄링으로 인한 load invalance는 확연히 준것을 볼 수 있다.















반응형

댓글