HAM 여행

오늘은 CPU가 어떻게 일을 하는지 보겠습니다.

CPU가 하는일을 요약하면


Fetch(인출) : 메모리상의 프로그램 카운터가 가리키는 명령어를 CPU로 인출하여 적재

Decode(해석) : 명령어의 해석. 이 단계에서 명령어의 종류와 타겟 등을 판단한다

Execute(실행) : 해석된 명령어에 따라 데이터에 대한 연산을 수행한다.

Writeback(쓰기) : 명령어대로 처리 완료된 데이터를 메모리에 기록한다.


참고로 CPU는 한 싸이클에 한 명령어(우리가 알고 있는 ls, cd 등과 같은 명령어 와는 다름)를 처리 합니다.


즉 다음과 같이 일을 한다.

Fetch: 실행할 명령어들을 가져온다. 이후 단계들도 그렇지만, 한 번에 보통 4개 정도를 처리하는데, Superscalar라고 불리는 기술은 이렇게 한 사이클에 여러 명령어를 처리하는 것을 말한다.


Decode: 이후 처리를 돕기 위해 명령어의 종류를 구분한다. Intel의 x86 ISA같이 복잡한 명령어를 쓰는 CISC의 경우, 내부적으로 RISC 명령어들로 쪼개지는 과정이 여기서 수행된다. 옛날 프로그램을 짜기 어려웠던 이유는 바로 이 디코드 동작시 불러오는 CPU 명령함수들이 CPU마다 전부 다 다르다는 것 때문이었다. 현재는 몇 개 회사가 CPU 공급을 독점하면서 그나마 단순화되었다. (같은 회사는 추가 기능이 없다면 같은 명령함수를 쓰는 게 일반적)


Rename: 명령어가 가리키는 레지스터(CPU에서 값을 저장하는 x86 ISA의 eax나 ebx등의 이름있는 공간들)를, 내부에 숨어있는 물리적 레지스터로 매핑한다. 이러한 과정은 Out-of-order CPU에서 발생하는 False-dependency 문제를 해결하기 위해 필수적이다.



Dispatch: 명령어가 실행하기 위해 기다리는 대기열 (ROB, IQ, LSQ)에 명령어를 넣는다.


Issue: 대기열에 있는 명령어가 실행될 수 있으면 실행하기 위한 장치(가령 계산 명령어는 ALU, 메모리 명령어는 Cache)로 보낸다. 참고로 프로그램에서 시간상 뒤의 명령어가 앞의 명령어보다 먼저 Issue될 수 있다. 이것이 바로 Out-of-order CPU의 핵심 동작 중 하나다


Execute: 실행한다


Writeback: 결과값을 레지스터에 써야 한다면 쓴다. 결과값을 기다리고 있던 명령어가 있다면 결과가 생겼다고 알려준다.


Commit: 명령어 수행을 완료하고, 명령어 실행을 위해 할당받은 자원을 모두 토해(반납)낸다. 명령어의 실행 결과를 사용자에게 노출시키며 (이거 전에는 노출이 안 된다), 이후로는 명령어의 실행을 취소 할 수 없다.



그리고 Out-of-order CPU를 만들기 위해선, 위의 명령어 처리 과정 외에도 몇몇 핵심 기술들이 요구된다.


Cache (캐시 메모리): 주 메모리 값을 임시 저장하는 작고 빠른 메모리. 주 메모리 접근은 CPU입장에서 100사이클 정도 놀게 만드는 엄청나게 느린 동작이므로 Cache가 없으면 명령어를 빠르게 실행하고 싶어도 값이 준비가 안 돼서 불가능하다. 캐시 메모리도 한 개만 존재하는 것이 아니라, 보통 중요도와 접근 빈도에 따라 L1~L3의 3개 캐시 메모리를 사용하며, 숫자가 작을수록 용량이 더 작고, 더 빠르다. 또한 캐시 메모리만을 위한 색인 제조 방법과 구동방식은 해당 문서에서 확인 바람.


Branch prediction: Fetch를 매 사이클마다 하기 위해선 다음에 실행할 명령어 주소를 알아야 하는데, branch 명령의 결과가 나오려면 꽤나 시간이 걸린다 (게다가 프로그램마다 차이는 있지만, 명령어의 약 30%정도는 branch이다.) 그러니 branch 명령의 결과를 과거의 기록을 기반으로 예측하는 기술이 필요하다.


Speculative memory disambiguation: 메모리 접근 명령어들은 메모리 접근 전에 접근할 메모리 주소를 먼저 구해야 한다. 이 때문에 만약 LSQ에 Store 명령이 접근할 메모리 주소를 계산하기 위해 대기중이면, 이후 모든 Load 명령어는 접근할 메모리 주소가 준비되었다 하더라도 메모리 접근을 할 수 없다. 혹시라도 그 Store가 접근하는 주소가 Load가 접근하는 주소랑 같으면 가장 신선한 값은 메모리가 아니라 그 Store 명령어가 가지고 있기 때문이다.하지만 할 수 없는 걸 그냥 해버리면? (즉, Speculative memory disambiguation) 대부분의 경우 접근하는 메모리 주소는 다르기 때문에 문제가 없으며, 문제가 있더라도 그 Store가 접근하는 메모리 주소를 계산하기 전까진 Load들을 Commit을 하지 않는 것으로 실행 취소가 가능하다.


오늘 이야기는 조금 어려운 이야기가 되었습니다.

그러나 Linux(라즈베리파이)를 사용하면서 CPU가 어떤 과정을 거쳐서 일을 하는지는 감으로나마 알고 있는것이

필요하지 않을까하여 몇자 적었습니다.


프로그래밍이란것이 그리고 소프트웨어가 얼마나 잘 만들어 졌고 잘 돌아가고 얼마나 가벼운지는 CPU가

어떻게 일을 하는지를 모르면 설명하는데 한계가 있는것 같습니다.

CPU가 하는 일 중에서 일부분을 설명했습니다.

다음은 CPU의 명령체계와 레지스터리에 대한것을 설명 할까 합니다.


감사합니다.


DE HL1RR 73!


글로벌스피드 https://smartstore.naver.com/globalspeed