강민철님의 "혼자 공부하는 컴퓨터 구조+운영체제"을 기반으로 학습한 게시물입니다.
📕 목차
1. 빠른 CPU를 위한 설계 기법
2. 명령어 병렬 처리 기법
3. CISC와 RISC
1. 빠른 CPU를 위한 설계 기법
📌 클럭(Clock)
- CPU의 속도를 나타내는 단위(Hz)
- 1초 동안 파장이 한 번 움직이는 시간으로, 이 시간 동안 처리하는 데이터 양에 따라 CPU 속도가 달라진다.
- 컴퓨터 부품들은 '클럭 신호'에 맞춰 움직인다.
- CPU는 '명령어 사이클'이라는 정해진 흐름에 맞춰 명령어들을 실행한다.
- 클럭 속도가 높으면 CPU가 빠르게 동작하긴 하지만 물리적인 한계가 존재한다. (발열)
✒️ 클럭 속도는 일정하지 않다
CPU는 기본 클럭 속도(Base)와 최대 클럭 속도(Max)로 나뉘어져 있다.
고성능을 요구하는 순간에는 순간적으로 클럭 속도를 높이고, 그렇지 않을 때는 낮춘다.
최대 클럭 속도를 강제로 끌어올리는 것을 오버클럭킹(overclocking)이라 한다.
📌 코어(Core)와 멀티코어(Multi-core)
- 과거에는 CPU를 명령어를 실행하는 부품 → 코어라는 용어로 대체
- CPU는 "명령어를 실행하는 부품(core)을 여러 개 포함하는 부품"으로 재정의
- CPU의 성능을 높이는 간단한 방법
- 코어 추가
- 스레드 추가
- 멀티코어 CPU (혹은 멀티코어 프로세서) : 코어를 여러 개 포함하는 CPU
코어 수 | 프로세서 명칭 |
1 | 싱글코어(single-core) |
2 | 듀얼코어 |
3 | 트리플코어 |
4 | 쿼드코어 |
6 | 헥사코어 |
8 | 옥타코어 |
10 | 데카코어 |
12 | 도데카코어 |
- 코어 수 증가로도 한계점 존재
- CPU 연산 속도가 꼭 코어 수에 비례하여 증가하지 않는다.
- 코어마다 처리할 연산이 적절히 분배되어야 한다.
- 작업량에 비해 코어 수가 지나치게 많아도 성능에 큰 영향이 없다.
📌 Thread와 Multi-thread
- 실행 흐름 단위
- CPU에서 말하는 쓰레드와 프로그래밍에서 사용되는 쓰레드는 용례가 다르다.
- CPU에서 사용되는 하드웨어 쓰레드가 있고, 프로그램에서 사용되는 소프트웨어 쓰레드가 있다.
- 하드웨어 쓰레드
- 하나의 코어가 동시에 처리하는 명령어 단위 (노예의 손 개수....)
- 운영체제의 최소 작업 단위이자, 물리적 CPU 또는 코어를 말한다.
- 원칙적으로 CPU는 한 번에 1개의 쓰레드만 처리할 수 있다.
- intel의 HyperThreading, AMD의 SMT(Simutaneous MultiThreading) 기술로 1개의 코어가 동시에 2개의 쓰레드를 지원할 수 있게 되었다.
- 멀티 쓰레드 프로세서 (혹은, 멀티스레드 CPU)
- 6코어 12쓰레드는 6개의 코어에서 12개의 쓰레드가 병령 수행되는 것이다.
- 여러개의 프로그램이 동시에 실행되는 것처럼 보이는 것은 시분할(time sharing) 기법이다.
- 소프트웨어 스레드
- 하나의 프로그램에서 독립적으로 실행되는 단위
- 응용 프로그램이 갖는 최소 작업 단위이자, 시스템 자원 한도 내에서 계속해서 만들어 낼 수 있다.
- SW Thread가 많다고 해서 병렬 수행이 가능한 것은 아니며, 물리적 CPU를 초과할 수 없다.
✒️ Multi-thread Processor
1 core 2 thread가 가능한 이유의 핵심은 Register 때문이다.
하나의 코어가 프로그램 카운터, 스택 포인터, 데이터 버퍼 레지스터, 데이터 주소 레지스터와 같은 하나의 명령어 수행을 위한 레지스터를 여러개 가지고 있으면 된다.
레지스터 세트가 두 개인 코어는 두 개의 명령어를 동시에 처리할 수 있다.
프로그램 입장에서는 2코어 4쓰레드 CPU 환경에서 CPU가 4개 있는 것처럼 보인다.
그래서 하드웨어 쓰레드를 논리 프로세서(logical processor)라고도 한다.
실제로 작업 관리자 - 성능 탭으로 이동하면 4 코어임에도 불구하고 8 쓰레드 환경이기 때문에 Logical processor가 8임을 확인할 수 있다.
2. 명령어 병렬 처리 기법
💡 CPU 성능을 높이기 위해서, CPU가 한시도 쉬지 못하게 하는 명령어 병렬 처리 기법을 적용한다.
- 명령어 병렬 처리 기법(ILP; Instruction-Level Parallelism)
📌 명령어 파이프라인(instruction pipline)
- 일반적인 명령어 처리 과정
- 명령어 인출(Instruction Fetch)
- 명령어 해석(Instruction Decode)
- 명령어 실행(Execute Instruction)
- 결과 저장(Write Back)
- 같은 단계가 겹치지만 않는다면, CPU는 각 단계를 동시에 실행할 수 있다.
- 파이프라인 위험(pipeline hazard)
- 데이터 위험(data hazard)
- 명령어 간 데이터 의존성에 의해 발생
- 이전 연산 값을 필요로 하는 연산의 경우, 값이 저장되기 전에 인출해버리면 결과가 달라진다.
- 즉, 데이터 의존적인 두 명령어를 무작정 동시 수행하려 하면 제대로 작동할 수 없다.
- 제어 위험(control hazard)
- 프로그램 카운터의 갑작스러운 변화(ex. 분기)에 의해 발생
- 프로그램 카운터는 기본적으로 '현재 실행 중인 명령어의 다음 주소'로 갱신된다.
- ex. '실행' 단계에서 분기를 해버리면, 미리 처리하던 '인출', '해석' 처리는 불필요해진다.
- 분기 예측(branch prediction) : 프로그램이 어디로 분기할지 미리 예측하여 주소를 인출
- 구조적 위험(structural hazard)
- 서로 다른 명령어가 동시에 ALU, Register 등의 CPU 부품을 사용하려 할 때 발생
- 자원 위험(resource hazard)이라고도 부른다.
- 데이터 위험(data hazard)
📌 슈퍼스칼라(Superscalar)
- 슈퍼스칼라 프로세서 또는 슈퍼스칼라 CPU
- 멀티쓰레드 프로세서는 매 클럭 주기마다 동시에 여러 명령어 인출, 해석, 실행이 가능하다.
- 이론적으로 파이프 라인 개수에 비례하여 프로그램 처리 속도가 빨라진다.
- 실제로는 파이프라인 위험 등의 이슈로 비례하지 않으며, 위험 방지를 위해 고도로 설계되어야 한다.
📌 비순차적 명령어 처리(OoOE; Out-of-order execution)
고성능 마이크로프로세서가 특정한 종류의 지연으로 낭비될 수 있는 명령 사이클을 이용하는 패러다임 (합법적 새치기)
// 메모리 N번지 : M(N)
// 메모리 N번지에 M 저장 : M(N) <- M
M(100) <- 1
M(101) <- 2
M(102) <- M(100) + M(101)
M(150) <- 1
M(151) <- 2
M(152) <- 3
- ③ 명령이 실행되기 위해서는 ①, ②번 명령이 선행되어야 한다.
- 이때 순서를 바꿔도 무방한 ④⑤⑥ 명령을 먼저 처리하여 효율을 높이는 기법이다.
- 이를 위해서는 어떤 명령어와 데이터 의존성을 가지고 있는지, 순서를 바꿔 실행 가능한 명령어는 어떤 것들인지 판단할 수 있어야 한다.
- 실제로 오늘날 CPU 성능 향상에 크게 기여한 기법이자 대부분의 CPU가 차용하고 있다.
3. CISC와 RISC
📌 명령어 집합(instruction set)
- 명령어 집합 구조(ISA; Instruction Set Architecture)
- CPU가 이해할 수 있는 명령어들의 모음
- CPU의 언어이자 하드웨어가 소프트웨어를 어떻게 이해할지에 대한 약속
- 제조사마다 명령어의 세세한 생김새, 가능한 연산, 주소 지정 방식 등이 다를 수 있다.
- 같은 소스 코드로 만들어진 프로그램도 ISA가 다르면 어셈블리어도 달라진다.
- ex. Intel 노트북(x86 또는 x86-64 ISA), apple iPhone(ARM ISA)은 서로의 명령어 해석 불가
- ISA가 달라지면 제어장치의 명령어 해석 방식, 사용되는 레지스터 종류와 개수, 메모리 관리 방법 등 많은 것이 달라진다. ⇒ CPU 하드웨어 설계에도 영향
- 명령어 병렬 처리 기법들을 도입하기 위한 2가지 ISA
- CISC
- RISC
📌 CISC(Complex Instruction Set Computer)
- 복잡한 명령어 집합을 활용하는 컴퓨터(CPU)
- ex. x86, x86-64
- 가변 길이 명령어
- 다양한 메모리 접근 주소 지정 방식
- pros
- 다양하고 강력한 명령어를 활용해 적은 수의 명령어로도 프로그램을 실행할 수 있다.
- 메모리 공간 절약
- cons
- 너무 복잡하고 다양한 기능을 제공해서 명령어 크기와 실행되기까지 시간이 일정하지 않다.
- 명령어 하나를 실행하는 데 여러 클럭 주기를 필요로 한다.
- 규격화되지 않은 명령어가 파이프라이닝을 어렵게 만든다. (성능 이슈)
- 전체 명령어 중에 20% 정도가 사용된 전체 명령어의 80%를 차지
📌 RISC(Reduced Instruction Set Computer)
- 명령어 길이와 수행 시간이 짧고, 자주 쓰이는 기본적인 명령어를 작고 빠르게 규격화하여 활용
- ex. ARM
- 고정 길이 명령어 (되도록 1클럭 내외로 실행 가능할 정도의 크기)
- 메모리 직접 접근 명령어 load, store 두 개로 제한 (load-store 구조)
- pros
- 메모리 접근을 단순화, 최소화 하는 대신 레지스터를 적극 활용
- 일반적인 경우보다 레지스터 개수도 많고, 레지스터 이용 연산도 더 많다.
- cons
- 프로그램 실행을 위해 CISC보다 많은 명령이 필요