컴퓨터는 어떻게 움직일까?!
➡️ 클럭 속도가 높아지면 CPU는 명령어 사이클을 더 빠르게 반복 → 다른 부품들도 그에 발맞춰 더 빠르게 작동한다
일반적으로 클럭 속도가 높은 CPU가 성능이 좋다
클럭 속도는 헤르츠(Hz) 단위로 측정
하지만 클럭 속도를 높인다고 해서 CPU가 빨라지는 것은 아니다! > 발열 문제가 있음
클럭 속도만으로 CPU의 성능을 올리는 것에는 한계가 있다
클럭 속도를 높이는 방법 외에 CPU의 성능을 높이는 방법은 무엇이 있을까?!
➡️ CPU의 코어와 스레드 수를 늘리는 방법
코어 - 명령어를 실행하는 부품 (과거 CPU의 정의)
그럼 CPU는?! 명령어를 실행하는 부품을 여러 개 포함하는 부품으로 명칭의 범위 확장
ex. 8코어 → 명령어를 실행하는 부품을 여덟 개 포함하고 있다
멀티코어 CPU (멀티코어 프로세서) - 코어를 여러 개 포함하고 있는 CPU
코어 수 | 프로세서 명칭 |
---|---|
1 | 싱글코어 |
2 | 듀얼코어 |
3 | 트리플코어 |
4 | 쿼드코어 |
6 | 헥사코어 |
8 | 옥타코어 |
10 | 데카코어 |
12 | 도데카코어 |
중요한 것은 코어마다 처리할 명령어들을 얼마나 적절하게 분배하느냐에 따라서 연산 속도가 달라진다는 것!
스레드의 사전적 의미는 '실행 흐름의 단위'
CPU에서 사용되는 스레드와 프로그래밍에서 사용되는 스레드의 용례가 다르다. 구분해서 기억해야 함!
ex. 2코어 4스레드 CPU = 명령어를 실행하는 부품을 두 개 포함하고, 한 번에 네 개의 명령어를 처리할 수 있는 CPU
멀티스레드 프로세서(멀티스레드 CPU) - 하나의 코어로 여러 명령어를 동시에 처리하는 CPU
ex. 8코어 16스레드 = 명령어를 실행하는 부품을 여덟 개 포함하고, 한 번에 열여섯 개의 명령어를 처리할 수 있는 CPU (코어 하나당 두 개의 하드웨어 스레드를 처리한다)
하나의 프로그램은 실행되는 과정에서 한 부분만 실행될 수도 있지만, 프로그램의 여러 부분이 동시에 실행될 수도 있다
여러 개의 기능을 각각의 스레드로 만들면 동시에 실행할 수 있다
스레드 정리!
➡️ 하드웨어적 정의: 하나의 코어가 동시에 처리하는 명령어 단위
➡️ 소프트웨어적 정의: 하나의 프로그램에서 독립적으로 실행되는 단위
하나의 코어로 여러 명령어를 동시에 처리하는 CPU!
멀티스레드 프로세서를 설계하는 일은 매우 복잡하지만 가장 큰 핵심은 레지스터
→ 하나의 명령어를 처리하기 위해 꼭 필요한 레지스터들을 여러 개 가지고 있으면 된다
ex. 레지스터 세트가 두 개인 CPU = 두 개의 명령어를 처리하기 위한 정보들을 기억할 수 있다
➡️ ALU와 제어장치가 두 개의 레지스터 세트에 저장된 명령어를 해석하고 실행하면 하나의 코어에서 두 개의 명령어가 동시에 실행된다
그런데! 프로그램의 입장에서는 2코어 4스레드 CPU가 한 번에 네 개의 명령어를 처리할 수 있는 것처럼 느껴진다! CPU가 네 개 있는 것처럼 보이는 것임! (논리 프로세서 4)
하드웨어 스레드 = 논리 프로세서라고 부르기도 한다.
빠른 CPU를 만들기 위해서는 높은 클럭 속도 + 멀티코어, 멀티스레드를 지원하는 CPU를 만드는 것이 중요하다
그리고, CPU가 놀지 않고 시간을 알뜰하게 쓰며 작동하게 만드는 것도 중요!
CPU를 한시도 쉬지 않고 작동시키는 기법이 바로 명령어 병렬 처리 기법이다 ^_^
명령어 처리 과정을 클럭 단위로 나누어 본다
➡️ 같은 단계가 겹치지만 않는다면 CPU는 '각 단계를 동시에 실행할 수 있다'!
ex. CPU는 한 명령어를 '인출'하는 동안에 다른 명령어를 '실행'할 수 있고, 한 명령어가 '실행'되는 동안에 연산 결과를 '저장'할 수 있다
공장처럼 명령어들을 명령어 파이프라인에 넣고 동시에 처리한다 ➡️ 명령어 파이프라이닝
파이프라이닝이 높은 성능을 가져오기는 하지만, 특정 상황에서는 성능 향상에 실패하는 경우도 있다
명령어 간 '데이터 의존성'에 의해 발생
데이터 의존적인 두 명령어를 무작정 동시에 실행하려고 하면 파이프라인이 제대로 작동하지 않는다
주로 분기 등으로 인한 '프로그램 카운터의 갑작스러운 변화'에 의해 발생
분기 예측 이라는 기술을 사용하기도 한다 (프로그램이 어디로 분기할지 미리 예측한 후 그 주소를 인출하는 기술)
명령어들을 겹쳐 실행하는 과정에서 서로 다른 명령어가 동시에 ALU, 레지스터 등과 같은 CPU 부품을 사용하려고 할 때 발생
파이프라이닝은 단일파이프라인으로도 구현이 가능하지만, 오늘날 대부분의 CPU에서는 여러 개으 파이프라인을 이용한다
CPU 내부에 여러 개의 명령어 파이프라인을 포함한 구조
슈퍼스칼라 구조로 명령어 처리가 가능한 CPU를 슈퍼스칼라 프로세서(슈퍼스칼라 CPU)라고 한다!
슈퍼스칼라 프로세서는 이론적으로 파이프라인 개수에 비례하여 프로그램 처리 속도가 빨라지지만, 파이프라인 위험 등의 예상치 못한 문제가 있다 → 고도로 설계되어야 한다!
Out-of-order execution, 명령어들을 순차적으로 실행하지 않는 기법
명령어를 순차적으로만 실행하지 않고 순서를 바꿔 실행해도 무방한 명령어를 먼저 실행하며 명령어 파이프라인이 멈추는 것을 방지하는 기법 = 비순차적 명령어 처리 기법
비순차적 명령어 처리가 가능한 CPU는 명령어들이 어떤 명령어와 데이터 의존성을 가지고 있는지, 순서를 바꿔 실행할 수 있는 명령어에는 어떤 것들이 있는지를 판단할 수 있어야 한다!
CPU가 이해할 수 있는 명령어들의 모음을 명령어 집합 또는 명령어 집합 구조라고 한다
ex.
인텔의 노트북 속 CPU는 x86 혹은 x86-64 ISA를 이해한다
애플의 아이폰 속 CPU는 ARM ISA를 이해한다
→ 실행 파일은 명령어로 이루어져 있고 서로의 컴퓨터가 이해할 수 있는 명령어가 다르다
→ ISA는 일종의 CPU언어인 셈이다
→ 제어장치가 명령어를 해석하는 방식, 사용되는 레지스터의 종류와 개수, 메모리 관리 방법 등 많은 것이 달라진다
➡️ ISA는 CPU의 언어이자 하드웨어가 소프트웨어를 어떻게 이해할지에 대한 약속이다
Complex Instruction Set Computer의 약자 = 복잡한 명령어 집합을 활용하는 컴퓨터
→ 형태와 크기가 다양한 가변 길이 명령어를 활용한다
이는 상대적으로 적은 수의 명령어로도 프로그램을 실행할 수 있다는 것을 의미한다
프로그램을 실행하는 명령어 수가 적다 = 컴파일 된 프로그램의 크기가 작다
→ 같은 소스 코드를 컴파일해도 CPU마다 생성되는 실행 파일의 크기가 다를 수 있다
✔️ 명령어가 복잡하고 다양한 기능을 제공 → 명령어의 크기와 실행되기까지의 시간이 일정하지 않다
✔️ 복잡한 명령어 → 명령어 하나를 실행하는 데에 여러 클럭 주기를 필요로 한다
➡️ 명령어 파이프라인을 구현하는 데에 큰 걸림돌이 된다!
CISC가 활용하는 명령어는 명령어 수행 시간이 길고 가지각색이기 때문에 파이프라인이 효율적으로 명령어를 처리할 수 없다
➡️ 규격화되지 않은 명령어가 파이프라이닝을 어렵게 만든다!
CISC의 한계가 우리에게 준 교훈
- 빠른 처리를 위해 명령어 파이프라인을 십분 활용해야 한다! → 명령어 길이와 수행 시간이 짧고 규격화되어 있어야 한다
- 어차피 자주 쓰이는 명령어만 줄곧 사용된다 → 자주 쓰이는 기본적인 명령어를 작고 빠르게 만드는 것이 중요하다
Reduced Instruction Set Computer, CISC에 비해 명령어의 종류가 적다
✔️ 짧고 규격화된 명령어, 되도록 1클럭 내외로 실행되는 명령어를 지향한다
하나의 명령어가 1클럭 내외로 실행 → RISC 명령어 집합은 명령어 파이프라이닝에 최적화되어 있다
✔️ 메모리에 직접 접근하는 명령어를 load
, store
두 개로 제한 (load-store 구조)
때문에 CISC보다 주소 지정 방식의 종류가 적은 경우가 많다
➡️ 메모리 접근을 단순화, 최소화하는 대신 레지스터를 적극적으로 활용
➡️ 레지스터를 이용하는 연산이 많고, 일반적인 경우보다 범용 레지스터 개수도 더 많다
하지만 사용가능한 명령어 개수가 CISC보다 적기 때문에 RISC는 CISC보다 많은 명령으로 프로그램을 작동시킨다!
CISC | RISC |
---|---|
복잡하고 다양한 명령어 | 단순하고 적은 명령어 |
가변 길이 명령어 | 고정 길이 명령어 |
다양한 주소 지정 방식 | 적은 주소 지정 방식 |
프로그램을 이루는 명령어 수가 적음 | 프로그램을 이루는 명령어의 수가 많음 |
여러 클럭에 걸쳐 명령어 수행 | 1클럭 내외로 명령어 수행 |
파이프라이닝하기 어려움 | 파이프라이닝하기 쉬움 |