오늘은 CPU의 프로그램 처리 속도를 향상시키는 명령어 파이프 라이닝에 대해서 알아보겠습니다.
1. 명령어 파이프라이닝
1) 명령어 파이프라이닝 개요
CPU의 성능은 컴퓨터시스템의 프로그램 처리 시간에 직접 영향을 주기 때문에, 그 속도를 향상시키기 위한 여러가지 방법들이 사용됩니다.
그중 가장 간단하고 효과적인 방법이 명령어 파이프라이닝 입니다. 명령어를 실행하는데 사용되는 하드웨어를 여러 개의 독립적인 단계(stage)들로 분할하고, 동시에 서로 다른 명령어들을 처리하도록 함으로써 CPU의 성능을 높여주는 기술 입니다. 명령어 파이프라인은 분할되는 단계의 수가 많아질 수록 그 속도가 높아지는 특징이 있습니다.
명령어 파이프라이닝(instruction pipelining): 명령어 실행에 사용되는 하드웨어를 여러 단계로 분할함으로써 처리 속도를 높여주는 기술
2) 2-단계 명령어 파이프라인
2-단계 명령어 파이프라인은 명령어를 실행하는 하드웨어를 인출 단계와 실행 단계로 분리하여 구성할 수 있습니다.
그림으로 설명해보겠습니다.
파이프라인을 사용하지않고서 3개의 명령어를 실행한다고 해봅시다.
각 명령어는 인출과 실행단계로 나눠놓고 각각 한주기씩 걸린다고 하였을 때 3개의 명령어를 실행하는데는 6클록주기가 걸립니다.
2-단계 명령어 파이프라인을 적용해보겠습니다. 각 단계는 서로 다른명령어에 대해서 각자의 동작을 수행합니다.
첫번째 클록주기 동안에 인출 단계가 첫번째 명령어를 인출합니다.
두번째 클록주기에서 인출된 명령어는 실행단계로 처리되고, 동시에 인출단계는 두번째 명령어를 인출합니다.
세번째 단계에서는 두번째 명령어의 실행과 세번째 명령어의 인출이 동시에 이루어집니다.
이는 다음에 실행될 명령어를 미리 인출하는 명령어 선인출 혹은 인출 중복으로 인해서 가능해집니다.
명령어 선인출(instruction prefetch): 다음에 실행될 명령어를 미리 인출하는 동작
2-단계 명령어 파이프라인이 적용되었을때, 3개의 명령어를 실행시키는데는 4클록주기가 걸렸습니다.
파이프라인을 적용하지 않았을 때 6클록주기가 걸렸으니, 속도향상은 1.5배가 되었습니다.
더 많은 수의 명령어를 실행시키는 경우에는 속도향상이 파이프라인 단계의 수와 같은 2배에 근접하게 됩니다.
그러나 이와 같은 속도 향상은 명령어의 인출과 실행에 같은 시간이 걸려야만 얻을 수 있습니다. 실제 명령어 처리 과정을 분석해보면, 일반적으로 실행단계에서 소요되는 시간이 인출 단계보다 더 길기 때문에, 인출단계는 하나의 명령어를 인출한 다음에 즉시 다음 명령어 인출을 실행시키지 못하고, 실행단계의 동작이 끝날때까지 기다려야 한다는 단점이 있습니다.
3) 4-단계 명령어 파이프라인
2-단계 파이프라인의 단점을 보완하기 위한 방법으로는, 단계를 더욱 세부적으로 나누는 방법이 있습니다.
여러개로 분할하며, 단계들의 처리시간이 거의 같아지도록 하는 것 입니다. 이러한 방법을 통해 속도 향상을 더욱 높일 수 있습니다.
4단계로 구분하는 4-단계 파이프라인에 대해 알아보겠습니다.
- 명령어 인출(IF): 명령어를 기억장치로부터 인출
- 명령어 해독(ID): 해독기를 이용하여 명령어를 해석
- 오퍼랜드 인출(OF): 기억장치로부터 오퍼랜드를 인출
- 실행(EX): 지정된 연산을 수행, 결과 저장
이런식으로 구성하면 각 단계에서 걸리는 시간이 거의 같아질 수 있습니다. 편의상 모두 같다고 했을때, 명령어들이 연속적으로 실행되는 경우의 시간흐름도는 다음과 같습니다.
이로인해 얻을 수 있는 속도향상을 식으로 나타내보면 다음과 같습니다.
명령어의 수가 커질 수록 속도향상은 파이프라인 단계에 근접하게 됩니다.
2. 파이프라이닝의 문제점
1) 파이프라이닝의 근본적인 문제점
파이프라이닝은 CPU의 속도를 향상시킬 수 있지만 몇가지 근본적인 문제점이 있습니다.
그 문제점을 4-단계파이프라인으로 예시를 들어 알아보도록 하겠습니다.
1.1) 모든 명령어들이 모든 파이프라인을 거칠 필요는 없다.
4-단계 명령어 파이프라인을 예로 들때, 어떤 명령어는 실행 과정에서 오퍼랜드를 인출할 필요가 없기 때문에, OF단계는 수행하지 않아도 됩니다. 하지만 파이프라인 하드웨어를 단순화시키기 위해서는 모든 명령어들이 네 단계를 모두 통과하도록 해야합니다. 결과적으로 OF단계를 수행하는데 걸리는, 불필요한 시간이 소모되게 됩니다.
1.2) 파이프라인 클록은 처리시간이 가장 오래 걸리는 단계를 기준으로 정해야 한다.
예를 들어 IF,ID 및 OF 단계의 처리가 각각 1ns 씩 걸리고, EX단계는 1.5ns가 걸린다면, 클록주기는 1.5ns로 결정되어야 합니다.
앞에서 처리가 먼저 끝나더라도 EX단계의 처리가 끝나기 전에는 그 결과를 보내주지 못하고 기다려야 하기 떄문입니다. 결과적으로 앞의 세 단계에서는 0.5씩 일찍 처리되어도 기다려야 하고 그로 인한 불필요한 시간이 소모되게 됩니다.
1.3) 기억장치 충돌
기억장치 충돌은 두 개 이상의 하드웨어 모듈들이 동시에 기억장치 엑세스를 시도하는 상황입니다. 하나의 기억장치 모듈을 두 단계가 동시에 엑세스할 수 밖에 없기 때문에 둘 중의 하나는 지연될 수 밖에 없습니다.
기억장치 충돌(memory conflict): 두 개 이상의 하드웨어 모듈들이 동시에 기억장치 엑세스를 시도하는 상황
1.4) 조건 분기 명령어
조건에 따라 다른 위치로 분기하도록 하는 명령어가 실행된다면, 미리 인출되어 처리되고 있던 명령어들이 무효화될 수 있습니다.
위의 흐름도에서 명령어 3이 실행되고 명령어 12부터 새로이 인출하여 실행되면서 명령어 4, 5, 6은 제거되고 있습니다.
조건 분기 명령어 : 지정된 조건이 만족하는 경우에는 프로그램 처리 순서를 변경하는 명령어
2) 성능 저하를 최소화 하기 위한 방법
위의 문제들은 파이프라이닝 구조가 가지고 있는 근본적인 것으로 완전히 해결할 수는 없지만, 보완하기 위한 많은 노력이 이루어지고 있습니다.
두번째 문제점을 해결하기 위한 방법으로 슈퍼파이프라이닝이 있습니다. 파이프라인 단계들을 더욱 작게 분할함으로써, 처리 시간의 차이를 최소화 하는 기술로, 최근에는 대부분의 프로세서들이 10단계 이상의 단계로 분할된 명령어 파이프라인 구조를 사용하고 있습니다.
슈퍼파이프라이닝(superpipelining): 명령어 파이프라인의 단계들을 더욱 작게 분할하여 처리속도를 높여주는 기술
세번째 문제를 보완하기 위해, 파이프라인의 IF 단계와 OF 단계가 직접 액세스 하는 CPU내부 캐시를 명령어 캐시와 데이터 캐시로 분리시키는 방법이 사용되고 있습니다.
네번째 문제인 조건 분기 때문에 발생하는 문제도 완전히 해결할 수는 없지만 다음과 같은 방법들이 사용되고 있습니다.
- 분기 예측
- 분기가 일어날 것인지를 예측하고, 그에 따라 어느 경로의 명령어를 인출할 지를 결정하는 방법.
- 분기역사표를 참조하여 예측하는 방법이 가장 널리 사용됨 - 분기 목적지 선인출
- 조건 분기가 인식되면, 분기 명령어의 다음 명령어뿐 아니라, 조건이 만족될 경우에 분기하게될 목적지의 명령어도 함께 인출.
- 만약 분기가 이루어지더라도 목적지의 명령어가 이미 인출되어 있어서 지연시간 줄일 수 있음
- 분기 목적지 명령어를 별도로 저장해 둘 수 있는 기억장소가 추가되어야 함 - 루프 버퍼
- 파이프라인의 명령어 인출 단계에 포함되어 들어있는 작은 고속 기억장치
- 가장 최근에 인출된 일정 개수의 명령어들이 순서대로 저장됨
- 분기 발생 시, 목적지의 명령어가 버퍼에 있는지를 검사하고, 있다면 버퍼에서 인출 - 지연 분기
- 프로그램 내의 명령어들을 재배치
- 분기 명령어의 위치를 적절히 조절함으로써, 원래보다 나중에 실행되도록 재배치
조건 분기 명령어에서 사용하는 조건들은 CPU 내부의 상태 레지스터에 저장되어 있습니다. 각 조건의 상태를 나타내는 비트를 플래그라고 부릅니다. CPU는 실행 사이클 동안에 조건 분기 명령어가 지정하는 플래그의 값을 검사하여 분기 여부를 결정합니다.
- 부호(S) 플래그 : 직전에 수행된 산술 연산 결과값의 부호 비트로 세트. 0은 양수, 1은 음수
- 제로(Z) 플래그 : 연산결과값이 0이면 1로 세트
- 올림수(C) 플래그 : 덧셈이나 뺄셈에서 올림수나 빌림수가 있으면 세트
- 동등(E) 플래그 : 두 수를 비교한 결과가 동일한 경우에 세트
- 오버플로우(V) 플래그 : 오버 플로우 발생 시 플래그
- 인터럽트(I) 플래그 : 인터럽트 가능 상태이면 1, 불가능 상태이면 0
- 슈퍼바이저(P) 플래그 : 슈퍼바이저 모드와 사용자 모드 중 어느 모드에서 실행하는지를 나타냄. 슈퍼바이저 모드는 운영체제를 포함한 시스템을 수행하는 모드, 사용자 모드는 사용자 프로그램 혹은 응용 프로그램이 수행되는 모드
3. 속도 향상을 위한 방법들
1) 슈퍼스칼라
슈퍼 스칼라는 내부에 두개 혹은 그 이상의 명령어 파이프라인들을 포함시킨 구조 입니다. CPU는 매 클록 주기마다 각 명령어 파이프라인이 별도의 명령어를 인출하여 동시에 실행할 수 있기 때문에, 이론적으로는 파이프라인의 수만큼 속도가 높아질 수있습니다.
슈퍼스칼라(superscala): CPU내에 여러개의 명령어 파이프라인을 두어, 동시에 그 수만큼의 명령어들을 실행할 수 있도록 한 구조
다음 그림에서 두개의 파이프라인들로 이루어진 2-way 슈퍼스칼라를 나타내고 있습니다.
일반적인 파이프라인이 4개의 명령어를 실행한것에 비해서, 2-way 슈퍼스칼라에서는 8개의 명령어를 실행하는것을 볼 수 있습니다.
이를위해서 중요한점은 동시에 처리할 명령어들이 서로간에 영향을 받지 않아야 한다는 것 입니다.
예를들어 다음과 같은 두 명령어가 동시에 실행된다고 가정해봅시다
명령어 1 : R1 <- R2 + R3
명령어 2 : R4 <- R1 + R5
명령어 1과 2가 순차적으로 실행된다고 하면 상관없겠지만 동시에 실행된다고 했을때, R4는 R1을 가져올 수 없는 문제가 발생할 수 있습니다. 이와같은 관계를 데이터 의존성 관계라고 부르며, 슈퍼 스칼라 프로세서에서는 이를 유의해야 합니다. 이러한 상황에서는 파이프라인들의 일부 단계들이 유후 상태에 들어가기 때문에 속도 향상은 이론보다 낮아집니다.
데이터 의존성(data dependency): 한 명령어를 실행한 다음에, 그 결과값을 보내주어야 다음 명령어의 실행이 가능한 관계
유휴 상태(idle): 컴퓨터나 프로그램이 실행중이지만 작업을 처리하지 않는 상태
2) 동적 실행
동적 실행이란 프로그램을 컴파일하여 생성한 실행 코드 파일에 나열되어 있는 명령어들을 원래의 순서와는 다르게 변경하면서 실행하는 기법입니다. 이는 슈퍼스칼라의 파이프라인에서 유휴사이클이 발생하는 현상을 줄여주기 위한것으로 다음과 같은 방법으로 명령어를 실행합니다.
- 기억장치로부터 명령어 순서대로 인출
- 명령어를 해독하고, 그 결과를 명령어 풀에 저장
- 데이터 의존성으로 인해 동시처리가 불가능한 경우에, 의존성이 존재하지 않는 명령어를 찾아냄
- 동시 처리 가능한 명령어들의 연산을 수행할 연산장치들에 배정하고, 명령어와 데이터를 그 장치들로 발송 시켜 처리되게 함
- 퇴거 유니트에서 연산 처리 결과를 저장하고 명령어 코드를 제거함으로써 실행 종료
명령어 풀(instruction pool): 해독된 마이크로 명령어들을 일시 저장해두는 장소로서, 주로 레지스터 세트로 구현
퇴거 유니트(retire unit): 연산 처리 결과를 최종 저장하고, 명령어 코드를 제거함으로써 실행을 종료시키는 하드웨어 모듈
그림을 통해 알아보겠습니다.
명령어 인출 유니트가 기억장치로부터 명령어를 두개씩 인출해옵니다.
명령어를 해독하고 그 결과를 풀에 저장합니다.
그 다음에 위치한 재배열/디스패치 유니트는 명령어 풀을 검색하여 동시에 처리할 수 있는 명령어들을 찾아서 실행 유니트로 보내줍니다.
실행 유니트는 명령어를 처리하고 퇴거 유니트에서 저장되어 명령어가 제거되며 실행이 종료됩니다.
3) 멀티-코어 프로세서
반도체 기술이 발전하면서, 한 칩에 두개 혹은 그 이상의 CPU 코어들을 포함시킬 수 있게 되었습니다. CPU 코어 란 기존의 CPU칩에 포함된 하드웨어 중에서 명령어 실행에 반드시 필요한 핵심 모듈들을 말하는데, 명령어 파이프라인들로 이루어진 슈퍼스칼라 모듈과 ALU 및 레지스터 세트 등을 말합니다. CPU 코어 여러개를 하나의 칩에 넣은것을 멀티-코어 프로세서 라고 합니다. 그리고 갯수에 따라 듀얼-코어 프로세서, 쿼드-코어-프로세서 등이 있습니다. 또한 이들은 칩-레벨 다중 프로세서, 혹은 단일-칩 다중 프로세서 라고 불리기도 합니다.
CPU 코어 : cpu 칩의 내부 회로 중에서 명령어 실행에 반드시 필요한 핵심 부분들로 이루어진 하드웨어 모듈
멀티-코어 프로세서 : 여러 개의 CPU코어들을 포함하고 있는 CPU 칩
듀얼 코어 프로세서의 각 CPU 코어는 슈퍼스칼라 구조로 구성 됩니다. 각 CPU 코어는 프로그램 처리를 독립적으로 수행하며, 필요한 경우에만 공유 캐시를 통하여 정보를 교환합니다. 결과적으로, 하나의 프로그램에 포함된 명령어들을 명령어 파이프라인의 수만큼씩 인출하여 동시에 실행하는 슈퍼스칼라 프로세서와는 달리, 듀얼-코어 프로세서에서는 독립적인 처리가 가능한 태스크 프로그램들이 CPU 코어들에 의해 동시에 처리될 수 있습니다. 이런 동시처리 기술을 멀티-태스킹 이라고 부릅니다. 더 많은 수의 CPU 코어들을 포함하고 있는 멀티-코어 프로세서는 그 수만큼의 태스크 프로그램들을 동시에 처리할 수 있습니다.
OS와 같은 시스템 소프트웨어와 응용 프로그램들을 내부적으로 여러 개의 스레드들로 분할할 수 있습니다.
일반적인 멀티-코어 프로세서에서 각 코어가 한번에 한개씩의 스레드를 실행합니다.
이는 각 코어가 한개의 레지스터세트를 가지고 있기 때문입니다.
(그림에서는 레지스터세트를 RS로 표시)
그렇다면 만약 여러개의 레지스터 세트를 가지고있다면, CPU 코어는 한번에 여러개의 스레드를 작업할 수 있게됩니다.
이를 멀티 스레딩 기법이라고 합니다.
멀티-태스킹: 여러 CPU 코어들을 이용하여 독립적인 태스크 프로그램들을 동시에 처리하는 기술
멀티-스래딩 : 하나의 CPU 코어가 다수의 스래드들을 동시에 실행하는 기법
스레드: 독립적으로 실행될 수 있는 최소 크기의 프로그램 단위
내용이 딥해지면서 공부하는데 걸리는 시간이 많이 늘어가고 있습니다.
지식을 쌓는건 좋지만 지장이 안되는 선에서 해야하기 때문에, 범위를 적절히 나누고 집중하는 능력을 길러야 할 것 같습니다.
'CS > 컴퓨터 구조' 카테고리의 다른 글
[컴퓨터 구조] CPU의 구조와 명령어 실행 (4) | 2025.03.27 |
---|---|
[컴퓨터 구조] 컴퓨터의 발전 과정 (2) | 2025.03.26 |
[컴퓨터 구조] 컴퓨터의 기본 구조, 정보의 표현과 저장, 시스템의 구성 (1) | 2025.03.25 |