티스토리 뷰

Study/Architecture

[Study] Pipeline

생각많은 소심남 2013. 3. 15. 17:51

Computer Organization & Design 책을 보면 pipeline 파트의 맨 처음에는 다음과 같이 언급되어 있다.

Never Waste Time.

 동서고금의 명언이다. 아마 이 말이 pipeline을 하는 이유를 설명한 가장 간단한 구문이 아닐까 생각을 해본다.


말그대로 pipeline을 하는 이유는 시간을 낭비하지 않기 위함이다. 잘 모르는 사람이라면 컴퓨터가 사람이 시키는 대로 연산을 하는 건데 어떤 부분에서 시간을 낭비하는 건지 의아할 수도 있다. 하지만 그건 결과론적으로 본 것이고, 그 내부를 살펴보면 컴퓨터 동작 중에서 시간을 낭비하는 요소들이 곳곳 존재하는 것을 확인할 수 있다. 

 컴퓨터는 기본적으로 연산을 자동화해주는 기기이긴 하지만 무엇을 연산할 건지, 어떻게 연산할 건지는 컴퓨터를 사용하는 사용자의 입력에 따라서 결정된다. 그런데 이 연산을 하기 위해서는 필요한 것이 앞에서도 잠깐 나왔지만 무엇을 연산할 건지, 어떻게 연산할 건지가 있어야 할 것이고, 추가적으로 이 연산의 결과물을 어떻게 활용할 것인지에 대한 정의도 필요할 것이다. 그러면 이걸 조금더 나아가면 무엇을 연산할 것인지를 정의하기 위해서는 사용자가 입력으로 넣길 원하는 변수들이 저장된 register나 Memory를 넣어주고 읽어오는 과정이 필요하겠다. 또 어떤 연산을 할 건지는 자주 쓰는 연산에 대해서 일종의 table을 만들고 해당 부분에 해당하는 걸 불러오면 앞에서 언급한 사용자가 원하는 컴퓨터의 연산을 수행할 수 있을 것이다. 

 보통 이런 연산자와 메모리 주소, 환경설정에 대한 모든 정보가 담겨져 있는 것을 Instruction Set 이라고 하며, 이런 형식으로 동작하는 컴퓨터들을 Instruction Set Architecture (ISA) 라고 한다. 그러면 컴퓨터는 이 Memory 상에 저장되어 있는 Instruction Set을 읽고, 그 Instruction Set에서 요구하는 동작을 수행하게 되는데 이 때 다음과 같은 과정을 거치게 된다. 

- Instruction Fetch (IF)

-> Instruction Decode / Register Fetch (ID)

-> Instruction Execution (EX)

-> Memory Access (MEM)

-> Register Write Back (WB)

물론 Memory Access를 요구하지 않는 것들은 보통 Execution 과정까지 수행하게 된다. 아무튼 이렇게 5 stage로 나눠서 연산을 수행하게 된다. 그러면 처음에 생각할 수 있는 방법이 바로 정해진 Cycle에 따라서 순차적으로 수행되는 것이다.



책에서는 이 예제를 빨래에 비유했다. 만약 옷이 더러워진다면 옷을 깨끗이 하기 위해서는 세탁기에 넣어서 빨고, 건조기에 넣어서 말리고, 옷을 접어서 옷장에 집어넣는 일련의 과정을 거치게 된다. 이게 하나의 instruction을 처리하는 일련의 과정이다.그런데 이거야 한개의 instruction을 처리하는 과정이고, 컴퓨터와 같이 여러개의 instruction set을 처리하는 복잡하는 기기라면 위와 방식을 그대로 적용하면 다음과 같이 수행할 것이다.


뭔가 순서를 지키고 있고, 효율적으로 보일 수 있지만 그건 A의 입장에서 바라본 시점일 뿐 B,C,D의 입장은 단순히 먼저 쓰지 않았다는 이유로 한없이 기다려야 하는 것이 문제인 것이다. 더구나 D는 자기 Task를 수행하기 위해서는 12시까지 기다려야 하는 비효율성을 나타내는 것이다. 그러면 A,B,C,D의 일이 전부 끝나기 위해서는 새벽 2시까지 기다려야한다는 이야기이고, 만약 A,B,C,D가 같은 기숙사를 쓰면서 D가 기숙사 키를 가지고 있다면 문제는 더 커질 것이다. 이런 방식을 보통 Sequential Execution 방식이다. 

 그럼 이런 문제를 해결하려면 어떻게 해야 될까? 가장 쉽게 생각해보는 방법은 바로 Cycle의 Speed를 높이는 것이다. 위의 예에 적용해보면 당연히 세탁기와 건조기를 좋은 걸로 바꾸는 것이 될 것이다. 그런데 당연한 이야기이겠지만, 그런건 한계가 있다. 우선은 비쌀 것이고, 고성능인 만큼 그에 소비되는 전력도 덩달아 커질 것이다. 그대로 Operation에 적용해보면 Computer의 발전 방향과 정반대로 나아가는 것이다. 요즘의 추세는 Smaller / Low Power / Low Cost 를 추구하기 때문에 위와 같은 접근 방식은 어울리지 않는다.

 그래서 생각해본 방법 중 하나가 한가지 작업을 수행한 후에는 다른 Instruction을 동시에 수행할 수 있게 하자는 아이디어다. 그림으로 표현하면 다음과 같다.


어차피 동시에 같은 작업을 수행하는 게 아니라면 순차적으로 다음 instruction이 수행할 수 있도록 배려하자는 것이다. 이러면 D가 끝나기 까지 걸리는 시간이 앞의 Sequential Execution 방식에 비해 약 절반으로 줄어들게 된다. 마치 이런 방식이 pipeline에 Instruction을 꾸역꾸역 집어넣는 방식같다고 해서 Pipelined Execution 이라고 한다. 꾸역꾸역 집어넣으니 먼저 집어넣은 Instruction은 먼저수행되고 빈틈없이 다음 Instruction이 수행될 것이다. 그러면 맨 앞에서 언급했던 것처럼 세탁기와 건조기가 Time을 Waste하는 일은 없을 것이다. 이걸 Computer에서는 다음과 같이 구현된다.



결론적으로 pipeline을 통해서 추구하고자 했던 바는 한번에 처리할 수 있는 instruction의 수(stage)를 늘림으로써 instruction에 대한 throughput, 즉 정해진 시간동안 instruction을 얼마나 처리할 수 있는지를 높이기 위해서 였다고 할 수 있다. 유의할 것은 한개의 instruction이 처리되는 속도가 증가하는 것이 아니라 동시에 처리할 수 있는 instruction 수를 늘려서 전체 instruction이 처리되는 속도를 증가시키는 효과를 얻는 것이다. 참고로 위의 예시는 MIPS의 5-stage pipelined 구조이고, Pentium 4의 pipeline은 31 stage였다. 그런데 연구결과 무조건 stage만을 늘려서 효율성을 얻기에는 한계가 있어서 다른 부분을 발전시키는 방향으로 발전해가고 있으며, 현재 출시된 core i7의 stage는 16이다. 


기본적으로 pipeline을 설계하기위해서 고려한 사항은 몇가지가 있었다. 

MIPS의 경우는 우선 모든 instruction이 동일한 bit length를 가지고 있다는 것이다. 즉 앞에서 잠깐 언급했던 컴퓨터의 동작과정 중 나왔던 Instruction Decode를 위해서는 전체 32bit instruction 중에서 Opcode와 Register Address를 분해하는 작업을 수행해야되는데 이 영역이 정해져 있다면 Decode시에도 특정 규칙을 적용할 필요없이 그대로 decode가 가능했던 것이다. 동기간에 나와있던 80x86의 Instruction Set의 경우에는 instruction의 길이가 가변적이었기 때문에 pipeline이 가능하긴 했어도, MIPS에 비해서는 decode에 쓰이는 Resource가 더 커지는 것이다.  

 그러면 문득 현재 인텔에서 나오고 있는 x86 based CPU는 이런 pipeline이 안되지 않느냐는 의문을 가질 수 있는데, 이에 대한 흥미로운 포스트가 있어서 첨부한다. 

 x86기반 cpu는 파이프라인이 안되지 않냐? - http://kese111.tistory.com/88

두번째는 instruction set을 표현하는데 format이 몇몇개로 정해져 있다는 것이다. 이 말은 즉, instruction field와 register field로 나눠져 있는 규격이 정해져 있기 때문에 별도의 확인과정이 필요없다는 것이다. 즉 이때문에 Decode시에 소비되는 시간이 정형화되기에 이에 따른 pipeline 설계가 가능해지는 것이다. 

 물론 이밖에도 몇가지 요소가 있는데 이런 요소로 비춰볼때 MIPS가 pipeline이 가능했던 것은 instruction set의 format이 특정 규격에 맞춰서 정의되어 있어서였다. 잠깐 나온 내용이긴 하지만 인텔의 x86 규격은 CISC이며, Instruction set의 length가 가변적이기 때문에 pipeline이 힘들고, MIPS나 ARM같은 RISC 기반 CPU는 상대적으로 pipeline을 적용하기 수월했을 것이다. 


 pipeline이 이런 특징을 가지고 있기는 하지만 고려해줘야 할 사항도 있다. 

분명 pipeline을 쓰게 되면 throughput를 늘릴 수 있고, 이에 따라서 operating speed가 높아지는 효과를 가져온다고 언급했다. 하지만 연속적으로 처리되면서 서로 같은 영역을 Access하거나 순차적으로 이뤄지는 동안 원치않는 결과를 얻게 될 수도 있다. 보통 이걸 hazard라고 하고, 이 speed를 추구하는 동안 나타나는 hazard를 세 가지로 구분해서 각각에 대한 해결책을 제시한다. 설계시에는 이런 speed와 hazard간의 상관성을 고려해야 한다. 이 hazard에 관한 이야기는 다음 포스트에서 정리해보려고 한다.


- Reference 

 Instruction Set : http://en.wikipedia.org/wiki/Instruction_set

 Instruction Pipeline : http://en.wikipedia.org/wiki/Instruction_pipeline

그림으로 설명한 pipeline : http://www-ee.eng.hawaii.edu/~tep/EE461/Notes/overview2.html

OLC - Computer Architecture : http://olccenter.or.kr

댓글