본문 바로가기
운영체제

컴퓨터 구조 : 명령어 파이프라이닝(Instruction Pipelining)

by oobw 2023. 10. 20.

CPU의 속도는 컴퓨터 시스템의 프로그램 처리 시간에 큰 영향을 주기 때문에, CPU의 성능을 향상하는 다양한 방법들이 연구 및 적용되고 있습니다. 그러한 방법 중에서도 간단하면서 효과적인 최적화 기법인 명령어 파이프라이닝(Instruction Pipelining)에 대해 이번 글에서는 소개하고자 합니다.

 

파이프라이닝의 작동 원리

파이프라이닝의 기본 기능은 공장의 조립 라인과 유사한 원리로 동작합니다. 프로세서는 명령어의 여러 단계를 동시에 처리함으로써, 한 번에 더 많은 명령어를 빠르게 실행할 수 있게 됩니다.

이 원리를 이해하기 위한 간단한 비유는 세탁하는 과정입니다. 세탁을 완료하기 위해서는 세탁하고, 건조한 후, 접는 세 단계가 있다고 생각해 보세요. 세탁물 하나당 30분 동안 세탁하고, 40분 동안 건조한 뒤, 20분 동안 접는다면 총 90분이 소요됩니다. 네 개의 더러운 세탁물이 있다고 가정해 봅시다. 네 개의 세탁물에 이 과정을 반복한다면 90분의 4번 총 360분이 필요합니다. 즉, 오후 6시에 시작한다면, 이 방법으로 모든 세탁물을 처리하는 데 자정까지 걸릴 것입니다.

 

파이프라이닝 단계1

 

 

하지만 파이프라이닝 원리에 따르면, 첫 번째 세탁물이 세탁되는 동안, 두 번째 세탁물을 준비하고 세탁기에 넣을 수 있습니다. 첫 번째 세탁물이 건조하는 동안, 두 번째는 세탁되고, 세 번째는 준비됩니다. 이런 식으로 각 단계를 최대한 활용하여 작업을 동시에 진행하면, 모든 세탁물을 처리하는 데 360분이 걸리던 것이 210분으로 단축되게 됩니다.

파이프라이닝 단계2

RISC 파이프라이닝

RISC와 CISC 프로세스 중에서 RISC 프로세스는 파이프라이닝에 최적화된 프로세스입니다. RISC 프로세서의 파이프라이닝은 여러 단계를 통해 구현되며, 프로세서별로 단계의 수는 다를 수 있습니다. 그러나 일반적으로 MIPS R3000 프로세서에서 사용되는 기본 다섯 가지 단계를 참고로 할 수 있습니다.

  1. 메모리에서 명령어를 가져옴
  2. 레지스터에서 값을 읽고 명령어를 디코딩
  3. 명령어 실행 혹은 주소 계산
  4. 데이터 메모리의 피연산자 접근
  5. 계산 결과를 레지스터에 저장

위에서 언급한 세탁 과정의 비유로 보면, 세탁기의 작업은 30분 동안 진행되지만, 건조기가 10분 더 걸리는 상황에서 젖은 옷은 건조기가 사용 가능해질 때까지 기다려야 합니다. 이러한 원리로, 파이프라이닝의 각 단계의 길이는 가장 긴 단계의 시간에 의존적입니다.

 

RISC 명령어 구조는 전통적인 CISC(Complex Instruction Set Computer) 명령어 구조에 비해 단순한 편입니다. CISC의 명령어는 길이가 다양할 수 있지만, RISC의 명령어는 일정한 길이를 갖고 있어 파이프라이닝에 유리합니다. 이상적으로 RISC 프로세서 파이프라인의 각 단계는 1 클록 사이클 동안 처리되어야 하며, 이로써 프로세서는 명령어 당 평균 하나의 클록 사이클(CPI)만을 필요로 합니다.

파이프라이닝의 문제점

실제 RISC 프로세서에서는 데이터 종속성과 분기 명령어 때문에 명령어 당 두 개 이상의 클록 사이클이 필요하게 될 수 있습니다. 이때 데이터 종속성 문제가 발생할 수 있습니다. 데이터 종속성은 한 명령어의 수행 결과가 다음 명령어의 입력으로 사용될 때 발생합니다. 

add $r3, $r2, $r1
add $r5, $r4, $r3

예를 들면, 여기서 첫 번째 명령어는 r1과 r2의 값을 더하여 r3에 저장하도록 지시하고, 두 번째 명령어는 r3와 r4의 값을 더하여 r5에 저장하도록 지시합니다. 파이프라이닝 시 첫 번째 명령어가 아직 r3에 결과를 저장하지 않았는데, 두 번째 명령어가 r3의 값을 필요로 할 경우 문제가 발생합니다. 이에 따라 파이프라인은 정지하게 되며, 여러 '버블'이 파이프라인 내에 생기게 됩니다.

 

MIPS에서는 이러한 데이터 종속성 문제를 해결하기 위해 코드 재배열을 통해 종속성이 없는 명령을 중간에 배치하여 파이프라이닝의 효율성을 높입니다. 일반적으로 이 재배열은 컴파일러가 수행합니다. 


분기 명령어는 특정 조건을 만족할 때만 특정 코드 블록을 실행하게 하는 명령어입니다. 

loop:
add $r3, $r2, $r1
sub $r6, $r5, $r4
beq $r3, $r6, loop

여기서 beq는 r3와 r6의 값이 같을 경우 'loop' 라벨로 점프하는 명령어입니다. 만약 r3 또는 r6의 값이 아직 결정되지 않았다면, 프로세서는 어떤 분기를 해야 할지 알 수 없습니다.

이러한 문제를 해결하기 위한 일반적인 방법의 하나는 분기 예측입니다. 프로세서는 특정 분기 경로를 예측하고 이를 따릅니다. 예측이 잘못되었다면 파이프라인을 재설정하고 올바른 명령어로 다시 시작합니다.

RISC System/6000과 같은 일부 프로세서들은 분기 예측의 과정을 건너뛰고, 분기의 두 경로 모두를 디코딩하여 가져옵니다. 분기를 결정한 후, 올바른 명령어를 실행 파이프라인으로 전달합니다.

파이프라이닝 구현

프로세서의 속도를 향상시키기 위해 파이프라인을 최적화하는 다양한 방법이 연구되었습니다.

슈퍼파이프라이닝은 파이프라인을 더 많은 단계로 나누는 기법을 의미합니다. 파이프 단계가 많으면 각 단계의 시간이 줄어들어 전체적인 파이프라인의 속도가 빨라집니다. 이론적으로, 5개의 스테이지를 가진 파이프라인은 파이프라인이 없는 프로세서(또는 1개 스테이지를 가진 파이프라인)보다 5배 더 빠를 것으로 예상됩니다. 명령은 각 단계가 완료되는 속도로 처리되며, 각 단계는 파이프라인 없이 명령어를 실행할 때 걸리는 시간의 1/5만큼 소요됩니다. 따라서 8단계 파이프라인을 가진 MIPS R4000 프로세서는 5단계 파이프라인보다 빠르다고 할 수 있습니다. MIPS R4000은 일부 단계를 세분화하여 파이프라인을 더욱 세분화하였습니다. 예를 들면, 명령어 가져오기는 이제 한 단계가 아닌 두 단계로 처리됩니다. 그 단계는 다음과 같습니다.

  1. 명령어 가져오기(전반)
  2. 명령어 가져오기(후반)
  3. 가져오기 등록
  4. 명령 실행
  5. 데이터 캐시 액세스(전반)
  6. 데이터 캐시 액세스(후반)
  7. 태그 확인
  8. 레지스터에 다시 쓰기

수퍼스칼라 파이프라이닝은 여러 파이프라인을 병렬로 실행하는 방식입니다. 프로세서 내부의 구성 요소들이 복제되어 여러 명령어를 동시에 처리할 수 있게 됩니다. RISC System/6000은 분기형 파이프라인을 가지며, 이는 부동 소수점 및 정수 명령어 처리 경로를 포함하고 있습니다. 두 유형의 명령어가 혼합된 프로그램의 경우, 프로세서는 두 경로를 동시에 실행할 수 있습니다. 두 유형의 명령어는 초기 단계인 명령어 가져오기와 명령어 디스패치를 공유합니다. 하지만 수퍼스칼라 파이프라이닝에서는 종종 모든 파이프라인 단계의 복제본들을 참조하게 됩니다. 최신의 프로세서들은 대부분의 파이프라인 단계에서 동시에 실행될 수 있는 2~6개의 명령어를 처리하려고 합니다. 그러나 명령어 간의 의존성이 있을 경우 첫 번째 명령어만이 실행될 것입니다.

수퍼스칼라


동적 파이프라이닝은 중단 시점을 중심으로 작업을 스케줄링하는 기법을 포함합니다. 동적 파이프라이닝은 명령어 가져오기와 디코딩 단계, 5~10개의 실행 또는 기능 단계, 그리고 커밋 단계의 세 가지로 구성됩니다. 각 실행 단계에는 예약 스테이션이라고 하는 버퍼가 있어 피연산자와 연산을 저장하게 됩니다.

 

기능 단위는 순서에 구애받지 않고 실행될 수 있으나, 명령어 가져오기/디코딩 및 커밋 단계는 파이프라인의 원활한 동작을 위해 일정한 순서로 작동해야 합니다. 명령어가 실행된 후 결과가 도출되면, 커밋 단계에서는 해당 결과를 안전하게 저장할 적절한 시점을 판단합니다. 만약 지연이 발생한다면, 프로세서는 그 지연이 해소될 때까지 다른 명령어의 실행을 예약할 수 있습니다. 이러한 방식은 동시에 여러 명령어를 실행하는 장치들의 효율성과 결합되어 동적 파이프라이닝을 매력적인 선택으로 만들어 줍니다.

마치며

파이프라이닝은 컴퓨터 과학과 전자공학에서의 혁신적인 발전 중 하나입니다. 물론 파이프라이닝은 그 자체만으로는 충분하지 않습니다. 최적의 성능을 위해서는 파이프라이닝과 다른 기술들, 예를 들어 슈퍼스칼라 기술, 동적 스케줄링, 분기 예측과 같은 기술들이 함께 사용되어야 합니다. 이러한 기술들의 결합은 프로세서 성능의 극적인 향상을 이끌어낼 수 있으며, 더욱 복잡한 알고리즘과 큰 데이터 세트를 처리하는 데 필요한 능력을 제공합니다.