파이프라인은 일반적으로 IF(Instruction Fetch), D(Decode), E(Execute), MEM(Memory), WB(WriteBack) 단계를 가집니다.
파이프 라이닝은 여러 명령어를 중첩하여 실행시키는 기술입니다.
한 명령어를 처리하고 그 이후에나 다음 명령어를 처리시키는 기존 방식과 달리 한 사이클 안에서 쉬는 컴포넌트 없이 작업하여 더 효율적인 처리를 가능토록 합니다.
위에 사진에서 보면 알 수 있듯이 15사이클 만에 끝나던 것이 8사이클 더 빨리 7사이클 만에 끝났습니다.
모든 단계가 동일한 시간에 끝나면 좋겠지만 실제로는 처리시간이 다르기 때문에 약간의 중간중간 쉬는 시간이 있습니다.
x86(CISC)의 경우 명령어 중에 메모리에 직접 접근하는 명령이 있기 때문에 파이프라인에 바로 적용하면 명령어가 다른 명령어들에 비해 늦게 끝나 파이프라인을 뒤흔들 수 있고, x86의 명령어는 복잡하기 때문에 데이터 종속성으로 인해 중단될 가능성이 높습니다.
그래서 x86 명령어는 디코딩된 다음 μops(micro-operations)로 변환하여 μops로 변환하여 1사이클에 1 코드 실행이 가능하게 합니다.
width: 사용 가능한 파이프라인의 수 (최신 인텔 프로세서에선 일반적으로 4 개입니다.)
slots: 주기 당 프런트 엔드에서 발행하고 백엔드에서 폐기할 수 있는 고정된 수의 μop
(하나의 uop를 처리하는 데 필요한 하드웨어 리소스)
front-end: 프런트 엔드는 명령어를 가져오고 해석하여 μop로 변환합니다.
front-end-bound: 백 엔드가 이를 수용할 수 있음에도 불구하고 명령이 프런트 엔드에서 백 엔드로 이동하지 못할 때 발생합니다.
back-end: 비 순차적 스케줄러가 준비된 μop들을 각각의 실행 단위로 디스 패치하고, 완료되면 이러한 μops는 프로그램 순서에 따라 폐기되는 프로세서 코어의 일부
back-end-bound: 백엔드에서 새 μop들을 수락하는 데 필요한 리소스가 부족하여 μop들이 제공되지 않는 파이프 라인 슬롯 비율(프런트 엔드와 백엔드 모두 stall시 백엔드로 구분)
allocation: front-end에서 μop를 back-end로 넘기는 과정
retirement: μop의 실행 완료(보통 대부분의 μop들은 완전히 파이프라인을 통해 통과하고 리타이어 되지만, 종종 예측적으로 패치된 μop들은 리타이어 전에 취소될 수도 있습니다. 예: 예측 실패한 분기의 경우)
각 슬롯은 포함된 uop에 어떤 일이 발생하는지에 따라 주어진 주기에서 네 가지 범주 중 하나로 분류할 수 있습니다.
Front-End-Bound
이 예에서 명령어 B는 디코딩이 끝날 때까지 추가 주기를 취하고, 백엔드로 전달하는 대신 사이클 4의 해당 단계에 남아 있습니다. 이것은 여기에 느낌표로 표시된 파이프 라인 버블이라고 알려진 파이프 라인 아래로 전파되는 빈 공간을 만듭니다.
Back-End-Bound
이 예에서 명령 B는 실행하는 데 추가 사이클이 필요하며, 여전히 사이클 5에서 Execute 단계를 차지하고 있기 때문에 명령 C는 백엔드로 이동할 수 없습니다. 이것은 또한 파이프 라인 버블을 초래합니다.
꼭 Decode 또는 Execute 단계에서 지연이 발생하지 않아도 됩니다.
프런트 엔드 바운드 그림에서 B가 가져오기 위해 추가 주기를 수행한 경우 사이클 3에서 Decode 단계로 전달된 명령이 없어서 버블이 생성됩니다. 따라서 사이클 4에서 백엔드로 전달하라는 명령이 없습니다.
백엔드 바운드 그림에서 명령 A가 메모리 단계에서 추가 주기를 수행한 경우, 그러면 B는 준비가 되었는지 여부에 관계없이 사이클 5에서 Execute 단계를 벗어날 수 없었을 것입니다. 따라서 C가 백엔드로 진행하는 것을 차단하여 원래 위치에 남아 있습니다.
Bad Speculation
부분적으로 처리된 μop이 완료되기 전에 취소될 때마다 발생합니다. μop이 취소되는 가장 일반적인 이유는 분기 예측 오류 때문입니다.
정교한 알고리즘을 사용하여 분기 명령이 Execute 단계의 끝에 도달하기 전에 경로 X를 사용할지 Y를 사용할지 추측하여 파이프라인에 로드합니다.
여기에서 두 가지 가능한 결과가 있습니다.
- 분기 예측이 정확하고 상황이 정상적으로 진행됩니다.
- 분기가 잘못 예측되어 잘못된 명령이 삭제되고 거품이 제자리에 남고 올바른 명령이 파이프 라인에 들어가기 시작합니다.
성능 저하는 파이프 라인이 명령 로드를 시작하기 전에 분기 실행이 해결될 때까지 기다린 것과 사실상 동일하지만 분기가 발생할 때마다 발생하는 것이 아니라 예측 알고리즘이 잘못된 경우에만 발생합니다. 이 때문에 예측 알고리즘을 개선하기 위한 지속적인 노력이 있습니다.
결론적으론 분기 예측을 해서 맞으면 성능이 좋아지고, 예측에 실패하여 버블이 생긴다 하더라도 분기가 Execute 단계의 끝에 도달할 때까지 기다리는 성능과 같기 때문에, 성능 저하가 없습니다.
Pipeline Hazards
- 구조적 해저드(Structural Hazard)
한정된 자원. 한 개 이상의 명령어를 중복된 하드웨어에서 처리하고자 하는 상황이 발생합니다.
내부 버스에 두 모듈이 하나의 모듈로 동시에 신호를 보내면 처리가 불가능해서 구조적 Hazard 가 생깁니다.
예로는 메모리 입출력이 있습니다.
자원을 더 추가하거나 파이프라인 버블을 만들어 해결할 수 있습니다. (Pipeline Freezing이라고 부릅니다.)
- 데이터 해저드(Data Hazard)
명령어가 아직 처리 중인 앞선 명령어에 종속성을 가질 때 발생합니다.
- Read After Write (RAW)
- Write After Write (WAW)
- Write After Read (WAR)
예시에서는 첫 번째 명령에서 $2에 저장된 결과를 두 번째, 세 번째 명령에서 활용합니다.
pipeline을 적용하면서 $2가 저장되기 이전에 그 이후에 수행되어야 할 명령이 미리 수행되어 버려서
메모리에 값을 쓰기 전에 다른 명령에서 읽게 됩니다. 그러면 and와 or 연산은 $1과 $3이 Sub 한 결과가 아닌 이전에 들어있던 쓰레기 값으로 연산을 하게 됩니다.
해결방법은 간단합니다. pipeline freezing을 하여 앞선 명령어가 다 끝날 때까지 대기하거나, forwarding을 하여서 명령 실행 중간에 다른 모듈로 값을 넘겨주면 됩니다.
- 제어 해저드(Control Hazard)
분기 명령어의 결과를 MEM 단계에서 알 수 있기 때문에 결과가 나오기 전 명령이 잘못 처리되는 일이 발생합니다.
분기 예측(Branch prediction)을 사용하여 해결할 수 있습니다.
'해킹 > 과제' 카테고리의 다른 글
6. 추측 실행(Speculation Execution), 분기 예측(Branch Prediction) (0) | 2021.04.17 |
---|---|
5. 비순차적 실행(Out-of-order Execution) (0) | 2021.04.17 |
3. CPU의 명령어 처리 구조 (0) | 2021.04.16 |
2. 명령어 구조, CPU 구성요소 (0) | 2021.04.16 |
1. CPU 명령어 집합 구조 (0) | 2021.04.16 |