파이프라인과 벡터처리 - 파이프라인 CPU의 성능분석
패스트캠퍼스에서 컴퓨터 구조 강의 를 듣고 스스로 공부한 내용을 정리하고 있습니다.
파이프라인 분기 예측
파이프라인의 대부분은 명령어 파이프라인 command pipeline 인데, 이 친구들이 정상적인 동작에서 벗어나게 되는 요인에는 다음과 같은 이유들이 있다.
1. 자원충돌 resource conflict
두 세그먼트가 동시에 메모리를 접근하려고 하면 자원충돌이 발생하게 되는데, 이는 명령어 메모리와 데이터 메모리를 분리함으로써 대부분 해결할 수 있다.
2. 데이터 의존성 data dependency
충돌은 어떤 명령어가 이전 명령어의 결과에 의존하여 수행되는데, 그 값이 아직 준비되지 않은 경우에 발생한다.
데이터의존성 : 세그먼트에서 아직 준비되지 않은 데이터를 기다리는 경우.
예를들면, FO에 의해서 피연산자를 fetch 하려는데, 아직 EX 세그먼트에 의해 데이터가 만들어지지 않은 경우
주소의존성 : 마이크로 연산시에 레지스터 간접모드를 사용하는 명령어는 이전 명령어가 주소값을 메모리로부터 로드하는 명령어라면, 곧바로 피연산자를 fetch 하지 못하고 기다리게 된다.
이런 경우는 어떻게 해결할 수 있을까?
하드웨어 인터락 hardware interlock
하드웨어 인터락은 파이프라인을 지나면서 어떤 명령어의 피연산자가 이전에 지나간 명령어의 목적지와 일치하는지를 검사하는 회로이다.
ADD R1
->SUBTRACT R2 - R1
이러한 상황이 감지되면 피 연산자가 준비되지 않은 명령어는 충돌을 피할 수 있을 만큼 충분한 클럭사이클을 두어서 지연시킨다.
말하자면, 아무 기능도 하지 않는 명령어를 중간에 두어서 연산 결과값이 준비되기 이전에 다음 명령어가 실행되지 않도록 지연시키는 것이다.
오퍼랜드 포워딩 operand forwarding
오퍼랜드 포워딩은 충돌이 감지되면, 특별한 통로를 통해서 직접 파이프라인 세그먼트에 전달하는 것이다.
말하자면, 색인같은 것을 달아주는 셈! 충돌이 감지되면 다른 루트로 안내
3. 분기곤란 branch difficulty
분기 명령어같이 PC의 값을 변경시키려는 명령어에 의해서 발생한다. 조건분기나 무조건 분기는 사실상 프로그램의 순서를 바꾸어 버리기 때문에 파이프라인 시스템을 채택하고 있는 컴퓨터의 성능을 저하시키는 주 요인으로 간주되고 있다.
그렇다면, 이 문제는 어떻게 해결할 수 있을까?
순차적으로 처리될 명령어를 분기의 목표가 되는 명령어와 함께 저장하는 방법
분기 목표 버퍼 (branch target buffer, BTB)의 활용
fetch 세그먼트에 속해있는 associative memory 를 활용하여 이전에 실행된 분기 명령어와 분기 목표 명령어를 저장하여 활용한다.
associate memory : 주소가 아닌 내용에 의해 검색이 가능한 기억장치
loop buffer : 일종의 레지스터
분기 예측 branch prediction
마이크로 명령어는 비교적으로 규칙적으로 반복되는 것들이 많다.
이러한 배경을 바탕으로 예측을 한다는 것!
예측기법을 이용해서 분기명령어나 적재 명령어가 참조하는 오퍼랜드도 반복적으로 참조할 때에는 규칙성을 가지고 있으므로 이를 활용할 경우에 명령어 fetch 과정에서 신속하게 오퍼랜드를 제공할 수 있고 fetch 가 더 수월해질 수 있다.
다만 예측이 실패할 경우에는 그만큼 시간지연이 더 된다는 패널티가 있다.
RISC Reduced Instruction Set Computer 프로세서
설계 목표
간단한 명령어들을 모아놓는다.
비록 실행해야할 명령어의 수는 늘어날지라도 작업처리시간은 감소될 수 있다.
명령어 당 실행 클록수(CPI) 와 클록주기를 파이프라인 구조를 이용하여 획기적으로 감소시킬 수 있다.
파이프라인 구조와 잘 맞는 컴퓨터 설계라고 볼 수 있음!
구조적인 특정
세트구성 = 명령어 1 사이클 실행을 위한 파이프라인 구조 + 메모리 참조를 위한 온칩캐쉬(CPU내 메모리 구현, 명령어캐쉬, 자료캐쉬로 구성됨)
간단한 명렁코드 + 주소지정모드 + 하드와이어적 제어장치
하드웨어로 미리 구현이 되면 딱 알맞다
신속하게 오퍼랜드를 참조하고, 문맥을 전환하기 위한 레지스터 집합 (중첩된 레지스터 윈도우)
실수 연산을 별도로 처리하기 위해서 코 프로세서가 존재
닮았다...!
세그먼트 수가 늘어날수록 실행시간이 짧아지는 파이프라인구조
명령어 수가 늘어날수록 작업처리시간이 감소되는 RISC 의 구조
RISC 파이프라인
RISC 파이프라인은 구조가 정말 간단하기 때문에 3개의 세그먼트로 주로 이루어져 있다.
I : 명령어 Instruction 의 fetch
A : ALU 동작
E : 명령어의 실행 Execution
눈에 띄는 점은 3번 라인의 No-Operation 이다. 앞서 살펴봤던것처럼 충돌이나 데이터의 의존성이 생길 경우, 중간에 살짝 지연시간을 두는 것이다. 이러한 처리는 보통 프로그램에 의해서 처리하지 않고 효율적인 컴파일러를 통해서 처리한다.
파이프라인 CPU 성능분석
이론적으로는 명령어 세그먼트의 횟수가 많아질수록 파이프라인의 이론적 최대속도가 증가할 것으로 분석이 되었지만, 사실 현실세계에서 실제 상황은 그렇게 단순하지 않다. 파이프라인이 성능상 효과적이기 위해서는 아래와 같이 되어야 하는데 실제 상황에서는 불가능하기 때문이다.
파이프라인의 성능을 높이기 위한 조건 (현실에서 불가능)
모든 명령어는 동일한 처리과정(세그먼트의 적용)으로 처리되어야 한다.
파이프라인을 구성하는 각 단계의 처리 시간이 일정해야한다.
하지만 현실에서는 각 세그먼트 내부 부연산의 처리시간은 같을 수 없다.
모든 명령어는 작성된 순서에 따라서 순차적으로 실행되어야 한다.
하지만 실생활에서는 분기명령, 함수호출, 반환명령 등에 의해서 순차성이 깨진다.
사용 명령어들 사이에는 상호 의존성이 없어야한다.
하지만 이전 세그먼트의 결과값을 다음 연산에 사용하는 것은 너무도 흔한 일이다.
명령어들 처리 시에 공유자원의 충돌이 없어야한다.
하지만 이전 세그먼트의 결과값을 다음 연산에 사용하는 것은 너무도 흔한 일이다.
Last updated