CS 🦾

혼자 공부하는 컴퓨터 구조 + 운영체제 - 제 5장 CPU 성능 향상 기

침착하고 가야할 곳에만 집중하는 달팽이 2024. 12. 19. 21:45

1) 빠른 CPU를 위한 설계 기법

클럭

CPU 는 클럭 신호에 맞춰서 명령어 사이클을 반복한다 ⇒ 클럭 신호가 빠르게 반복되면 CPU 가 빠르다. ⇒ 그래서 클럭 속도를 CPU 속도로 간주한다.

HZ

클럭 속도는 헤르츠 단위로 측정한다.

1초에 1번 반복함 → 1HZ , 1초에 100번 반복함 → 100HZ

기본 속도는 1초에 30억번, 최대 속도는 58억번

💡 클럭 속도는 일정하다?
No!
고성능을 요할 때는 속도를 높이고 그렇지 않을 때는 속도를 늦춘다. 최대 클럭 속도를 강제로 끌어올리는 기법을 오버클럭킹이라고 한다.
오버클럭킹을 사용하는 경우 : 고사양 게임할 때 프레임 수를 높이고자 할 때, 3D 모델링 작업 시 렌더링 시간을 단축
⇒ 오버클럭킹은 터보 부스트의 한계를 넘어서 극한의 성능이 필요할 때 사용하는 특수한 기법

 

💡클럭 속도는 무조건 빠른게 좋다?
No!
클럭 속도가 빠르다고 CPU가 무조건 빨라지는 건 아니다. 클럭 속도를 너무 높이면 발열 문제가 심해진다. 클럭 속도만으로는 CPU의 성능을 올리는 건 한계가 있다.

코어와 멀티코어

코어와 스레드 수를 늘리면 CPU 성능이 높아진다.

코어란?

예전에는 CPU는 부품 하나만 존재했는데 이제는 여러개를 만들 수 있다.

이렇게 여러 개의 코어를 포함한 CPU를 멀티코어 CPU / 멀티코어 프로세서 라고 부른다.

코어 수에 따른 CPU 종류

💡 그럼 코어 수가 많을 수록 무조건 속도가 빠르다?
No!
코어마다 처리할 연산이 적절히 분배되지 않으면 코어 수에 비례하여 속도가 증가하지 않는다. (like 조별과제, 인원이 많다고 딱히 결과물이 더 좋아지지 않음.)
그리고 작업량이 적은 경우에는 코어가 엄청 많아도 큰 영향이 없다.

 

코어 수와 속도가 비례하지 않는 더 자세한 이유 by 클로드

1. 소프트웨어의 병렬처리 한계
모든 프로그램이 다중 코어를 효율적으로 활용하도록 설계되지는 않았습니다일부 작업은 본질적으로 순차적 처리가 필요해서 병렬화가 어렵습니다예를 들어, 단순한 웹 브라우징은 아무리 코어가 많아도 1-2개만 주로 사용합니다
2. 병목 현상
CPU 코어가 많아도 메모리(RAM)나 저장장치(SSD/HDD)의 속도가 따라가지 못하면 전체 성능이 제한됩니다많은 코어가 동시에 데이터를 요청하면 메모리 대역폭이 부족할 수 있습니다
3. 발열과 전력 문제
코어가 많을수록 발열이 심해집니다발열 때문에 모든 코어를 최대 성능으로 계속 가동하기 어렵습니다전력 공급도 제한되어 있어 모든 코어를 동시에 최대로 활용하기 어렵습니다
4. 코어 간 통신 오버헤드
코어가 많아질수록 코어 간 데이터를 주고받는 데 더 많은 시간이 필요합니다이 통신 과정에서 발생하는 지연 시간이 전체 성능을 저하시킬 수 있습니다
따라서 용도에 맞는 적절한 코어 수를 선택하는 것이 중요합니다. 게임이나 일반적인 작업은 6-8코어 정도면 충분한 경우가 많습니다

스레드와 멀티스레드

프로그래밍할 때의 그 스레드와 다르다! 우리가 지금 하는 건 하드웨어적 스레드!

하드웨어적 스레드

하나의 코어로도 여러 개의 명령어를 동시에 실행할 수 있다.

스레드란? 하나의 코어가 동시에 처리하는 명령어 단위

2코어 4스레드 CPU

이런 CPU를 멀티스레드 프로세서 / 멀티스레드 CPU 라고 부른다.

💡자주 보게 될 용어 ‘하이퍼스레딩’
인텔의 멀티스레드 기술에 붙인 이름이다. 마케팅용 이름이다.

 

 

소프트웨어적 스레드

소프트웨어적 스레드란? 하나의 프로그램에서 독립적으로 실행되는 단위

프로그램의 한 부분만 실행되면 싱클 스레드, 여러 부분이 동시에 실행되면 멀티스레드

예를 들면 워드 프로세서 프로그램은 이렇게 여러 기능을 각각의 스레드로 만들어서 동시에 실행함.

멀티스레드 프로세서

멀티스레드 프로세서를 만들기 위해서는? → 레지스터가 여러 개 있으면 된다.

레지스터가 2개씩 있으니까 두 개의 명령어를 처리하기 위한 정보들을 기억할 수 있다.

이처럼 하나의 CPU로도 스레드를 이용해 여러 명형어를 동시에 처리할 수 있음. 그런데 프로그램 입장에서는 1개의 CPU가 2가지 명령어를 처리하는게 아니라 2개의 CPU가 1개의 명령어를 처리하는 것처럼 보임. 그래서 하드웨어 스레드를 논리 프로세서라고 부름.

4개의 스레드인데 CPU 4개 라고 착각하는 프로그램 입장

 

그래서 실제로 4코어 8스레드 CPU를 사용하는 컴퓨터의 작업 관리자에 들어가보면 논리프로세서가 8로 뜬다.

💡용어 정리!
코어: 명령어 실행할 수 있는 하드웨어 부품
멀티코어 프로세서: 명령어 실행할 수 있는 하드웨어 부품이 CPU에 2개 이상 있는 CPU
스레드: 명령어 실행하는 단위
멀티스레드 프로세서: 하나의 코어로 여러 개의 명령어를 동시에 실행할 수 있는 CP

 

2) 명령어 병렬 처리 기법

명령어 병렬 처리 기법이란? CPU에서 명령어를 동시에 처리하여 한시도 쉬지 않고 작동시키는 기법이다.

  • 명령어 병렬 처리 기법 종류:
    1. 명령어 파이프 라이닝
    2. 슈퍼스킬라
    3. 비순차적 명령어 처리

1. 명령어 파이프라인

명령어 처리 과정 중 같은 단계가 겹치지 않게 하여 동시에 실행시킬 수 있다.

전공서에 따라 단계를 다르게 나누기도 함! 무조건 이 4단계로 나뉘는게 아님.

공장 생산 라인처럼 명령어 파이프라인에 넣고 이렇게 동시에 처리하는 기법이 명령어 파이프라이닝이다.

파이프라이닝 위험

특정 상황에서 성능 향상에 실패하는 경우가 있다.

  1. 데이터 위험
  2. 제어 위험
  3. 구조적 위험

1. 데이터 위험

명령어 간 ‘데이터 의존성’ 때문에 발생한다.

어떤 명령어는 이전 명령어를 끝까지 실행해야만 비로소 실행할 수 있는 경우가 있다. 이런 경우에도 무작정 동시에 실행하라고 하면 파이프라인이 제대로 작동하지 않는다.

😵‍💫 예시:
명령어 1: c ← a + b
명령어 2: d ← c + e

 

2. 제어 위험

주로 분기 등으로 인한 프로그램 카운터의 갑작스러운 변화 때문에 발생함.

💡프로그램 카운터가 뭐였더라?
프로그램 카운터는 레지스터 중에서 다음에 실행할 명령어의 메모리 주소를 저장하는 역할을 한다.

 

분기문을 만나면 if 문에 따라서 jump 를 할 때도 있는데 그럼 미리 바로 다음 명령어를 인출,해석하던 것이 헛수고가 됨.

미리 인출,해석한게 헛수고가 되어버린 CPU 입장

 

그래서 이런 문제를 해결하기 위해 분기 예측을 사용하기도 한다. 프로그램이 어디로 분기할지 미리 예측한 후 그 주소를 인출하는 기술이다.

3. 구조적 위험(자원 위험)

구조적 위험은 하드웨어 자원이 부족해서 발생하는 충돌이다. 쉽게 말해서, 여러 명령어가 동시에 같은 하드웨어를 사용하려고 할 때 발생하는 문제다.

예를 들어 서로 다른 명령어가 동시에 ALU, 레지스터 등과 같은 CPU 부품을 사용하려고 할 때 구조적 위험이 발생한다.

슈퍼스칼라

CPU 내부에 여러 개의 명령어 파이프라인을 포함한 구조를 슈퍼스칼라라고 한다.

명령어 파이프라인을 하나만 두는 것이 아니라 여러 개 두는 것이다.

슈퍼스칼라 구조로 명령어 처리가 가능한 CPU를 슈퍼스칼라 프로세서/ 슈퍼스칼라 CPU 라고 부른다. 멀티스레드 프로세서의 경우에 한 번에 여러 명령어를 인출,해석,실행할 수 있기에 슈퍼스칼라 구조가 가능하다.

💡파이프라인 개수에 비례해서 프로그램 처리 속도가 빨라진다?
No! 사실 이론적으로는 그래야 하지만 파이프라인 위험 때문에 사용하기 까다롭다. 이 때문에 고도로 설계되어야 한다.
슈퍼스칼라는 어떻게 파이프라인 위험을 해결할까? by 클로드
슈퍼스칼라의 기본 개념:

여러 개의 파이프라인으로 동시에 여러 명령어를 처리 예를 들어 2-way 슈퍼스칼라면 사이클당 2개의 명령어 처리 가능

하지만 말씀하신 대로 위험(Hazard)이 더 복잡해집니다. 이를 해결하기 위해 다음과 같은 기술들을 사용합니다:

1. 동적 스케줄링(Dynamic Scheduling) 명령어들의 의존성을 실시간으로 분석 서로 독립적인 명령어들을 찾아서 병렬 실행 assembly Copy ADD R1, R2, R3 // 파이프라인 1 MUL R4, R5, R6 // 파이프라인 2 (R1과 무관하므로 병렬 실행 가능)
2. 레지스터 리네이밍(Register Renaming) 이름 의존성(WAW, WAR)을 제거하기 위해 물리적 레지스터를 더 많이 사용 가상의 레지스터 이름을 실제 하드웨어 레지스터에 매핑
3. 재정렬 버퍼(Reorder Buffer) 명령어들을 순서와 관계없이 실행하되 결과는 원래 프로그램 순서대로 저장
4. 분기 예측(Branch Prediction) 여러 경로의 명령어를 미리 가져와서 실행 예측이 틀리면 파이프라인을 비우고 올바른 경로 실행

실제 예시를 보면:

assembly Copy ADD R1, R2, R3 // 파이프라인 1에서 실행 MUL R4, R5, R6 // 파이프라인 2에서 동시 실행 SUB R7, R1, R8 // ADD가 끝날 때까지 대기 (데이터 의존성) DIV R9, R10, R11 // SUB와 독립적이므로 다른 파이프라인에서 실행 가능

이처럼 복잡한 하드웨어와 알고리즘을 사용해서 파이프라인 위험을 관리하면서도 높은 성능을 얻을 수 있습니다. 현대의 CPU들은 이보다 더 복잡한 기술들을 사용하여 명령어 수준 병렬성(ILP)을 최대한 활용하고 있죠.

3. 비순차적 명령어 처리 OoOE

오늘날 대부분의 CPU 가 차용하는 방식! 합법적 명령어 새치기라고 생각하면 된다.

순서를 바꿔도 의존성이 없어서 프로그램 실행 흐름에 영향을 주지 않도록 순서를 바꿔서 실행하는 것이 비순차적 명령어 처리이다.

3) CISC와 RISC

위에 나온 방식들을 적용하기 위해서는 명령어가 파이프라이닝에 최적화되어 있어야 한다.

CPU가 이해할 수 있는 명령어들의 모음을 명령어 집합 / 명령어 집합 구조 (ISA) 라고 한다. CPU 마다 제조사, 규격, 기능이 다 달라서 ISA 도 다를 수 있다.

왜 명령어 집합 ‘구조’ 라고 하는지?
CPU가 어떤 명령어를 이해하는지에 따라 컴퓨터 구조 및 설계 방식이 달리지기 때문에

 

ISA가 다르면 명령어 어셈블리어도 다르다.

동일한 소스 코드를 ISA가 다른 컴퓨터에서 어셈플리어로 컴파일하면 다른 코드가 나온다.

동일한 컴파일러를 사용했음에도 다르게 나온다.

 

ISA 에 따라 많은 것들이 바뀐다. 제어장치가 명령어를 해석하는 방식, 사용되는 레지스터 종류와 개수, 메모리 관리법 그리고 하드웨어 설계에도 영향을 미친다.

현재 ISA 중 많이 쓰이는 것은 CISC 와 RISC 이 있다.

그럼 명령어 병렬 처리 기법을 도입하기에 유리한 ISA 는?

CISC

CISC 는 다양하고 강력한 명령어 집합을 이용하는 ISA 이다.

❓강력한 명령어가 뭐지?
한 번의 명령어로 여러 단계의 작업을 수행할 수 있는 것을 ‘강력하다’라고 한다.
비교하자면
일반적인 단순한 명령어:
메모리에서 데이터를 읽어온다
더하기 연산을 한다
결과를 메모리에 저장한다
강력한 명령어:
메모리에서 두 수를 가져오고 곱셈을 수행하고 결과를 다시 메모리에 저장하는 것을 모두 한 번의 명령어로 처리한다

 

이런 특징 덕분에 메모리를 아끼면서 개발할 수 있어서 옛날에는 인기가 높았다. 근데 오늘날에는 쓰일 수 없게하는 치명적인 단점..! → 명령어가 너무 길고 복잡해서 실행되는 시간이 일정하지가 않다. 하나의 명령어를 실행하는데 여러 클럭 주기가 쓰이기도 한다. 이게 왜 단점이냐면 파이프라인을 구현하는데 큰 문제가 생긴다.

수행 시간이 가지각색이라 효율적으로 처리하기 어려움

그리고 복잡하고 다양한 명령어를 활용할 수는 있지만 사실상 대다수의 복잡한 명령어들은 사용 빈도가 낮다. 그래서 오늘날에는 CISC 를 잘 쓰지 않는다.

RISC

CISC 의 한계를 통해 깨달은 2가지를 반영해서 만든 것이 RISC이다.

  1. 파이프라인을 위해 명령어는 길이와 수행 시간이 짧고 규격화되어야 한다.
  2. 복잡한 명령어보다는 자주 쓰이는 기본적인 명령어를 작고 빠르게 만들어야 한다.

⇒ 그래서 RISC 는 명령어의 종류도 비교적 적고 되도록 1클럭 내외로 실행되는 명령어를 지향한다.

즉 고정 길이 명령어 를 활용한다.

💡RISC의 또다른 특징
1. 메모리 접근을 단순화하고 최소화하고자 한다. 그래서 메모리에 직접 접근하는 명령어를 load, store 두 개로 제한해서 load-store 구조라고 부르기도 한다.
2. 레지스터를 적극적으로 활용해서 일반적인 경우보다 레지스터 개수도 더 많다.

CISC 와 RISC 비교표

 

'CS 🦾' 카테고리의 다른 글

제어장치와 연산장치  (0) 2026.02.10
컴퓨터 시스템의 구성요소  (0) 2026.02.09
부동 소수점  (0) 2026.02.05
고정 소수점  (0) 2026.02.04