검색
회원가입로그인
AI와 함께 공부하기 : 컴퓨터 구조

CPU: 파이프라인 해저드란?

Pipeline Hazards

파이프라인 해저드(Pipeline Hazards)는 명령어 파이프라인의 성능을 저해하고, 올바르지 않은 결과를 초래할 수 있는 상황들을 일컫습니다. 파이프라인은 여러 명령어를 동시에 처리함으로써 CPU의 처리량(throughput)을 높이는 강력한 기술이지만, 특정 상황에서는 의존성(dependency) 문제로 인해 명령어가 순차적으로 실행될 때와 다른 결과가 나오거나, 파이프라인의 효율성이 떨어질 수 있습니다.

파이프라인 해저드는 크게 세 가지 주요 유형으로 분류됩니다.


1. 구조적 해저드 (Structural Hazards)

  • 정의: 여러 명령어가 동시에 파이프라인의 같은 하드웨어 자원을 요청할 때 발생합니다. 마치 한 번에 한 명만 들어갈 수 있는 화장실을 두 명이 동시에 사용하려고 할 때 발생하는 병목 현상과 유사합니다.

  • 원인: 단일 메모리(명령어 및 데이터), 단일 레지스터 파일 포트, 단일 ALU 등 공유 자원의 경합이 주된 원인입니다.

  • 예시:

    • 단일 메모리: IF(Instruction Fetch) 단계에서 명령어를 인출해야 하는데, MEM(Memory Access) 단계에서 데이터를 메모리에서 읽거나 써야 하는 경우, 단일 포트 메모리에서는 동시에 접근할 수 없으므로 충돌이 발생합니다.

    • 단일 레지스터 파일 포트: ID(Instruction Decode) 단계에서 레지스터를 읽어야 하고, WB(Write Back) 단계에서 레지스터에 써야 하는데, 레지스터 파일이 동시에 읽기와 쓰기를 지원하지 않는 경우.

  • 해결 방법:

    1. 파이프라인 정지(Stalling) : 충돌이 해결될 때까지 한 명령어의 진행을 잠시 멈추고 다른 명령어가 자원을 사용하도록 합니다. 이는 파이프라인의 효율성을 일시적으로 저하시킵니다.

    2. 자원 복제(Duplication): 충돌이 발생하는 자원을 복제하여 여러 명령어가 동시에 사용할 수 있도록 합니다. (예: 명령어 메모리와 데이터 메모리를 분리하는 하버드 아키텍처, 레지스터 파일에 여러 포트 추가)


2. 데이터 해저드 (Data Hazards)

  • 정의: 파이프라인에 있는 명령어들이 서로 데이터 의존성을 가질 때 발생합니다. 즉, 나중에 실행되는 명령어가 이전에 실행되는 명령어의 결과값을 필요로 하는데, 그 결과값이 아직 계산되지 않았거나 레지스터 파일에 기록되지 않았을 때 생기는 문제입니다.

  • 유형:

    • RAW (Read After Write) - True Data Dependency: 가장 흔한 유형으로, 읽기 전에 쓰기가 완료되어야 하는 경우입니다. 명령어 A가 레지스터 R에 값을 쓰고, 명령어 B가 그 R의 값을 읽으려고 할 때, A의 쓰기가 B의 읽기보다 늦게 끝나면 발생합니다.

      • I1 : ADD R1, R2, R3 (R1에 값을 씀)

      • I2 : SUB R4, R1, R5 (R1의 값을 읽음)

      • I1에서 WB 단계를 거친 후 I2에서 R1의 값을 읽어야 하지만, WB이 되지 않은 채로 읽어 문제가 발생합니다.

      • I2가 ID 단계 일 때, I1이 EX, MEM, WB 일 때 문제가 발생합니다.

  • 해결 방법:

    • 포워딩(Forwarding) / 바이패싱(Bypassing): 가장 일반적이고 효과적인 방법입니다. 아직 레지스터 파일에 기록되지 않은 중간 결과를 파이프라인 레지스터(예: EX/MEM, MEM/WB)에서 직접 다음 단계의 ALU 입력으로 전달하여 데이터 의존성을 해결합니다.

      • 하지만, lw 인 경우 값을 메모리에서 불러와야 하기 때문에 포워딩 / 바이패싱을 하지 못하고 한 단계를 stall 해야 하는 문제가 있습니다. (load-use data hazard)

    • 컴파일러 스케줄링(Compiler Scheduling): 컴파일러가 명령어의 순서를 재배열하여 데이터 의존성을 가진 명령어들 사이에 독립적인 명령어들을 끼워 넣어 해저드를 피하거나 최소화합니다.

      • Load-use data hazard 의 경우 명령어 순서를 재배열하여 해저드를 피하도록 조정합니다.

      • lw (파란 박스)의 $t4 를 lw 아랫줄의 add 에서 사용하기 때문에 lwMEM 단계에 도달했을 때 addEXE에 도달하게 되어 문제가 발생합니다.

      • 이때, 위 그림처럼 add(빨간 박스), lw(파란 박스) 를 변경하는 경우 load 할 때까지 시간을 갖게 되어 문제를 해결할 수 있습니다.

  • Data Hazard Conditions

  • WAW, WAR은 병렬 연산 시 발생할 수 있습니다.

    • WAW (Write After Write) - Output Dependency: 두 명령어가 같은 레지스터에 값을 쓰려고 할 때, 순서가 바뀌면 발생하는 문제입니다. 나중 명령어가 먼저 값을 쓰고, 이전 명령어가 나중에 값을 쓰게 되면 잘못된 최종 결과가 나옵니다. 현대 파이프라인에서는 드물게 나타나며, 주로 순서 없는(out-of-order) 실행 파이프라인에서 문제가 될 수 있습니다.

      • I1 : MUL R1, R2, R3 (R1에 값을 씀)

      • I2 : ADD R1, R4, R5 (R1에 값을 씀)

    • WAR (Write After Read) - Anti-dependency: 읽기 전에 쓰기가 발생하면 안 되는 경우입니다. 명령어 A가 레지스터 R을 읽고, 명령어 B가 그 R에 값을 쓰려고 할 때, B의 쓰기가 A의 읽기보다 먼저 일어나면 잘못된 결과를 읽을 수 있습니다. WAW와 마찬가지로 순서 없는 실행에서 문제가 될 수 있습니다.

      • I1 : ADD R1, R2, R3 (R3를 읽음)

      • I2 : MUL R3, R4, R5 (R3에 값을 씀)

    • (추후 보충)


3. 제어 해저드 (Control Hazards)

  • 정의: 분기(branch) 명령어, 점프(jump) 명령어, 예외(exception) 등 프로그램 카운터(PC)의 흐름을 변경하는 명령어 때문에 발생합니다. 분기 명령어가 실제 어느 주소로 갈지(즉, 분기할지 말지)는 파이프라인의 뒤쪽 단계(MIPS의 경우 EX 단계)에서 결정되는데, 그 사이에 이미 파이프라인의 앞쪽 단계(IF, ID)에서는 미리 다음 명령어를 인출해버린 상태일 때 문제가 생깁니다.

  • 원인: PC의 다음 값을 미리 예측하기 어렵거나, 예측이 틀렸을 때 발생합니다.

  • 예시:

    • beq $t0, $t1, label

    • beq 명령어가 실행되고 분기할지 말지 결정되기 전에, 파이프라인은 이미 beq 명령어 다음의 명령어를 미리 가져와서 처리하기 시작합니다. 만약 분기가 실제로 발생하면, 미리 가져온 명령어들은 쓸모없게 되므로 폐기해야 합니다.

    • 분기나 점프 명령어가 아니라면 PC+4를 통해서 다음 명령어를 실행 하지만 분기와 점프 명령어이기 때문에 다음 명령어가 아닌 점프를 통한 명령어로 이동해야 합니다.

  • 해결 방법:

    • 파이프라인 정지(Stalling) / 버블 삽입: 분기 결과가 결정될 때까지 파이프라인을 멈춥니다. 가장 간단하지만 비효율적인 방법입니다.

    • 분기 예측(Branch Prediction): 가장 널리 사용되는 방법입니다. 분기할지 말지 미리 예측하고 그에 따라 명령어를 인출합니다. 예측이 맞으면 성능 손실이 없고, 틀리면 예측 실패 패널티(잘못 가져온 명령어 폐기 및 올바른 경로로 다시 인출)가 발생합니다.

      • MIPS 에서는 분기가 선택될 확률이 평균적으로 약 53% 라고 합니다.

    • 두 분기 모두 실행(Execute both paths): 2개의 CPU로 두 분기를 모두 실행하고 둘 중 올바른 것을 실행합니다. 한 사이클도 손해를 보지 않지만 분기 개수에 따라 CPU 개수를 늘려야 합니다.

    • 지연 분기(Delayed Branch): (MIPS 등 일부 아키텍처에서 사용) 분기 명령어 뒤에 오는 특정 수의 명령어(지연 슬롯)는 분기 결과와 상관없이 항상 실행되도록 합니다. 컴파일러가 이 슬롯에 유용한 명령어를 채워 넣어 성능 손실을 줄입니다. (최신 고성능 CPU에서는 잘 사용되지 않음)

      • 재배치와 같이 분기 뒤에 큰 관련이 없는 instruction을 미리 처리함으로써 손실을 최소화하는 방법입니다.

    • Control Hazards Control


파이프라인 해저드는 CPU 설계에서 파이프라인의 효율성과 정확성을 보장하기 위해 반드시 고려하고 해결해야 하는 중요한 문제입니다. 현대 고성능 CPU는 이러한 해저드를 감지하고 해결하기 위한 복잡하고 정교한 하드웨어 로직을 내장하고 있습니다.


공유하기
카카오로 공유하기
페이스북 공유하기
트위터로 공유하기
url 복사하기