핵심 인사이트 (3줄 요약)
- 본질: RAW (Read After Write)는 앞선 명령어가 값을 아직 기록하지 않았는데, 뒤 명령어가 그 값을 먼저 읽으려 할 때 생기는 진성 데이터 의존성 (True Data Dependency) 이다.
- 가치: RAW를 제대로 다루지 못하면 파이프라인은 빨라지는 대신 틀린 값을 계산하므로, 성능보다 먼저 정확한 실행 순서 보존이 핵심이 된다.
- 판단 포인트: 포워딩으로 해결 가능한 RAW와 반드시 스톨이 필요한 Load-Use 상황을 구분하는 능력이 제어 유닛과 컴파일러 최적화의 수준을 가른다.
Ⅰ. 개요 및 필요성
RAW (Read After Write)는 어떤 명령어가 만든 결과를 다음 명령어가 곧바로 사용하려 할 때, 아직 결과 기록이 끝나지 않아 충돌하는 현상이다. 파이프라인은 여러 명령어를 겹쳐 실행해 처리량을 높이지만, 이 겹침 때문에 "논리적 순서"와 "물리적 실행 시점"이 어긋날 수 있다. 바로 그 틈에서 가장 대표적으로 발생하는 데이터 해저드 (Data Hazard)가 RAW다.
순차 실행만 하던 시절에는 앞 명령어가 끝난 뒤 다음 명령어가 시작되므로 이런 문제가 거의 드러나지 않았다. 하지만 명령어 인출, 해독, 실행, 메모리 접근, 결과 기록을 동시에 겹치는 파이프라인에서는 뒤 명령어가 너무 일찍 출발한다. 결과가 아직 준비되지 않았는데도 읽기를 시도하면, 프로그램은 최신값이 아닌 이전값을 사용해 잘못된 계산을 하게 된다.
결국 RAW를 제어하는 목적은 "빠르게"가 아니라 "순서를 어기지 않고 빠르게"이다. 프로세서는 사람 눈에는 동시에 움직이는 것처럼 보여도, 데이터의 인과관계만큼은 절대 어기면 안 된다. 그래서 제어 유닛은 RAW를 감지하면 값을 우회 전달하거나, 불가피하면 잠깐 멈춰서라도 정답을 보장한다.
- 📢 섹션 요약 비유: RAW는 앞사람이 계약서에 서명하기도 전에 뒷사람이 그 계약서를 들고 은행에 가는 상황과 같다. 종이는 넘어갔지만 효력은 아직 없으므로, 잠깐 기다리거나 서명 직후 내용을 바로 전달받아야 한다.
Ⅱ. 아키텍처 및 핵심 원리
RAW는 파이프라인 단계별 시점 차이에서 생긴다. 대표적인 5단계 파이프라인은 IF (Instruction Fetch), ID (Instruction Decode/Register Read), EX (Execute), MEM (Memory Access), WB (Write Back)로 구성된다. 문제는 뒤 명령어가 ID 단계에서 레지스터를 읽을 때, 앞 명령어는 아직 EX나 MEM 단계에 있어서 결과를 레지스터 파일에 기록하지 않았을 수 있다는 점이다.
다음 그림은 왜 RAW가 단순한 이름 충돌이 아니라, 실제 시간 축 위의 충돌인지를 보여준다.
┌──────────────────────────────────────────────────────────────────────────────┐
│ RAW 발생 시점: 읽는 순간이 쓰는 순간보다 빠름 │
├────────┬────────┬────────┬────────┬────────┬────────────────────────────────┤
│ Clock │ 1 │ 2 │ 3 │ 4 │ 5 │
├────────┼────────┼────────┼────────┼────────┼────────────────────────────────┤
│ I1:ADD │ IF │ ID │ EX │ MEM │ WB ── t0 기록 │
│ I2:SUB │ │ IF │ ID │ EX │ MEM ... │
│ │ │ │ t0 읽기 │ │ │
├────────┴────────┴────────┴────────┴────────┴────────────────────────────────┤
│ 충돌 지점: I2는 Clock 3에 t0가 필요하지만, I1은 Clock 5가 되어야 t0를 쓴다. │
└──────────────────────────────────────────────────────────────────────────────┘
이 문제를 해결하는 대표 기법은 포워딩 (Forwarding)이다. 포워딩은 결과가 레지스터 파일에 정식 기록되기 전이라도, ALU (Arithmetic Logic Unit)나 메모리 단계에서 막 생성된 값을 다음 명령어 입력으로 바로 우회 전달한다. 제어 유닛은 목적지 레지스터와 소스 레지스터를 비교해 충돌을 감지하고, 멀티플렉서 경로를 바꿔 가장 최신값을 선택한다.
┌──────────────────────────────────────────────────────────────────────────────┐
│ 해결 방식: 레지스터 기록을 기다리지 않고 우회 전달 │
├──────────────────────────────────────────────────────────────────────────────┤
│ I1: ADD ── EX 결과 생성 ───────────────┐ │
│ ├──▶ Forwarding Path ──▶ I2 EX 입력 │
│ Register File 기록(WB)은 나중 수행 ────┘ │
└──────────────────────────────────────────────────────────────────────────────┘
하지만 모든 RAW가 포워딩으로 해결되지는 않는다. 대표적인 Load-Use 해저드는 LW r1, 0(r2) 다음에 곧바로 ADD r3, r1, r4가 오는 경우다. 로드 데이터는 MEM 단계가 끝나야 나오는데, 뒤 명령어는 그보다 먼저 EX 단계에서 피연산자를 요구하므로 물리적으로 값이 아직 없다. 이때는 인터락 (Interlock)으로 파이프라인을 1사이클 이상 멈추고 버블 (Bubble)을 넣어 시간을 맞춘다.
| 상황 | 값이 준비되는 시점 | 뒤 명령어가 필요한 시점 | 대표 해법 |
|---|---|---|---|
| 산술 결과 의존 | EX 종료 직후 | 다음 EX | 포워딩 가능 |
| 메모리 로드 의존 | MEM 종료 직후 | 바로 다음 EX | 스톨 필요 가능성 큼 |
| 긴 지연 연산 의존 | 다중 사이클 이후 | 소비 시점 다양 | 스코어보드/대기 필요 |
- 📢 섹션 요약 비유: RAW 해결은 주방에서 완성 접시를 창고에 넣기 전에 바로 서빙 직원에게 건네는 것과 같다. 다만 아직 조리가 끝나지 않은 음식은 아무리 급해도 건넬 수 없으니, 그때는 손님을 잠깐 기다리게 해야 한다.
Ⅲ. 비교 및 연결
RAW를 제대로 이해하려면 WAR (Write After Read), WAW (Write After Write)와 구분해야 한다. RAW는 데이터 자체의 선후관계가 얽힌 진짜 의존성이라서 이름만 바꿔 없앨 수 없다. 반면 WAR와 WAW는 주로 같은 레지스터 이름을 공유해서 생기는 가짜 의존성이라, 레지스터 리네이밍 (Register Renaming)으로 상당 부분 해소할 수 있다.
| 구분 | 의미 | 왜 생기는가 | 대표 해결책 |
|---|---|---|---|
| RAW | 먼저 쓴 값을 나중에 읽어야 함 | 실제 데이터 흐름 때문 | 포워딩, 스톨, 비순차 실행 |
| WAR | 먼저 읽어야 하는데 뒤가 먼저 쓰려 함 | 이름 재사용 때문 | 레지스터 리네이밍 |
| WAW | 두 쓰기 중 마지막 결과 보존 필요 | 이름 재사용 때문 | 레지스터 리네이밍, 완료 순서 관리 |
또한 RAW는 단순 파이프라인 이론을 넘어 슈퍼스칼라와 비순차 실행 (Out-of-Order Execution)으로 연결된다. 현대 CPU (Central Processing Unit)는 RAW 때문에 막힌 명령어를 무조건 앞줄에 세워 두지 않고, 뒤에 있는 독립 명령어를 먼저 실행해 공백을 메운다. 즉 RAW는 병렬 실행의 적이면서도, 동시에 더 똑똑한 스케줄링 기법이 등장하게 만든 출발점이기도 하다.
운영체제와 컴파일러 관점에서도 연결점이 있다. 컴파일러는 명령어 스케줄링으로 RAW가 심한 코드 배치를 완화하고, 하드웨어는 스코어보드 (Scoreboard)나 토머설로 알고리즘 (Tomasulo Algorithm)으로 준비된 명령어부터 보낸다. 결국 RAW는 하드웨어 문제이면서 소프트웨어 배치 품질까지 드러내는 경계 개념이다.
- 📢 섹션 요약 비유: RAW는 앞사람이 써 준 재료가 있어야만 다음 요리를 시작할 수 있는 관계이고, WAR·WAW는 같은 선반 이름을 여러 사람이 써서 헷갈리는 관계에 가깝다. 전자는 재료가 실제로 필요하고, 후자는 보관함 이름표를 바꾸면 상당수 풀린다.
Ⅳ. 실무 적용 및 기술사 판단
실무에서 RAW를 다룰 때 첫 판단은 "이 의존성이 성능 병목으로 얼마나 자주 반복되는가"이다. 루프 내부에서 결과를 즉시 다시 쓰는 누적 합산, 포인터 체이싱, 직렬화된 암호 연산은 RAW 비중이 높아 파이프라인 효율을 크게 떨어뜨린다. 반대로 독립 연산이 풍부한 벡터 처리나 멀티미디어 코드는 RAW의 압박이 상대적으로 낮다.
설계자는 먼저 포워딩 경로가 어디까지 필요한지 정해야 한다. EX→EX, MEM→EX 경로만으로 대부분의 산술 의존성을 줄일 수 있지만, 경로가 늘수록 멀티플렉서와 비교 로직이 복잡해지고 임계 경로도 길어진다. 즉 "스톨 감소"와 "제어 복잡도 증가" 사이의 균형이 설계 포인트다.
컴파일러와 소프트웨어 최적화도 중요하다. Load 뒤에 바로 소비 명령을 붙이지 않고 독립 명령을 사이에 끼우면, 하드웨어가 강제로 쉬어야 하는 시간을 다른 일로 채울 수 있다. 기술사 답안에서는 이런 하드웨어-소프트웨어 협력을 함께 말해야 단순 암기가 아니라 설계 판단으로 보인다.
실무 체크포인트
- 포워딩으로 해결 가능한 RAW와 Load-Use처럼 스톨이 불가피한 RAW를 분리했는가?
- 포워딩 네트워크가 늘어나면서 클럭 주기와 배선 복잡도가 악화되지 않는가?
- 컴파일러 스케줄링, 레지스터 할당, 비순차 실행이 하드웨어 한계를 얼마나 보완하는가?
피해야 할 안티패턴
-
누적 변수 하나에 모든 계산이 직렬로 매달리는 코드 구조
-
메모리 로드 직후 즉시 소비하는 패턴을 반복하는 루프
-
하드웨어 포워딩만 믿고 코드 배치를 전혀 고려하지 않는 최적화 전략
-
📢 섹션 요약 비유: RAW 대응은 막히는 차선마다 무조건 도로를 더 까는 일이 아니다. 어디는 우회도로를 만들고, 어디는 신호를 잠깐 멈추고, 어디는 애초에 차량 배치를 바꿔 정체를 줄이는 교통 설계에 가깝다.
Ⅴ. 기대효과 및 결론
RAW를 정확히 관리하면 파이프라인은 프로그램 의미를 보존한 채 높은 처리량을 낼 수 있다. 포워딩은 불필요한 대기를 줄여 성능을 올리고, 인터락은 잘못된 값을 쓰는 치명적 오류를 막아 신뢰성을 지킨다. 즉 RAW 제어는 성능 최적화 기법이기 전에 정확성 유지 장치다.
다만 RAW는 완전히 사라지지 않는다. 데이터에 실제 선후관계가 있는 한, 어떤 아키텍처도 인과관계를 무시하고 앞질러 갈 수는 없다. 그래서 현대 시스템은 RAW 자체를 제거하기보다, 드러나는 지점을 숨기고 대기 시간을 다른 작업으로 메우는 방향으로 진화해 왔다.
결국 RAW는 "파이프라인의 약점"이 아니라 "병렬 처리의 경계선"으로 기억하는 것이 맞다. 이 경계선을 이해해야 포워딩, 스코어보드, 비순차 실행, 컴파일러 스케줄링이 왜 필요한지 한 번에 연결된다.
- 📢 섹션 요약 비유: RAW는 릴레이 경기에서 반드시 바통을 받아야만 다음 주자가 뛸 수 있는 규칙과 같다. 중요한 것은 규칙을 없애는 것이 아니라, 바통 전달을 최대한 빠르고 안전하게 만들어 전체 기록을 올리는 것이다.
📌 관련 개념 맵
| 개념 | 연결 포인트 |
|---|---|
| 데이터 해저드 (Data Hazard) | RAW는 데이터 해저드의 가장 대표적인 형태다. |
| 포워딩 (Forwarding) | 레지스터 기록 전 값을 우회 전달해 산술 RAW를 줄인다. |
| 인터락 (Interlock) | 하드웨어가 RAW를 감지하면 자동으로 스톨과 버블을 삽입한다. |
| 비순차 실행 (Out-of-Order Execution) | RAW로 막힌 명령어를 기다리며 독립 명령어를 먼저 실행한다. |
| 레지스터 리네이밍 (Register Renaming) | WAR·WAW에는 강력하지만 RAW 자체는 없애지 못한다. |
📈 관련 키워드 및 발전 흐름도
명령어 파이프라이닝
│
▼
데이터 해저드 (Data Hazard)
│
├──▶ RAW (Read After Write): 진성 의존성
│ │
│ ├──▶ 포워딩 (Forwarding)
│ └──▶ 인터락 (Interlock) · 스톨 (Stall)
│
▼
스코어보드 · 토머설로 알고리즘 (Tomasulo Algorithm)
│
▼
비순차 실행 (Out-of-Order Execution) · 슈퍼스칼라 최적화
이 흐름은 단순 파이프라인 충돌 감지에서 출발해, 동적 스케줄링과 고성능 실행 구조로 확장되는 발전 방향을 보여준다.
👶 어린이를 위한 3줄 비유 설명
- 앞 친구가 답을 공책에 다 쓰기 전에 뒷친구가 먼저 베껴 보면 틀린 답을 가져가게 돼요.
- 컴퓨터도 앞 계산이 끝나기 전에 뒤 계산이 값을 읽으려 하면 이런 실수를 할 수 있어요.
- 그래서 컴퓨터는 답이 나오자마자 바로 건네주거나, 잠깐 기다리게 해서 꼭 맞는 답만 쓰게 해요.