나무모에 미러 (일반/어두운 화면)
최근 수정 시각 : 2024-11-25 01:27:03

파이프라인

파이프라이닝에서 넘어옴

파일:나무위키+유도.png  
은(는) 여기로 연결됩니다.
운송 수단에 대한 내용은 파이프라인(운송) 문서
번 문단을
부분을
, 2021년 한국 영화에 대한 내용은 파이프라인(영화) 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
, 에 대한 내용은 문서
번 문단을
번 문단을
부분을
부분을
참고하십시오.
1. 개요2. 상세3. 역사4. 한계5. 해결 방법, 그러나 다시 한계6. 의의7. 관련 용어8. 관련 항목

1. 개요

Pipeline

한 데이터 처리 단계의 출력이 다음 단계의 입력으로 이어지는 형태로 연결된 구조를 가리킨다. 이렇게 연결된 데이터 처리 단계는 한 여러 단계가 서로 동시에, 또는 병렬적으로 수행될 수 있어 효율성의 향상을 꾀할 수 있다.

대표적인 파이프라인 구조는 다음과 같은 것들이 있다.

2. 상세

디지털 집적회로는 스위치 역할을 하는 많은 수의 트랜지스터[1]가 연결된 조합 논리 회로[2]들과 상태값을 기억하는 레지스터로 구성된다. 레지스터는 매 클럭 주기마다 조합 논리 회로의 출력값에 따라 내부 상태가 갱신된다. 따라서 조합 논리 회로들은 다음 클럭 주기가 도래하기 전 처리작업을 완료하고 값을 출력해야 한다. 이 과정에서 주의해야 할 요소는 다음과 같다.

그리고 어느 날 어떤 공돌이가 이런 멋진 생각을 하게 되었다.
"중간 중간에 동작 상태를 저장해 놓고 다음 클럭이 들어왔을 때 그 상태를 다음 단계로 넘겨주면 직렬연결 단계를 줄이게 되면서 동작클럭을 높일 수 있지 않을까?"

디지털 집적회로에서의 파이프라인이라는 개념이 탄생하는 순간이었다.

즉 중간에 동작 상태 저장 단계를 5개 추가했다고 가정하면, 같은 100MHz짜리 트랜지스터라고 해도 직렬연결의 단계는 100단계에서 최대 20단계로 줄어들게 되고, 해당 회로가 수용할 수 있는 클럭은 100MHz/20stage=5MHz까지 증가하게 된다.

CPU의 명령어 파이프라인에 대한 전통적인 설명은 4단 파이프라인 구조를 통한 것이며 대체로 다음과 같은 명칭을 가지고 있다.

4단 파이프라인에서 작업 A와 B를 처리할 때(트랜지스터 40개, 동작속도 40Hz):
1사이클: fetch(A) → 2사이클 fetch(B),decode(A) → 3사이클 decode(B),execute(A) → 4사이클 execute(B),writeback(A,완료) → 5사이클 writeback(B,완료)
순서이고 40Hz/40=1Hz의 속도를 내던 CPU가 40Hz/10=4Hz 속도를 내므로 2작업을 5사이클(1.25초)만에 끝마칠수 있고, 파이프라인이 없다는 가정하에 1작업이 1사이클이 소모되므로 2초가 걸린다.

쉽게 설명하자면 파이프라인이 도입되기 전에는 1명이 하나의 일을 처음부터 끝까지 처리했다면 파이프라인이 도입 이후에는 한가지 작업만 할수있는 사람 여러명을 차례대로 놔두고 하나의 큰 작업을 조그만 작업으로 쪼개서 다음사람에게 순서대로 넘기는 방식으로 실행한다. 이렇게되면 하나의 작업을 1명이 할때 걸리는 시간보다 다음 사람한테 넘기는 시간이 훨씬 짧기 때문에 클럭을 올리기 쉬워지게 되어 특정 조건에서 동작 속도를 크게 올릴 수 있다.

비유를 통해 좀 더 쉽게 생각해보자. 어떤 자동차 공장에 자동차를 대량으로 만들어달라는 주문이 들어왔다. 이 공장에는 자동차 생산 공정에 필요한 모든 장비가 일렬로 늘어서 있어서, 처음부터 끝까지 모두 선만 따라가면 되도록 설계되어 있다. 우선 이 공장은 금속 가공, 가공이 끝난 후 기계장치 제작, 그 후로 차체 제작, 차체 조립, 성능 테스트를 순서대로 모두 마쳐야 자동차를 출고한다고 가정하자. 첫 번째 차량을 만들기 위해 금속 가공을 시작하고, 가공이 끝난 후 기계 장치를 만들었으며, 차체를 만들고 이를 조립하여 성능을 테스트하고 출고했다. 그런데 문제는, 한 대를 만드는데에 온 정신이 팔려서 작업을 마친 공정은 다음 공정에 작업물을 넘겨주고는 그냥 놀고 있었다는것이다. 그리고는 차가 완성되어 출고되고 생산라인이 완전히 텅텅 비워질 때까지 새로운 차량의 제작 역시 시작하지 않는다. 이는 비효율적이다.

따라서, 공장장은 이러한 비효율적 운영을 피하기 위해 각각의 공정에서 작업이 끝나는대로 다음 공정으로 넘기고, 곧바로 이전 공정에서 작업을 받아 일을 하도록 시켰다. 이렇게 되면 모든 공정이 전부 착착 돌아가게 되어 더 효율적으로 자동차가 찍혀나오게 된다.

CPU도 마찬가지로, 1초에 수백만번의 명령어를 처리하는 요즘 컴퓨터들 역시 명령어를 "읽고", 이 명령어가 무슨 뜻인지 "이해"하고, 이해한 명령어를 "실행"하는 등 일단 읽고 넘기기만 하는 공정, 앞에서 받은 명령어를 이해만 하고 넘기는 공정, 또 앞에서 받은 명령어를 실행만 하는 공정 등등으로 비유해볼 수 있다. 만약 이렇게 착착 진행되지 않는다면 명령어 하나를 다 읽고 이해하고 실행해서 마무리가 될 때까지 다 놀고 있는데 아직 앞 명령어 처리가 안 끝났단 이유로 뒤에 줄 서있는 명령어들은 애꿎은 시간낭비만 하게 된다. 이것을 해결할 기술이 바로 파이프라이닝이다.

어느 날, 자동차를 열심히 조립하고 있던 한 일꾼이 크게 당황했다. 웬 오토바이 부품이 들어와서 지나가고 있었던 것이다. 뭔가 잘못됐음을 깨달은 일꾼은 이 차체를 그냥 지나가게 냅뒀다간 뒤쪽 공정에서도 시간낭비만 초래할 것임을 알아냈고, 차체 외부에 파란색 깃발을 꽂아 표시했다. 이는 "쓸모가 없거나 잘못 들어와 쓸 수 없는 부품"을 의미한다. 따라서 뒤쪽 공정에서 일하던 일꾼들도 파란 깃발이 꽂힌 차체를 보면 "이 차체는 뭔가 잘못됐구나" 하면서 이걸 들어내서 빼버리던가, 아니면 그냥 완성 지점까지 냅둬서 저 끝에서 걸러내도록 해서 이것 때문에 헛짓을 하지 않게 될 것이다. 이것을 CPU 파이프라이닝에서 "버블"이라고 부른다. 관련 용어 문단 참조.

3. 역사

파이프라인이라는 개념은 ENIAC이 처음 나오기 이전 시절인 1939년 Z1부터 ILLIAC II와 IBM Stretch 프로젝트를 한정으로 처음 사용되었고, 1970년대부터 슈퍼컴퓨터메인프레임에 본격적으로 도입되었으며, 개인용 컴퓨터는 1980년대 초 RISC의 태동과 궤적을 같이 하여 본격적으로 도입했을 것으로 추정된다. 이후 파이프라인 단계의 확장 역사는 다음과 같다.

2004년 펜티엄 4 프레스캇의 31단계를 기점으로 파이프라인 단계가 다시 축소되었다. 만약, 개발 취소된 테자스가 출시되었다면 40~50단계가 최고점이었을지도 모른다. 그래서 오히려 성능이 하락한 것으로 추측을 할 수도 있지만, 파이프라인 단계의 깊이가 증가하는 것은 자연스럽게 '클럭수의 증가' 를 가져오게 되는데 클럭의 증가는 곧 전력 소모 증가와 옴의 법칙에 따른 발열의 증가가 발생했으며, 고발열은 성능 저하는 물론 칩 자체의 손상을 가져오고 쿨링 대책 또한 감당 못 할 수준에 이르렀다. 즉 흔히 말하는 전성비가 파이프라인이 더 적을 때 보다 떨어지게 되었다. 이를 4 GHz의 벽 이라고도 부른다. 자세한 내용은 문서 참조. 그래서 이때를 기점으로 코어 하나의 파이프라인과 클럭을 늘려 성능을 확보하는 것이 아니라 코어를 여러 개 배치하여 성능을 높이는 멀티코어 프로세서가 등장하면서 시장을 정복했으며 높은 단계의 파이프라인 단계는 사장되었다.

4. 한계

파이프라인 기법은 '모든 명령이 원하는대로 수행된다'는 것을 가정하기 때문에, 이 가정이 깨지는 순간 혼돈의 카오스가 터진다.

우선 기존에 사용하던 메모리를 다시 사용할 때 부터 문제가 된다. 동일한 위치의 메모리를 사용하는데 '쓰기' 명령이 파이프라인에 어느 곳에 있고, '읽기' 명령은 다른 곳에 있는 경우 발생하기 쉬운데, 아직 파이프라인에서 처리되지 못한 데이터를 사용해야 하는 상황이 오기 때문이다. 이를 '데이터 위험'(Data Hazard), 또는 '데이터 의존성(Data Dependency)'이라 하는데, '읽고 나서 다시 읽는'(Read after Read) 것만 빼고는 어느 단계에서 '쓰든' 무조건 데이터 위험에 들어간다.[8][9] (약자를 따서 각 RAW, WAR, WAW 위험이라 한다. A는 After의 약자이고, W는 당연히 Write의 W이다.) 때문에 이러한 위험을 만난 경우 CPU 차원에서 No Operation(명령 없음)을 넣어 후속 명령을 사실상 파이프라인 밖으로 쫓아내고 있다. 또한 WAR, WAW Hazard는 레지스터 이름 변경(register renaming)을 통해 부분적으로나마 없애는 것이 가능하다. 따라서 실제로 데이터 위험이 존재하는 의존성은 RAW 하나로 볼 수 있다. 이는 프로그램의 흐름에 따라 결정되기 때문에 Flow Dependency라고도 하며 '진짜 위험'이라는 뜻으로 True Dependency라고도 한다.

분기 명령 예측에 실패하면 일은 걷잡을 수 없이 커진다. A를 가정하고 처리하고 있었는데 알고 보니 A가 아니라 B를 처리해야 했던 상황이라면, A로 가정하고 처리하던 것은 전부 버려야 한다.[10] 이를 Control Hazard라 하는데, 이 위험은 분기가 덕지덕지 붙은 프로그램에서 더욱 심하다. 심지어는 실제로 낭비되는 처리 단계가 아키텍처의 파이프라인 깊이보다도 훨씬 커질 수 있다. 실제로 31단계의 파이프라인이 있는 프레스캇의 경우 연속 예측 실패 4방이면 100단계가 그냥 낭비된다. 무너지는건 한순간이지만 다시 세우는건 아닙니다.

5. 해결 방법, 그러나 다시 한계

그래도 일반적인 환경에서는 평균적으로 큰 성능 향상이 있기에 많은 개선이 시도되었다.

우선 위험성을 예측하는 알고리즘이 사용되고는 있지만, 그냥 지연시키는 방법의 복잡도가 O(n)O\left(n\right)인 마당에 O(n3)O\left(n^3\right)이라서 최악의 경우에는 안하는 것만도 못하는 일도 발생한다.

또 다른 방법은 uOP 캐시를 이용하는 것인데, CPU의 프론트 엔드에서 프로그램의 명령어를 마이크로 명령어(uOP)로 해독하는 과정에서 명령어들을 적재하고 인덱싱하는 기법이다. 이 과정에서 uOP는 RISC의 특징을 따라가게 되는데, 이를 통해 전력 소모를 낮추면서도 단위 시간 당 처리 능력이 향상되었다. 실제로 이 기법이 적용된 스카이레이크의 경우, 같은 클럭의 프레스캇에 비해 효율이 높다. 하스웰에 대비해서는 약간 뒤쳐지긴 했지만, 이는 파이프라인과 uOP 증설을 동시에 처리하면서 발생한 것인 데다가, 공정미세화와 고도의 전력 컨트롤 기법을 통해 단위 클럭 당 전력 소모를 개선 시킨 것이라 모호하다.

그 외의 방법으로 명령어 및 데이터 선인출, 투기적실행, 분기 예측, 레지스터 재명명, 명령어 프리디코드 등의 여러 기법들이 개발되고 적용되어 파이프라인의 문제점들을 상당 부분 완화시키긴 했으나, 그러한 추가 기능을 하드웨어 차원에서 구현하다 보니 대량의 트랜지스터가 추가로 되면서 결국 CPU의 구조가 더욱 복잡해지는 결과를 낳았고, 2018년에 CPU게이트가 일어나는데 일조를 하게 되었다.

또한 파이프라인을 깊게 설계하면서 클럭을 끌어올리는 전략은 물리적인 법칙으로 인하여 발열 문제로 돌아왔고, 결국 2004년 경 4 GHz의 벽에 막히면서 중단되었다. 그 이후로 인텔은 31단계에 이르렀던 깊은 파이프라인을 다시는 시도하지 않게 된다. 게다가 무어의 법칙 마저 경제적, 물리학적 한계로 버린 이상, 현재의 깊이 마저 더욱 줄여야 할 형편이 되었다.

6. 의의

현대의 CPU 중에서 어느 정도 성능을 지향하도록 개발된 CPU 중 파이프라인 구조를 채택하지 않은 CPU는 사실상 없으며 특히 적극적인 파이프라인의 도입은 1980년대 말~2000년대 초에 경험했던 급격한 CPU 클럭의 향상과 그로 인한 CPU 성능 향상에 지대한 공헌을 하였다. 비록 2004년도 31단계라는 무지막지한 파이프라인 구조를 끝으로 파이프라인 단계 확대의 움직임은 제동이 걸린 상황이지만 그 이후의 CPU들 조차도 파이프라인 구조 없는 설계는 생각하기도 힘들다.

하지만 수행 시간에 민감한 특수 아키텍처, 특히 군사 & 우주용 CPU 아키텍처라면 얘기가 달라진다. 파이프라인 자체가 안전성 면에서 취약한 구조이니 만큼 ms(밀리초), 심지어는 μs(마이크로초) 단위를 다투는 하드웨어에 쓰기에는 위험해도 너무 위험하다. 이 때문에 관련 업체들은 칩을 직접 생산하면서까지 파이프라인을 피하려 하고 있으며, 어느 정도의 지연을 허용한다 해도 3~4단계로 그치는 게 대부분이다. 구식 아키텍처에 기반한 호환 CPU가 여전히 생산되고 있는 것도 다 이러한 수요가 있어서 그렇다.

7. 관련 용어

8. 관련 항목



[1] 게이트라는 표현도 쓴다. 현용 대부분의 CPU의 집적회로CMOS 기술로 구현되며 CMOS의 트랜지스터의 가운데 극의 이름이 게이트이기 때문.[2] 대표적으로 ALU 같은 것들이 있다.[3] 이전 명령어의 실행이 끝난 다음 명령어를 인출하는 8085와 달리 명령어 실행 중 버스를 사용하지 않는 사이클동안 다음 명령어를 미리 인출(prefetch)하는 2단계 파이프라인 구조이다. 단, 이후 등장한 RISC 방식의 CPU와 달리 여러 개의 더 작은 명령어로 이뤄진 마이크로코드를 통해 x86 명령어 동작을 구현하였기 때문에 실행 단계에 1 사이클이 소요된다고 가정한 위의 예시와는 달리 8086의 경우 ADD와 같은 간단한 명령어의 경우에도 피연산자에 따라 3-31 사이클이 소요되고, 명령어에 따라 최소 2 사이클(CLC, HLT, ...)에서 많게는 204 사이클이 소요된다.(IDIV mem16, base+index+disp., segment override)[4] 명령어 인코딩이 복잡해짐에 따라 디코드와 실행을 별도의 stage로 분리하였다.[5] 실행 단계에서 최소 2사이클을 소모하였던 이전의 x86 CPU와는 달리 여러 명령어를 1 사이클만에 실행할 수 있게 되었다.[6] 슈퍼스칼라 구조를 도입하였다.[7] 비순차적 실행 및 내부적으로 RISC 구조를 도입하였다.[8] 간단하게 예를 들어보자. 여러분이 컴퓨터에게 "A는 3이고, B는 4이다. 여기서 B는 A에다가 8을 더한 값으로 수정하도록 하겠다. 그러면 B값은 얼마인가 계산해달라." 하는 프로그램을 짰다고 가정하자. 우리가 원하는 정답은 B = 11이다. 그러나 컴퓨터는 이것을 정답으로 내놓지 못할수도 있다. A는 3이고, B가 4이며, B값을 A에다가 8을 더한값으로 수정하는건 좋은데, B값을 최종적으로 계산해서 다시 저장하기 전에 B값이 얼마인지 묻는 명령이 들어오면 B값을 계산하긴 했으나 아직 저장하지 못했기 때문에 값이 최신화 되지 못하고 예전에 저장되어있던 값인 4를 답으로 내놓게 되고, 이는 오류가 되는 것이다.[9] 세 사람이 앉아있고 100미터쯤 떨어진 곳에 계산기가 놓여있는 책상이 있으며, 이 사이를 왔다갔다하는 일꾼이 있다고 가정하자. 첫 번째 사람은 명령을 외치기만 하고, 두 번째 사람은 숫자를, 세 번째 사람은 일꾼을 보내 계산을 시키거나 명령이 완료되면 "오케이!"라고 외친다. 첫 번째 명령이 들어오자, "숫자 저장", "A=3"이었고, 이를 알아들은 세 번째 사람이 오케이라고 외쳤다. 두 번째에는 "숫자 더하기", "8"이라고 명령이 들어오자, 세 번째 사람은 일꾼을 시켜 계산기로 뛰어가 3+8이 얼마인지 계산시킨다. 아직 일꾼이 계산기가 있는 책상으로 뛰어가고 있는 중인데, 세 번째 명령으로 "결과 계산", "A"라는 명령이 들어왔는데, 일꾼은 아직도 계산기를 두들기고 있고 정답을 아직 이쪽으로 갖고오지 못했다. 따라서 세 번째 사람의 메모지엔 아직 A=3이라고 적혀있었고, 결국 "오케이! 정답은 3!"이라고 말한다. 당연히 오류.[10] CPU 자체에는 저장소의 제약사항이 상당하므로 재활용도 할 수 없다. 때문에 처리가 틀렸다면 쓰던 자원을 가급적 빨리 버려야 하는데, 이것을 늦추다 보면 다음 명령을 처리하는 데에 시간 낭비가 심할 뿐만 아니라 해커의 공격에 취약해 질 수 있다.