05-1 빠른 CPU를 위한 설계 기법

클럭

컴퓨터 부품들은 ‘클럭 신호’에 맞춰 일사불란하게 움직인다.

CPU는 ‘명령어 사이클’이라는 정해진 흐름에 맞춰 명령어들을 실행한다.

클럭 속도: 헤르츠(Hz) 단위로 측정. 초당 반복되는 횟수

오버클럭킹(overclocking): CPU의 최대 클럭 속도를 강제로 더 끌어올림

코어와 멀티코어

기존의 CPU: 전통적인 관점에서는 ‘명령어를 실행하는 부품’ 하나 ⇒ 현재는 코어(Core)

현재의 CPU: 여러 개의 코어를 포함하는 부품 ⇒ 멀티코어 CPU(multi-core CPU), 멀티코어 프로세서

스레드와 멀티스레드

스레드(thread)

  • 사전적 정의: 실행 흐름의 단위
  • 하드웨어적 스레드: 하나의 코어가 동시에 처리하는 명령어의 단위
  • 소프트웨어적 스레드: 하나의 프로그램에서 독립적으로 실행되는 단위

하드웨어적 스레드

  • 이하 하드웨어 스레드
  • 하나의 코어가 동시에 처리하는 명렁어 단위
  • 하나의 코어에 스레드가 많으면 동시에 여러 명령어를 처리할 수 있음
  • 멀티스레드(multithread) 프로세서, 멀티스레드 CPU
    • 하이퍼스레딩(hyper-threading) in Intel
  • 메모리 속 프로그램의 입장에선 각 하드웨어 스레드는 CPU로 보임(하나의 명령어를 처리하니까)
    • 따라서 **논리 프로세서(logical processor)**라고 부름

소프트웨어적 스레드

  • 이하 스레드
  • 하나의 프로그램에서 독립적으로 실행되는 단위
  • 프로그래밍 언어, 운영체제에서 이야기하는 스레드
  • 한 프로그램에서 여러 부분이 동시에 실행될 수 있다.
    • ex) 워드 프로세서
      1. 입력받은 내용 화면 출력
      2. 맞춤법 검사
      3. 상시 저장

멀티스레드 프로세서

멀티스레드 프로세서: 레지스터 세트(프로그램 카운터, 스택 포인터, MBR, MAR 등)를 여러 개 가지면 된다.

코어: 명령어를 실행할 수 있는 하드웨어 부품

스레드: 명령어를 실행하는 단위

멀티코어 프로세서: 명령어를 실행할 수 있는 하드웨어 부품이 CPU 안에 두 개 이상 있는 CPU

멀티스레드 프로세서: 하나의 코어로 여러 개의 명령어를 동시에 실행할 수 있는 CPU

05-2 명령어 병렬 처리 기법

명령어 병렬 처리 기법(Instruction-Level Parallelism): CPU가 명령어를 동시에 처리하는 기법

ILP는 한 프로그램 내 명령어들에 대한 이야기이므로 당연히 하나의 코어 내부에서 실행되어 명령어간 모든 리소스는 공유된다.

명령어 파이프라인

명령어 파이프라이닝(instruction pipelining): **명령어 파이프라인(instruction pipeline)**에 명령어들을 넣고 동시에 처리하는 기법

일반적인 명령어 처리 과정

  1. 명령어 인출
  2. 명령어 해석
  3. 명령어 실행
  4. 결과 저장

CPU는 같은 단계가 겹치지 않는다면, 각 단계를 동시에 실행할 수 있음.

첫번째 클럭: 명령어1의 인출

두번쨰 클럭: 명령어1의 해석, 명령어2의 인출

세번째 클럭: 명령어1의 실행, 명령어2의 해석, 명령어3의 인출

이런식으로!

왜 같은 단계가 겹치면 안되는걸까?

  1. 명령어 파이프라인과 하드웨어 스레드는 다른개념임. 명령어 파이프라인은 한 프로그램의 흐름에서 명령어들을 겹쳐서 처리하는 것임.
  2. 즉, 하나의 프로그램(= 여러 명렁어의 모음)에 있는 명령어들을 병렬하게 처리하는 방법에 대한 이야기
    1. 따라서 각 명령어 처리 단계는 같은 리소스(레지스터)를 공유하게 되므로, 같이 실행되면 오류가 발생한다.
  3. 그럼 소프트웨어적 스레드와는 같은 결인가?
    1. 소프트웨어 스레드는 해야 할 일의 단위를 이야기하는 것
    2. ILP는 그 일을 CPU가 처리할 때 병렬하게 처리한다는 이야기

파이프라인 위험(pipeline hazard)

  • 특정 상황에 명령어 파이프라이닝이 실패함
  • 데이터 위험, 제어 위험, 구조적 위험

데이터 위험

데이터 위험(data hazard): 데이터 의존성에 의해 발생

명령어 2가 명령어 1이 실행된 후에 실행되어야 하는 경우

ex) 명령어 3이 명령어 1과 명령어 2를 더하는 경우

제어 위험

제어 위험(control hazard): 분기 등으로 인한 ‘프로그램 카운터의 갑작스러운 변화’에 의해 발생

ex) 10번지, 11번지 명령어를 동시에 실행하던 중 10번지 명령어 실행 후 60번지 명령어로 분기하는 경우

분기 예측(branch prediction): 프로그램이 어디로 분기할 지 미리 예측한 후 그 주소를 인출

제어 위험이 왜 문제를 일으킬까?

  1. PC는 하드웨어 스레드당 1개씩 존재한다.
  2. PC는 다음 명령어 주소를 가져오기 위해 사용되므로 명령어 인출에서 사용된다.
  3. 제어위험은 PC에서 발생한다.
  4. 하드웨어 스레드가 가진 1개의 PC는 공식 PC(architectual PC)고, 각 파이프라인은 공식 PC와는 별도로 자신만의 PC 복사본이 있다.

정상적인 상황에서 PC가 가리키는 주소를 보면

클럭 1: 명령어 1을 인출 ⇒ PC는 명령어1을 가리킴

클럭 2: 명령어 2를 인출, 명령어 2를 해석 ⇒ PC는 명령어2를 가리킴

클럭 3: 명령어 3을 인출, 명령어 2를 해석, 명령어 1을 실행 ⇒ PC는 명령어 3을 가리킴

이렇게 순차적으로 명령어들을 가리키게 됨

명령어 2가 (가)조건이 True라면 주소를 60으로 점프한다 라고 가정.

(가)조건의 비교는 ALU 연산이 필요하므로, 명령어 해석을 지나 명령어 실행에서야 결과를 알 수 있음

클럭 1: 명령어 1을 인출

클럭 2: 명령어 1을 해석, 명령어 2를 인출

클럭 3: 명령어 1을 실행, 명령어 2를 해석, 명령어 3을 인출

클럭 4: 명령어 1을 저장, 명령어 2를 실행, 명령어 3을 해석, 명령어 4를 인출

이때 (가)조건이 충족되어 명령어 (가)가 True 였다면? PC는 주소 60을 가리킬 것.

정확한 실행 로직상으론 명령어 2를 실행 후, 주소 60에 있는 명령어 60이 실행되어야 했다. 하지만 이미 명령어3, 명령어 4는 인출 및 해석되었다.

이 때 올바르게 처리하기 위해 인출과 해석 단계에 있는 명령어 3, 명령어 4를 제거하여 파이프라인을 비운다.

  1. 파이프라인을 비우기 위한 리소스
  2. 실행될 필요가 없던 명령어 3, 명령어 4의 인출 및 해석에 소모된 리소스

로 인해 성능 저하가 발생하는 것.

명령어 3,4를 그냥 실행하면? ⇒ 애초에 실행되지 않도록 설계된 프로그램에서 명령어가 실행되는 거니까 잘못된 결과가 나타난다.

구조적 위험

구조적 위험(structural hazard): 서로 다른 명령어가 동시에 ALU, 레지스터 등과 같은 CPU 부품을 사용할 때

**자원 위험(resource hazard)**라고도 함

슈퍼스칼라

슈퍼스칼라(superscalar): CPU 내에 여러 개의 명령어 파이프라인을 포함한 구조

따라서 같은 단계를 여러 파이프라인이 실행할 수 있게 됨

슈퍼스칼라 프로세서, 슈퍼스칼라 CPU

비순차적 명령어 처리

비순차적 명령어 처리(Out-of-Order Execution): 명령어를 순차적으로만 실행하지 않고 순서를 바꿔 실행해도 무방한 명령어를 먼저 실행하여 명령어 파이프라인이 멈추는 것을 방지하는 기법

명령어 3이 명령어 1,2가 완료되어야만 실행할 수 있다고 가정하면

클럭 1: 명령어 1 인출

클럭 2: 명령어 1 해석, 명령어 2 인출

클럭 3: 명령어 1 실행, 명령어 2 해석

클럭 4: 명령어 1 저장, 명령어 2 실행

클럭 5: 명령어 2 저장

클럭 6: 명령어 3 인출

이 된다. 클럭3~클럭5 에서 명령어 3을 실행하지 못한다.

이때

  1. 이전 명령어의 실행과 전혀 상관없고(데이터 의존성이 없고)
  2. 순서를 바꿔 처리해도 수행 결과에 영향을 미치지 않는

다면 순서를 바꿔 처리한다. 그러면

클럭 1: 명령어 1 인출

클럭 2: 명령어 1 해석, 명령어 2 인출

클럭 3: 명령어 1 실행, 명령어 2 해석, 명령어 4 인출

이 된다

따라서 기존

명령어 1 → 2 → 3 → 4 → 5

의 순서를

명령어 1 → 2 → 4 → 5 → 3

으로 실행하여 시간을 단축한다.

05-3 CISC와 RISC

CPU가 파이프라이닝과 슈퍼스칼라 기법을 효과적으로 사용하려면 CPU가 인출하고 해석하고 실행하는 명령어가 파이프라이닝 하기 쉽게 생겨야 합니다.

명령어 집합

ISA(Instruction Set Architecture, 명령어 집합 구조)

  • 명령어 집합(instruction set)
  • CPU가 이해할 수 있는 명령어들의 모음
  • 명령어의 세세한 생김새, 명령어로 할 수 있는 연산, 주소 지정 방식등은 CPU마다 조금씩 차이가 있다.
  • 일종의 CPU 언어
  • x86-64, ARM 등이 ISA의 일종

ISA가 다르다 ⇒ CPU가 이해할 수 있는 명령어가 다르다 ⇒ 어셈블리어도 다르다.

즉, ISA가 다르면 같은 소스코드로 만들어진 같은 프로그램도 CPU가 이해할 수 있는 명령어, 어셈블리어가 달라진다.

ISA가 다른 CPU는 그로 인해 많은게 달라진다.

  • 제어장치가 명령어를 해석하는 방식
  • 사용되는 레지스터의 종류와 갯수
  • 메모리 관리 방법

운영체제와 ISA의 관계

  1. 운영체제(OS)는 ISA 위에서 동작한다. CPU가 제공하는 명령어와 기능을 이용해 시스템을 관리하는 것이 운영체제다.
  2. 즉 운영체제는 ISA에 맞춰 설계되야 함. 운영체제가 ISA를 이용해서 시스템을 관리하니까
  3. 하지만 현대에는 OS가 워낙 기능이 방대하고 복잡하며 성능도 중요하니, ISA가 OS를 전혀 고려하지 않고있지는 않다.

ISA, CPU, OS의 발전 순서

최초에 ISA가 정의되었고, CPU는 이를 실행할 수 있도록 설계되었다. 이를 기반으로 관리할 OS가 나타났다. 현재는 역방향으로도 영향을 끼치며 발전중이다.

CISC

CISC(Complex Instruction Set Computer)

  • 가변 길이 명령어: 복잡하고 다양한 명령어들을 활용
  • x86, x86-64가 CISC 기반의 ISA
  • 상대적으로 적은 수의 명령어로도 프로그램을 실행할 수 있음
    • 따라서 컴파일된 프로그램의 크기가 작음 ⇒ 메모리 공간 절약
  • 명령어가 다양해 명령어의 크기와 실행되기까지의 시간이 일정하지 않음
    • 규격화되지 않은 명령어가 파이프라이닝을 어렵게 만듬
  • 대다수의 명령어는 사용 빈도가 낮음

RISC

RISC(Reduced Instruction Set Computer)

  • 고정 길이 명령어: 짧고 규격화된 명령어, 되도록 1클럭 내외로 실행되는 명령어 지향
  • ARM이 RISC 기반의 ISA
  • 메모리 접근을 단순화하고 최소화하여 주소 지정 방식의 종류가 적음
    • load, store 만 메모리 접근 가능한 명령어임
    • load-store 구조라고도 부름