11
고고고고고고고고고고 Optimizing merge program 고고고고고고 20113313 고고고

Optimizing merge program

Embed Size (px)

Citation preview

Page 1: Optimizing merge program

고급시스템프로그래밍 Optimizing merge program

컴퓨터공학과20113313 이창현

Page 2: Optimizing merge program

Merge.c 코드는 ..

1. 두개의 파일을 하나로 합치는 프로그램이다 .2. 각 파일을 한줄씩 읽고 번갈아가며 새로운 파일에 write 한다 .3. 입출력에 파일스트림을 이용한다 .

Page 3: Optimizing merge program

최적화 1) 파일 입출력함수 변경

open 함수는 시스템에서 제공해주는 버퍼를 이용하며 , fopen 함수는 C 표준 라이브러리에서 할당해주는 버퍼를 이용한다 .

fopen() 함수는 이중버퍼를 사용하며 파일에서 한번 데이터를 읽어온 후 다음번에 얼마정도의 데이터를 가져올지 모르기 때문에 버퍼에 미리 얼마간의 데이터를

적재함으로서 system call 횟수를 줄인다 .

하지만 merge.c 와 같이 사용자가 파일에서 어느정도 크기의 데이터를 가져올지 알고있을 때 , open 함수로 한번의 system call 에서 필요한 데이터를 모두

가져오는것이 파일 read 를 여러번 실행하는것보다 system call 횟수를 줄이기에 효율적일 것이다 .

Page 4: Optimizing merge program

최적화 1) 파일 입출력함수 변경

파일 입출력함수를 바꾼 모습 .read() 함수로 100 메가 크기의 파일을

메인 메모리로 한번에 읽어왔다 .(merge_read_write.c)

합쳐진 파일을 write 할때 또한 200 메가 크기를 한번에 write 해주었다 .

>> 결과 : 실행시간이 절반가량 줄어듬

Page 5: Optimizing merge program

최적화 2) 병렬프로그래밍

오른쪽 사진은 라즈베리파이 내의 CPU 갯 수가 4 개임을 알려준다 .

이와 같은 다중코어 시스템에서는 여러개 의 스레드를 동시에 사용하면서 실행시간 을 단축시킬 수 있다 .

> less /proc/cpuinfo

Page 6: Optimizing merge program

최적화 2) 병렬프로그래밍

본 코드에서는 병렬프로그래밍을 더 쉽게 적용하기위해 오픈소스 라이브러리중 하나인 OpenMP 를 이용했다 .

그림 1 은 두 개의 파일을 읽는 행동을 동시에 하도록 만든 task parallel 코드그림 2 는 reverse 함수 for-loop 의 각 루프가 서로 dependency 가 없으므로

적용시킨 data parallel 코드 (merge_openmp.c)

그림 1. 파일 read 병렬화 그림 2. reverse 함수 병렬화

Page 7: Optimizing merge program

최적화 2) 병렬프로그래밍

하지만 총 실행시간은 오히려 늘어났다 ! ( 약 55 초 ->80 초 )

이유 : reverse 함수는 수없이 많이 실행되는 함수 . 실행시킬때마다 각 스레드에 할당시키는것 또한 context switch 에 따른 overhead 가 발생하며 overhead 로 발생하는 낭비가 스레딩으로 줄어든 시간보다 컸음을 의미한다 .

결론 : 병렬프로그래밍을 적용할 다른 방법을 찾아야 한다 .

Page 8: Optimizing merge program

최적화 3) reverse 분할

지금까지는 파일에서 입력받은 두 버퍼에서 한줄씩 읽고 reverse 후 바로 출력버퍼에써주었다 .

원본 버퍼를 reverse 해주는 부분을 함수로 따로 떼어낸 후 스레드를 할당해보았다 .=> 결과 : 오히려 시간이 늘어났다 .( 약 55 초 => 70 초 )=> 버퍼에서 한 줄씩 읽어들이는 행동이 overhead 로 작용했다 .

reverse 함수 병렬화[merge_divide_reverse.c]

Page 9: Optimizing merge program

최적화 4) write 분할

Race condition 때문에 두 입력버퍼에서 한줄씩 읽어 출력버퍼에 쓰는 행동을 동시에 할 수는 없다 .

출력버퍼에 쓰는 구간을 앞부분과 뒷부분으로 나눠 각각 스레드를 할당해주면 실행시간을 좀 더 줄일 수 있을것이다 .

코드 : merge_divide_outbuf.c=> 결과 : 실행시간이 약간 줄어들었다 . ( 약 55 초 -> 45 초 )=> 여기에서는 스레드 2 개까지밖에 활용하지 못했지만 스레드 4 개를 모두

활용한다면 더 좋은결과가 나올 것이다 .

Page 10: Optimizing merge program

최적화 4) write 분할 코드

[merge_divide_outbuf.c]

Merge 의 앞구간과 뒷구간으로 section 이 나뉘어졌다 .

두 스레드가 각각 두개의 입력버퍼를 한줄씩 읽으면서 reverse 후 출력버퍼에 써준다 .

두 출력버퍼가 완성되면 write 로 파일에 씌여진다 .

=> 결과 : 실행시간이 약간 줄어들었다 . ( 약 55 초 -> 45 초 )

=> 여기에서는 스레드 2 개까지밖에 활용하지 못했지 만 스레드 4 개를 모두 활용한다면 더 좋은결과가 나올 것이다 .

Page 11: Optimizing merge program

측정결과

단위 : sec

표의 reverse 는 문자열 뒤집기만 적용한 버전으로 fgets() 함수를 사용하면서 system call 횟수가 줄어든 결과 원본보다 오히려 실행시간이 줄어들었다 .

System call 이 최소화되도록 입출력함수를 바꿔준 것과 , 출력버퍼에 쓰는 구간을 나눠 각각 스레드를 할당해준 것이 실행시간을 줄이는데 효과가 있었다 .

성능개선 최종결과 : 119.83 => 44.86(sec) 37.4%