728x90

pi 계산 순차 코드

- 실행결과 1.326s 소요

 

 

 

어떻게 고칠까

- for문이 로드가 걸릴거같다 -> 병렬 처리

- private 할지 shared할지 결정해야함 : x 는 private, sum은 누적이므로 reduction 사용

 

병렬화 결과

- 일단 사용할 스래드 갯수 5개로 설정

- sum은 각 스래드별로 계산후 다합칠것이므로 reduction

- x는 각 스래드마다 개별로 가져야하므로 private

 * private을 안하면 다른 스레드의 x값이 덮어씌워줄수 있음.

- 순차 코드에서 1.326s가 소요됬으나, 병렬 코드에서는 0.318s가 소요

 

 

* #pragma omp parallel 과 parallel for의 차이

- prallel만 있는 경우 { } 병렬영역을 괄호로 지정해주어야 함

- parallel for의 경우 #pragma 바로 아래의 for문에만 영향을 줌

300x250

'컴퓨터과학 > 기타' 카테고리의 다른 글

openmp - 19. 중첩 스레드  (0) 2020.07.30
openmp - 18. 병렬 블록, 포크 조인, 동기화 문제  (0) 2020.07.30
openmp - 16. reduction과 factorial  (0) 2020.07.29
openmp - 15. reduction  (0) 2020.07.29
openmp - 14. 동기화  (0) 2020.07.29
728x90

순차 프로그램으로 팩토리얼 계산

- 5000만 펙토리얼 연산 수행

 => 0.151s 소요

* 4개 스레드 reduction 지시자 사용한 경우 0.091s 소요

 

 

reduction을 이용한 factorial 계산

- 4개의 스레드를 생성하여 reduction 지시자로 5000만회 펙토리얼 연산 수행

 => 0.91s 소요

 

 

 

 

 

 

300x250
728x90

시간 측정

- time ./실행파일명

ex. time ./13_serial_loop.x

- 13_serial_loop는 순차 프로그램, 15_parallel_for 작업분할지시자를 사용한 병렬 프로그램

 -> 20번 루프돌리는 동안 13은 0.045s 가 걸렸으나 15는 0.029s가 소요

 

 

atomic을 사용하는 경우

- 동기화를 위해 하나의 스레드만 사용하도록 막음

 => 병렬 처리의 성능을 크게 낮춤

* ciritical은 함수 범위 atomic은 한 줄연산 범위

 

 

 

reduction

- #pragma omp for reduction (+:sum)

 => 각 스래드들끼리 local sum을 구해서 다 더해라

 * atomic 처럼 한 스레드마다 다 돌떄까지 기다리지 않음. 단 전체가 로컬 sum을 구하도록 기다림

- sum이 shared 변수 -> 내부적으로 private처럼 처리

 

 

 

 

 

300x250
728x90

동기화 루틴

- #pragma omp critical 

 => 한 스레드가 동작중에 다른 스레드가 사용못하도록 막음

 => 한 스레드마다 처리 ? -> 차례차례이므로 병렬화가 아님 -> 성능이 떨어진다.

- 동기화를 시키기 위해 사용

 

 

 

 

 

 

 

동기화

- 스레드 작업 순서에 제한 두기 가능

- 공유 데이터 접근 제어

- 가능한 안쓰는것이 좋음

- 고수준 동기화 : critical, atomic, barrier

- 저수준 동기화 : flush, locks

 

critical과 atomic의 차이

- critical : 한번에 한 스레드만 이름으로 구분하는 critical 영역 진입

- atomic : 메모리의 한 위치에만 적용됨. mini-critical section. 크리티칼 영역보다 작음

 

 

 

베리어

- 모든 스레드들이 베리어에 도달 할 떄까지 대기함

- 작업 분할 구문(#pragma omp for)에서는 사용 불가

 

 

베리어가 없는 경우

- 스레드들이 베리어가 없으므로 기다리지 않고 그냥 처리

 => 결과 값이 달라짐

 

300x250
728x90

기본적인 내적 순차 연산

- 길이가 20인 벡터 a와 b의 내적(점곱)연산 결과

 

 

병렬 내적(=BLAS 내적) 연산

- BLAS Basic Linear Algebra Subsystem 선형대수 라이브러리 -> BLAS의 내적 연산 구현

- 스래드 4개 생성

- 20개의 작업을 4개의 스레드로 나눠서 수행 <- #pragma omp for(작업분할지시어)

- 결과는 순차 내적 연산 코드와 동일함. 시간 측정을 하면 병렬 코드가 더빠를듯

 

 

병렬화의 중요점

- 기본 로직과 병렬화 로직 중 병렬화를 함으로서 성능 이득이 커야함

- 기본 로직 상에서 병렬화를 수행할 부분을 잘 찾아야함

 

300x250
728x90

병렬 루프 만들기

- 코드에서 실행 시간이 오래걸리는 부분에서 병렬화를 수행해서 시간을 줄여야함

 => 그런부분들이 루프문임 => 루프문을 병렬화 해야함

- openmp의 단점. 사용 가능한 노드 수가 제한됨(1개)

- 여러 노드를 사용해야할때 mpi를 사용해야함

 

 

단순 순차 루프문

 

 

병렬 루프문

- N은 20, 스레드는 4개

- i, tid, istart, iend를 private으로 사용

tid    istart    iend       output i

 0      0        5       -> 0 ~ 4

 1      5       10      -> 5 ~ 9

 2      10      15     -> 10 ~ 14

 3      15      20     -> 15 ~ 19

- 아래에 컴파일러 지시자로 작업을 분할해주는것과 결과는 동일하나 구현은 복잡함

 

 

 

 

 

간단해진 병렬 루프문

- #pragma omp for <- 작업 분할 지시어(핵심)

 => 4개의 스레드가 20개의 문자열 출력 작업을 분할해서 수행

 

 

 

300x250
728x90

배열에 스레드 번호 저장하기

- 스래드 4개 생성

- 배열은 shared

- i는 계속 처음에 10으로 초기화

- 각 스래드마다 인덱스와 값으로 0, 4, 8을 추가하여 할당

- 정리

tid(idx)  value

0        0  4 8

1       1   5 9

2       2  6 10

3       3  7  11

 

300x250
728x90

스레드

- 프로세스 내 여러 실행 단위

- 메모리 공유. 스택에 변수 저장

 

프로세스

- 프로그램의 실행 단위

- 개별적인 메모리를 가짐

 

 

메모리 공간

- 코드 영역 : 실행할 명령어들이 저장된 공간

- 데이터 영역 : 전역 변수 저장

- 힙 영역 : 동적 할당 메모리 공간

- 스택 영역 : 함수 호출 정보와 스레드 변수, 지역 변수들을 저장

 

https://snupi.tistory.com/9

 

 

 

 

300x250
728x90

전역 변수로 초기화

-  전역변수 i = 10이 존재

- private i들을 10으로 초기화 -> firstprivate

 => print 출력 후 i는 20(지역변수)

- 병렬 영역 밖에서 i는 10

 

 

 

 

 

공유 변수

- shared(a)로 배열 변수 a를 공유 설정

 

- 병렬 영역 안에서 공유 변수 a에 값을 저장하였으나 병렬 영역밖에서도 접근 가능

 

 

private 배열 변수

- 아까 share 시킨 배열 변수 a를 private으로 지정후 병렬 영역 안에서 초기화 시키면

 => 병렬 영역 안에서만 값이 존재. 병렬 영역 밖에선 배열은 0으로 초기화 되지 않은채 남아있음.

 

300x250
728x90

OpenMP과 메모리 공유

- 스레드 중심이다보니 공유 메모리 병렬 프로그래밍 방식

-> 변수들이 공유됨

 

 

변수 공유 예시

- 아래의 코드 상에서 변수 tid들은 모든 스레드 상에서 공유됨

- 병렬 영역 전에 tid가 선언되고, 병렬 영역 안에서는 공유된 변수 공간에 초기화 수행

* 포트란에서는 모든 스레드가 덮어씌워져서 같은 tid를 가지나 c언어는 컴파일러가 수정해줘서 제대로 결과가 나옴

- 포트란에서는 tid가 공유되어 있어 다 덮어씌워지는 모습을 볼수있음.

 

 

변수 공유 해결

- tid를 private로 컴파일러 지시자를 지정해주면 됨.

 

- 혹은 tid를 지역변수로 만들어주면 됨

 

- 변수 tid에 각각의 스레드 번호가 할당되어 출력된 결과를 볼수 있음. 

 

 

 

300x250

+ Recent posts