오늘 끝나면
파이프라인과 해저드
- ✓파이프라인과 해저드의 핵심 문제를 한 문장으로 설명한다
- ✓오른쪽 실습에서 파이프라인과이 어떻게 움직이는지 관찰한다
- ✓다음 강의와 이어지는 한계를 말할 수 있다
실습 미션
명령을 겹쳐 처리 — stall·forwarding·flush·CPI 이 문장이 실제로 무슨 뜻인지 실습에서 한 번 손으로 확인한다.
성공 조건
- □실습의 기본값을 먼저 관찰
- □입력값이나 모드를 한 번 이상 바꿔 결과 비교
- □왜 결과가 바뀌었는지 한 문장으로 설명
반도체 설계 · 22
파이프라인과
해저드
한 명령을 끝낸 뒤에야 다음을 시작하면 나머지 단계는 그동안 놀고 있다.
다섯 단계를 겹쳐 흘리면 사이클마다 명령이 하나씩 완성된다.
대신 앞 명령의 결과가 아직 안 나왔는데 뒤 명령이 그 값을 쓰려는 충돌, 해저드가 생긴다.
단계를 겹쳐 처리량을 올린다
명령 하나는 IF·ID·EX·MEM·WB 다섯 단계를 거친다. 한 명령을 다 끝낸 뒤에 다음을 시작하면 매 사이클 네 단계가 놀고 있다.
IF는 명령 꺼내기, ID는 해독과 레지스터 읽기, EX는 연산, MEM은 메모리 접근, WB는 결과 쓰기다.
단계마다 회로가 따로 있으니, 한 명령이 EX에 있을 때 다음 명령은 ID를, 그다음은 IF를 동시에 처리할 수 있다.
이렇게 겹치는 것이 파이프라인이다. 명령 하나에 걸리는 시간(지연)은 그대로지만, 한 번 차오르고 나면 사이클마다 명령 하나가 완성된다.
5단계면 이상적으로 처리량이 약 5배가 된다. 현대 CPU가 빨라진 핵심 트릭이 바로 이것이다.
RAW 해저드, 앞 결과를 뒤가 바로 쓴다
겹치는 것이 공짜는 아니다. ADD R1, … 바로 뒤에 SUB R4, R1, …가 오면, R1은 아직 WB 전이라 레지스터에 들어 있지 않다.
앞 명령의 결과를 뒤 명령이 곧바로 읽으려는 충돌을 RAW 해저드(Read After Write)라 부른다. 가장 흔한 데이터 해저드다.
순진하게 두면 뒤 명령이 옛날 R1을 읽어 결과가 틀어진다.
막는 방법은 두 가지다. 하나는 stall로, 결과가 준비될 때까지 뒤 명령을 멈춰 세운다(버블 삽입).
다른 하나는 forwarding이다. EX에서 막 나온 결과를 레지스터를 거치지 않고 다음 EX 입력으로 바로 흘려준다. 멈추지 않고도 최신 값을 쓸 수 있다.
SUB의 EX(사이클4)가 ADD의 WB(사이클5)보다 먼저라 R1이 아직 없다
load-use는 forwarding으로도 1버블이 남는다
forwarding이 만능은 아니다. LD R6, [R4]의 데이터는 MEM 단계가 끝나야 손에 들어온다. EX 결과가 아니라서 미리 앞당겨 흘려줄 값이 없다.
바로 뒤 ADD R7, R6, R6가 R6을 EX에서 쓰려 해도, 데이터가 아직 메모리에서 나오지 않았다. 이것이 load-use 해저드다.
이때는 forwarding을 켜도 한 사이클 버블이 불가피하다.
그래서 컴파일러는 load 바로 뒤에 그 값을 안 쓰는 명령을 끼워 넣어 버블을 메우기도 한다. 하드웨어는 못 메우면 stall 한 칸으로 처리한다.
forwarding으로 RAW는 대부분 0버블이고 load-use만 1버블이 남는다.
LD 데이터는 MEM(사이클4) 끝에 나온다. ADD EX를 사이클5로 1칸 밀어야 forward가 가능하다
직접 흘려보는 forwarding·stall 토글
명령 5개를 한 사이클씩 흘려본다. forwarding과 stall 토글로 버블이 어디에 끼는지가 달라진다.
forwarding 칸은 점선, 버블은 흐린 칸, 잘못된 길로 들어와 버려진 명령은 빗금(╳)으로 표시된다.
stall OFF로 두면 해저드를 무시하고 그냥 겹쳐서 사이클은 최소가 되지만, 준비 안 된 레지스터를 읽어 결과가 틀어진다. 그래서 빨간 경고가 뜬다.
단계 수 5가 이 칩의 파이프라인 깊이이고, 그대로 최종 MyChip에 들어간다.
| 명령 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|---|---|---|---|---|---|---|---|---|---|---|
| ADD R1, R2, R3 | ||||||||||
| SUB R4, R1, R5 | ||||||||||
| LD R6, [R4] | ||||||||||
| ADD R7, R6, R6 | ||||||||||
| BEQ R7, R0, L | ||||||||||
| OR R8, R1, R2 | ||||||||||
| AND R9, R3, R4 |
forwarding ON, EX 결과를 다음 EX로 바로 흘려 RAW 대부분을 0버블로 막는다. 단 LD→ADD는 데이터가 MEM 끝에야 나와 1버블(load-use)이 남는다. 분기는 2칸 flush다.
단계 수 5(IF·ID·EX·MEM·WB)가 이 칩의 파이프라인 깊이이고, 그대로 최종 MyChip에 들어간다. 깊을수록 클럭은 빨라지지만 flush 손해도 커진다.
분기 flush와 CPI로 성능을 숫자로 잰다
분기도 해저드다. BEQ가 갈지 말지는 EX에서야 정해지는데, 그동안 IF는 다음 줄을 계속 가져오고 있다.
분기가 점프로 판명되면, 그새 파이프라인에 들어온 잘못된 명령들을 통째로 버려야 한다. 이것을 flush라 부른다. 5단계에서는 보통 2칸이 날아간다.
그래서 분기 예측이 빗나갈 때마다 손해가 쌓이고, 파이프라인이 깊을수록 flush 손해가 커진다.
성능은 CPI(Cycles Per Instruction)로 잰다. 명령당 평균 몇 사이클이 걸렸는지를 뜻한다.
이상적인 파이프라인은 CPI 1에 수렴한다. stall이나 flush가 끼면 1보다 커진다.
전체 시간은 명령 수 × CPI × 클럭 주기다. 설계는 이 셋의 곱을 줄이는 줄다리기다.
Q. forwarding이 해결하는 것은?
정답은 앞 명령의 결과를 기다리느라 생기는 stall(RAW 해저드)이다.EX에서 막 나온 결과를 레지스터(WB)를 거치지 않고 다음 EX 입력으로 바로 흘려주어, 멈추지 않고도 최신 값을 쓴다.
단 load 결과는 MEM 끝에야 나오므로 load-use는 forwarding으로도 1버블이 남고, 분기 flush는 데이터 해저드가 아니라 별개로 처리한다.
flush는 2칸 손해다
| 경우 | 사이클 | stall | flush | CPI |
|---|---|---|---|---|
| 이상적 | n+4 | 0 | 0 | →1.00 |
| forward ON | 10 | 1 | 2 | 2.00 |
| forward OFF | 17 | 8 | 2 | 3.40 |