2. Merge.c 코드는..
1. 두개의 파일을 하나로 합치는 프로그램이다.
2. 각 파일을 한줄씩 읽고 번갈아가며 새로운 파일에 write한다.
3. 입출력에 파일스트림을 이용한다.
3. 최적화 1) 파일 입출력함수 변경
open함수는 시스템에서 제공해주는 버퍼를 이용하며, fopen함수는 C 표준 라이브
러리에서 할당해주는 버퍼를 이용한다.
fopen()함수는 이중버퍼를 사용하며 파일에서 한번 데이터를 읽어온 후 다음번에
얼마정도의 데이터를 가져올지 모르기 때문에 버퍼에 미리 얼마간의 데이터를 적
재함으로서 system call횟수를 줄인다.
하지만 merge.c와 같이 사용자가 파일에서 어느정도 크기의 데이터를 가져올지 알
고있을 때, open함수로 한번의 system call에서 필요한 데이터를 모두 가져오는것이
파일read를 여러번 실행하는것보다 system call 횟수를 줄이기에 효율적일 것이다.
4. 최적화 1) 파일 입출력함수 변경
파일 입출력함수를 바꾼 모습.
read()함수로 100메가 크기의 파일을
메인 메모리로 한번에 읽어왔다.
(merge_read_write.c)
합쳐진 파일을 write할때 또한 200메가
크기를 한번에 write해주었다.
>> 결과: 실행시간이 절반가량 줄어듬
5. 최적화 2) 병렬프로그래밍
오른쪽 사진은 라즈베리파이 내의 CPU 갯
수가 4개임을 알려준다.
이와 같은 다중코어 시스템에서는 여러개
의 스레드를 동시에 사용하면서 실행시간
을 단축시킬 수 있다.
> less /proc/cpuinfo
6. 최적화 2) 병렬프로그래밍
본 코드에서는 병렬프로그래밍을 더 쉽게 적용하기위해 오픈소스 라이브러리중
하나인 OpenMP를 이용했다.
그림1은 두 개의 파일을 읽는 행동을 동시에 하도록 만든 task parallel코드
그림2는 reverse함수 for-loop의각 루프가 서로 dependency가 없으므로 적용시킨
data parallel코드(merge_openmp.c)
그림 1. 파일read 병렬화 그림 2. reverse함수 병렬화
7. 최적화 2) 병렬프로그래밍
하지만 총 실행시간은 오히려 늘어났다! (약 55초->80초)
이유: reverse함수는수없이 많이 실행되는 함수.
실행시킬때마다 각 스레드에 할당시키는것 또한 context switch에 따른
overhead가 발생하며 overhead로 발생하는 낭비가 스레딩으로 줄어든
시간보다 컸음을 의미한다.
결론: 병렬프로그래밍을 적용할 다른 방법을 찾아야 한다.
8. 최적화 3) reverse 분할
지금까지는 파일에서 입력받은 두 버퍼에서 한줄씩 읽고 reverse후 바로 출력버퍼에 써
주었다.
원본 버퍼를 reverse해주는 부분을 함수로 따로 떼어낸 후 스레드를 할당해주면 어떨까
=> 결과: 오히려 시간이 늘어났다.(약 55초 => 70초)
reverse함수 병렬화
<merge_divide_reverse.c>
9. 최적화 4) write 분할
Race condition때문에두 입력버퍼에서 한줄씩 읽어 출력버퍼에 쓰는 행동을
동시에 할 수는 없다.
출력버퍼에 쓰는 구간을 앞부분과 뒷부분으로 나눠 각각 스레드를 할당해주면 실
행시간을 좀 더 줄일 수 있을것이다.
=> 결과: 실행시간이 약간 줄어들었다. (약 55초 -> 45초)
=> 여기에서는 스레드 2개까지밖에 활용하지 못했지만 스레드 4개를 모두 활용
한다면 더 좋은결과가 나올 것이다.