Pipeline
슈퍼스칼라 기술과 함께 CPU의 속도를 향상시키기 위한 회로 내지는 회로설계 기법을 지칭한다.
1 개요
CPU의 회로는 스위치 역할을 하는 많은 수의 트랜지스터[1]가 연결된 회로로 구성되며 이 회로들은 시스템 클럭에 의해 동기화되어 동작된다. 즉 시스템 클럭이 일정 횟수가 입력될 동안 트랜지스터 회로들은 소정의 처리작업을 완료하고 다음 처리동작이 가능한 상태가 되어야 한다. 이 과정에서 주의해야 할 요소는 다음과 같다.
- 트랜지스터 자체의 스위칭 속도는 무한하지 않으며 물리적 한계가 존재한다. 이 한계를 예를 들어 100MHz라고 가정하자.
- CPU 회로에서 트랜지스터들의 동작이 시작되는 위치에서부터 동작이 종료되는 위치까지 직렬 연결된 최대 단계가 100단계라고 가정한다.
- 그럴 경우 예로 든 CPU 회로는 각 트랜지스터의 동작속도가 100MHz라고 해도 전체 회로의 동기화는 직렬 연결된 최대 길이 100단계의 제약을 받기 때문에 회로에 입력할 수 있는 최대 클럭은 100MHz/100 = 1MHz가 된다.
그리고 어느 날 어떤 공돌이가 이런 멋진 생각을 하게 되었다.
"중간 중간에 동작 상태를 저장해 놓고 다음 클럭이 들어왔을 대 그 상태를 다음 단계로 넘겨주면 직렬연결 단계를 줄이게 되면서 동작클럭을 높일 수 있지 않을까?"
CPU 회로에서의 파이프라인이라는 개념이 탄생하는 순간이었다.
즉 중간에 동작 상태 저장 단계를 5개 추가했다고 가정하면 같은 100MHz짜리 트랜지스터라고 해도 직렬연결의 단계는 100단계에서 최대 20단계로 줄어들게 되고 해당 CPU 회로가 수용할 수 있는 클럭은 100MHz/20stage=5MHz까지 증가하는 것이었다.
파이프라인에 대한 전통적인 설명은 4단 파이프라인 구조를 통한 것이며 대체로 다음과 같은 명칭을 가지고 있다.
- 1단계 : fetch(명령어를 메모리에서 인출)
- 2단계 : decode(명령어 해석)
- 3단계 : execute(명령어 실행)
- 4단계 : writeback(라이트백)
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명이 할때 걸리는 시간보다 다음 사람한테 넘기는 시간이 훨씬 짧기 때문에 클럭을 올리기 쉬워진다. 하지만 클럭이 올라갔을뿐 실질적으로 걸리는 시간은 비슷하다.[2]
2 역사
파이프라인이라는 개념이 단일칩 CPU에 도입된 것은 최소한 1980년대 초 RISC의 태동과 궤적을 같이 했을 것으로 추정된다. 이후 파이프라인 단계의 확장 역사는 다음과 같다.
3 한계
파이프라인 기법은 '모든 명령이 원하는대로 수행된다'는 것을 가정하기 때문에, 이 가정이 깨지는 순간 혼돈의 카오스가 터진다.
우선 기존에 사용하던 메모리를 다시 사용할 때 부터 문제가 된다. 동일한 위치의 메모리를 사용하는데 '쓰기' 명령이 파이프라인에 어느 곳에 있고, '읽기' 명령은 다른 곳에 있는 경우 발생하기 쉬운데, 아직 파이프라인에서 처리되지 못한 데이터를 사용해야 하는 상황이 오기 때문이다. 이를 '데이터 위험'(Data Hazard)라 하는데, '읽고 나서 다시 읽는'(Read after Read) 것만 빼고는 어느 단계에서 '쓰든' 무조건 데이터 위험에 들어간다. (약자를 따서 각 RAW, WAR, WAW 위험이라 한다. A는 After의 약자이고, W는 당연히 Write의 W이다.) 때문에 이러한 위험을 만난 경우 CPU 차원에서 No Operation(명령 없음)을 넣어 후속 명령을 사실상 파이프라인 밖으로 쫓아내고 있다.
분기 명령 예측에 실패하면 일은 걷잡을 수 없이 커진다. 사실 이게 파이프라인 기법이 가장 크게 욕을 먹는 이유로, A를 가정하고 처리하고 있었는데 알고 보니 A가 아니라 B를 처리해야 했던 상황이라면, A로 가정하고 처리하던 것은 전부 버려야 한다. (CPU 자체에는 저장소의 제약사항이 상당하므로 재활용도 할 수 없다.) 이를 '구조적 위험'(Structural Hazard)이라 하는데, 이 위험은 분기가 덕지덕지 붙은 프로그램에서 더욱 심하다. 심지어는 실제로 낭비되는 처리 단계가 아키텍처의 파이프라인 깊이보다도 훨씬 커질 수 있다. 실제로 31단계의 파이프라인이 있는 프레스캇의 경우 연속 예측 실패 4방이면 100단계가 그냥 낭비된다. 무너지는건 한순간이지만 다시 세우는건 아닙니다. 이 때문에 구조적 위험을 '분기 예측 실패'라고도 한다.
4 해결 방법, 그러나 다시 한계
그래도 일반적인 환경에서는 평균적으로 성능 향상이 있기에 많은 개선이 시도되었다.
우선 위험성을 예측하는 알고리즘이 사용되고는 있지만, 그냥 지연시키는 방법의 복잡도가 [math]O\left(n\right)[/math]인 마당에 [math]O\left(n^3\right)[/math]이라서 최악의 경우에는 안하는 것만도 못하는 일도 발생한다.
또 다른 방법은 uOP 캐시를 이용하는 것인데, CPU의 프론트 엔드에서 프로그램의 명령어를 마이크로 명령어(uOP)로 해독하는 과정에서 명령어들을 적재하고 인덱싱하는 기법이다. 이 과정에서 uOP는 RISC의 특징을 따라가게 되는데, 이를 통해 전력 소모를 낮추면서도 단위 시간 당 처리 능력이 향상되었다. 실제로 이 기법이 적용된 스카이레이크의 경우, 같은 클럭의 프레스캇에 비해 효율이 높다. 하스웰에 대비해서는 약간 뒤쳐지긴 했지만, 이는 파이프라인과 uOP 증설을 동시에 처리하면서 발생한 것인 데다가, 공정미세화와 고도의 전력 컨트롤 기법을 통해 단위 클럭 당 전력 소모를 개선 시킨 것이라 모호하다.
그 외의 방법으로 명령어 및 데이터 선인출, 투기적실행, 분기예측, 레지스터 재명명, 명령어 프리디코드 등의 여러 기법들이 개발되고 적용되어 파이프라인의 문제점들을 상당 부분 완화시키긴 했으나, 그러한 추가 기능을 하드웨어 차원에서 구현하다 보니 대량의 트랜지스터가 추가로 되면서 결국 CPU의 구조가 더욱 복잡해지는 결과를 낳았다.
또한 파이프라인을 깊게 설계하면서 클럭을 끌어올리는 전략은 물리적인 법칙으로 인하여 발열 문제로 돌아왔고, 결국 2004년 경 4GHz의 벽에 막히면서 중단되었다. 그 이후로 인텔은 31단계에 이르렀던 깊은 파이프라인을 다시는 시도하지 않게 된다. 게다가 무어의 법칙 마저 경제적, 물리학적 한계로 버린 이상, 현재의 깊이 마저 더욱 줄여야 할 형편이 되었다.
5 의의
현대의 CPU 중에서 어느 정도 성능을 지향하도록 개발된 CPU 중 파이프라인 구조를 채택하지 않은 CPU는 사실상 없으며 특히 적극적인 파이프라인의 도입은 1980년대 말~2000년대 초에 경험했던 급격한 CPU 클럭의 향상과 그로 인한 CPU 성능 향상에 지대한 공헌을 하였다. 비록 2004년도 31단계라는 무지막지한 파이프라인 구조를 끝으로 파이프라인 단계 확대의 움직임은 제동이 걸린 상황이지만 그 이후의 CPU들 조차도 파이프라인 구조 없는 설계는 생각하기도 힘들다.
하지만 수행 시간에 민감한 특수 아키텍처, 특히 군사 & 우주용 CPU 아키텍처라면 얘기가 달라진다. 파이프라인 자체가 안전성 면에서 취약한 구조이니 만큼 ms(밀리초), 심지어는 μs(마이크로초) 단위를 다투는 하드웨어에 쓰기에는 위험해도 너무 위험하다. 이 때문에 관련 업체들은 칩을 직접 생산하면서까지 파이프라인을 피하려 하고 있으며, 어느 정도의 지연을 허용한다 해도 3~4단계로 그치는 게 대부분이다. 구식 아키텍처에 기반한 호환 CPU가 여전히 생산되고 있는 것도 다 이러한 수요가 있어서 그렇다.
6 관련용어
- Deep Pipeline : 상술한 31단계 같은 단수가 높은 파이프라인을 칭하는 말. 그러나 후술할 버블을 과도하게 발생시키는 문제가 있다.
- Bubble : 딥 파이프라인 안에 No-Operation 혹은 딥 파이프라이닝으로 초래된 이미 변경되었으나 파이프 안에 들어온 데이터, 즉 쓸모 없이 CPU만 점유하고 있는 데이터를 칭한다. 관념적으로는 이런 버블을 빨리 파이프라인에서 빼 주어야 효율이 상승한다.
- No Operation : CPU파이프라인 전체가 모두 다 빌 때까지 인풋을 대기하는 어셈블리 명령어. 해저드를 회피할 수 있는 가장 강력한 수단이지만, 실질적으로 파이프라인의 의미를 퇴색시키고, 성능을 떨어트린다.