"클럭 싸이클이란"
클럭 싸이클은 CPU가 명령어를 실행하기 위해 데이터를 가져오고(fetch), *명령어를 해석하고(decode), 실행(execute)하는 단계를 말한다. 명령어를 실행하는 주기라고 해서 '명령 주기'라고 한다.
*싸이클: 메모리에서 명령어 코드(opcode)와 데이터가 있는 메모리 주소를 fetch한다. CPU가 갖고 있는 명령어 코드 중 일치하는 것을 찾고 어떤 명령인지 해독한다(decode). 그리고 실행(execute)한다.
"단위"
클럭 싸이클의 단위를 Hz(헤르츠)이다. 1Hz이면 1초 당 하나의 명령을 실행할 수 있다. 요즘은 컴퓨터로 영상을 끊김없이 보고, 게임도 한다. 요즘의 컴퓨터는 GHz 단위의 성능을 갖고 있다. 내 맥북의 경우 2.6GHz인데 1초에 8,589,934,592개, 즉 1초에 85개가 넘는 명령을 실행할 수 있다.
엔지니어들은 CPU에게 동시에 더 많은 명령을 내리기 위해서 여러 가지 방법을 고안했다.
"Cache"
캐시는 CPU에 내장된 RAM이라고 생각하면 된다. CPU가 명령을 실행하기 전, RAM에서 데이터를 가져온다. 그런데 CPU가 RAM에서 데이터를 가져오는 동안 CPU에 있는 ALU(누산기, 연산에 사용)는 아무것도 안하고 놀게 된다. 데이터를 가져오는 동안 지연이 생기게 되는데, 이를 막고 빨리 명령을 실행하기 위해 RAM과 같은 메모리를 CPU 안에 내장시킨다. 이를 Cache라고 한다. 브라우저에서 캐시에 데이터를 저장해놓고 빠르게 데이터를 불러오듯이 CPU도 캐시에 데이터를 저장해놓고 지연 없이 명령을 실행할 수 있다.
CPU와 RAM은 Bus로 연결되어 있다. 이전 포스팅에서 말한 것처럼 Bus는 여러 데이터를 한꺼번에 전송할 때 쓰는 용어이다. 아무튼 CPU와 RAM은 버스를 통해 데이터를 주고 받는다. CPU는 버스를 통해 명령어 실행에 필요한 메모리 블럭을 통으로 가져와서 이를 Cache에 저장한다. CPU는 메모리에서 데이터를 가져오길 기다리는 일 없이 Cache에서 데이터를 가져와 명령을 실행할 수 있다.
이때, 필요한 데이터가 캐시에 있다면 'Cache Hit'라고 하고 없으면 *'Cache Miss'라고 한다. Miss가 나면 RAM에서 데이터를 가져와야한다.
*이런 Hit/Miss 같은 용어들은 브라우저 캐시에도 동일하게 사용된다.
"Cache의 문제: 예측 / 메모리 동기화"
평균적으로 GB 단위의 RAM과 달리 캐시는 MB 단위의 용량만 갖고 있다. 따라서 한꺼번에 모든 명령을 가져오지 못하고 일부 메모리 블록만을 가져온다. 블럭 실행이 끝나면 캐시는 메모리 블럭을 교체하여 다음 명령을 가져온다. CPU는 다음 명령이나 데이터를 가져올 때 예측해서 갖고 온다. 하지만 예측이 틀린 경우, 캐시에 다음 명령이 저장되지 못해 Cache Miss가 나고 RAM에 다시 접근해야 하면서 지연이 일어난다. 다행히 최신 프로세서는 예측 알고리즘이 발전해서 지금의 캐시 적중률은 80% 이상이다. 그래서 요즘의 CPU는 Cache에 저장된 것을 사용하고 결과적으로 RAM만을 사용할 때보다 더 빨라진다.
명령을 실행할 때 메모리에 값을 저장하면서 Cache와 메모리에 있는 값이 달라진다. RAM에 있는 메모리에는 데이터 변화가 없기 때문에 Cache와 RAM의 데이터가 달라진다. 그래서 메모리 블록을 교체하는 과정에서 동기화가 필요하다. 하지만 메모리 블록에 있던 모든 데이터를 다시 동기화할 필요는 없다. Cache에서 데이터에 변화가 생길 때마다 해당 메모리에 'dirty bit'임을 체크해서 그 부분만 동기화한다.
"명령어 파이프라인(Instruction Pipeline)"
명령을 비동기로 실행한다. 다음 명령어가 이전 명령어의 실행을 기다리지 않고 시작하는 것이다. 그러므로 속도는 더 빨라진다. 하지만 다음 명령어가 이전 명령어의 출력값을 사용하는 등, 이전 명령어에 의존성(dependency)이 있다면 어떻게 될까? 이미 이전 명령어가 모두 실행되기 전이라면 다음 명령어는 수정되기 전의 값을 가져와서 실행하게 된다. 그러므로 파이프라인은 의존성이 있는 명령어를 미리 '예측'하고 명령어 실행을 잠시 '지연'시킨다. (자바스크립트의 async-await이 생각난다.)
"명령어 파이프라인 또 다른 문제"
jump-negative라는 명령어가 있다. 출력값이 음수인 경우, Negative 플래그가 true가 된다. jump-negative는 Negative 플래그가 true라면 어떤 메모리 주소로 이동(jump)한다. jump는 무조건 이동하지만, jump-negative는 조건이 붙는다.
문제는 비동기로 명령을 실행시키는 과정에서 어느 메모리로 점프할지 알 수 없다는 것이다. 점프 명령어의 결과가 무엇인지 알 수 없기 때문에 점프 명령어가 실행될 때까지 프로세서는 무작정 기다리는 수 밖에 없다. 이 경우, 실행이 많이 지연되므로 프로세서는 점프 명령어의 결과를 *예측 실행한다. 한편, 예측이 실패하면 '파이프라인 플러시(Pipeline flush)'를 실행하여 파이프라인을 재구성한다.
*점프가 어디로 튈지 몰라 명령어 갈림길(branch, 분기)라고 하는데, 이를 예측한다 하여 '분기 예측'이라고도 한다.
"슈퍼스칼라(SuperScalar)"
하나의 클럭 싸이클은 하나의 명령어 실행 주기를 말한다. 슈퍼스칼라는 성능을 높이기 위해서 클럭 당 1개 이상의 명령어를 실행할 수 있도록 같은 회로를 병렬로 추가한 것이다. 한번에 fetch, decode한 후 동시에 실행하기 때문에 훨씬 빨라진다.
"멀티 코어 프로세서(Multi Core Processor)"
우리가 컴퓨터를 고를 때 CPU에서 말하는 쿼드 코어, 헥사 코어 등은 멀티 코어 프로세서를 말한다. CPU 칩에 연산을 병렬로 실행할 수 있는 코어들이 여러 개 존재하여 배로 빨라진다.
"reference"
'개발 이야기 > computer science' 카테고리의 다른 글
multi bit buses / 로직 게이트에 여러 비트 정보 전달하기 (0) | 2021.01.31 |
---|---|
로직 게이트 / Xor, Nand, Nor, Mux, DMux (0) | 2021.01.31 |
로직 게이트(Logic gate) / AND, OR, NOT (0) | 2021.01.31 |
[Bool Algebra] 논리 연산 (0) | 2021.01.30 |
컴퓨터 과학, 왜 공부해야 하는가 (0) | 2021.01.29 |