프로그래머가 몰랐던 멀티코어 CPU 이야기, 리뷰 및 짧막한 요약

 

저자: 김민장 출판: 한빛미디어

회사에서 일을 하며, Thread/Process 등 병렬 처리 테크닉을 다뤄야 하는 일이 몇번 있었다. 확실히 득도 많지만 실도 많고, 배울 점도 많은 시간이었다. “조만간 좀더 공부해야지”하며 벼루고 있었는데, 예전에 존경하는 개발자 한분이 “이 책들 좋아요~” 리스트에 있어서 읽게 되었다.

Story 1 ~ 4

책의 초반 답게 처음 읽거나 관련 지식이 없어 생소한 사람들을 위한 챕터다. 이전에 컴퓨터 구조에서 어렴풋이 배웠던 지식을 상기시켜 주었다. 어셈블리 예제로 우리가 쓰는 코드가 CPU에서 어떻게 해석하는지 알 수 있다.

명령어가 어떻게 나뉘고, 프로그램에 따라 명령어의 분포가 다를 수 있다. 각 명령어 타입에 따라 프로세서가 처리하는 클록의 개수는 달라진다.

직렬 처리에서 멀티 프로세싱을 한다고, 프로그램의 속도가 단순히 1/N으로 줄어드는 것은 아니다. 만약 병렬 처리코드에 I/O가 주된 처리 내용이라면, 실질적인 향상 내역은 없을 수도 있다. 어쩌면 병렬 처리 부하로 인해 기존보다 더 느려질 수도 있다! 암달의 법칙이란 식을 통해 얼마나 속도가 향상 되었는지 계산할 수 있다. 아마 일반적인 개발하는 하지않겠지만…

Story 5 ~ 8, 의존성과 파이프라인

뉴비 개발자로서 이 챕터를 읽으며 신기했던 적이 엄청 많다. ch5 인 명령어 의존성을 읽을때는 재미도 없었고, 대충대충 빨리 넘겼었다. 하지만 이를 나중에 후회할 줄은 꿈에도 몰랐다. 이에 나오는 내용의 근본의 근-본은 결국 의존성에 기반하고 있었다.

프로세서는 사실 명령어를 하나하나 실행(한 명령어를 완료한 후 다음 명령어를 실행)시키는 것이 아닌 , 파이프라인 패턴으로 명령어를 동시에 실행하고 있다. 이때 명령어 의존성을 검사하여 동시에 실행해도 되는지 검사한다. 이때 [명령어 인출, 해독, 피연산자 인출, 실행, 저장]을 단계 단계 실행한다. 그래서 사실 우리는 명령어를 실행하는 것이 아닌 완료된 결과의 차례를 기다리고 있는걸 수도 있다.

Story 9 ~ 12, 하드웨어와 처리 방식

멀티 프로세서 코어의 처리방식, 자원의 공유방식을 알려준다. GPU는 몇천~몇만 개의 코어로 부동소수점 연산을 동시에 처리한다.

이 내용은 기존에 어느정도 알고 있었던 내용이기에 큰 임팩트는 없었다.

Story 13 ~ 16, 최적화와 prefetching

데이터를 가져올 때 캐시 미싱이 일어나 ram까지 데이터를 찾아 올수 도 있다. 그래서 prefetching 방식으로 메모리나 하위 캐시에서 미리 캐시를 가져와서 연산 해야될 때 바로 상위에서 가져와 명령어를 빨리 실행시킨다.

prefetching은 비단 캐시 로딩에만 사용하는 것이 아니다. if명령어나 가상 함수의 vtable에서 미리 명령어를 가져올 수 있다. 미리 예측해서 가져오는 방식은 실패했을 때 리스크가 크기 마련이다.

이 부분에서 놀랐던 점은 포인터가 항상 최적화를 가져오는 것은 아니라는 것이다. 명령어를 가져올 때 포인터가 명령어의 의존성을 방해한다. 포인터가 가르키는 값이 앞이나 뒤 명령어에서 어떻게 사용이 될지 몰라 명령어가 병렬로 실행하는 것을 방해한다.

Story 17 ~ 20, 멀티 코어를 배워야 하는 이유

CPU는 하드웨어의 한계에 봉착하여 클록 속도를 높이기보다는, core를 늘리는 방식으로 발전하고 있다. GPU도 인공지능, 블록 코인등 부동소수점, hash연산등 복합 부동소수점 연산을 동시에 빨리 처리하는 식으로 발전하고 있다. 여러 프로그램을 동시에 실행하고, thread와 프로세스를 control하는 능력을 길러 이 하드웨어를 잘 활용할 수 있어야 한다.

여러 프레임워크도 thread-safe code를 작성하며, 각각의 언어에서도 멀티 프로세싱을 지원하는 라이브러리가 오픈 소스에서도 쏟아져 나온다.

후기

이전까지는 thread 관련된 작업을 하게되면 “어떻게 하지, 이 버그는 어떻게 고치지” 등등 맞닥뜨린 문제에 대해서 스트레스를 받기만 했다. 아 해야지 해야지 라며 생각만 하다가 책을 읽으니, 내가 이 트렌드에 탑승하지 못하고 회피만 하고 있었다는 것을 깨닫게 되었다.

내가 컴퓨터 구조나 assembly, OS에 대한 기본 지식이 좀더 있었다면 이 책을 좀더 잘 받아들였을 텐데 양산형 개발자로 성장한 스스로가 아쉽다.