개발자는 기록이 답이다

혼공 컴퓨터구조 + 운영체제 5. CPU 성능 향상 기법 (Mac M2 코어 개수 확인 방법) 본문

CS/운영체제

혼공 컴퓨터구조 + 운영체제 5. CPU 성능 향상 기법 (Mac M2 코어 개수 확인 방법)

slow-walker 2024. 1. 6. 13:37

 

클럭과 코어, 스레드 라는 개념을 학습하고, 빠른 CPU를 만드는 설계 기법인 멀티 코어와 멀티 스레드란 무엇인지 이해해보자.

또한 맥에서 코어 수와 스레드 수를 보는 방법도 포스팅했으니 1절의 맨 마지막 부분을 확인하면 된다.


1. 빠른 CPU를 위한 설계

 

클럭 

 

CPU를 설계하는 엔지니어는 조금이라도 더 빠른 CPU를 만들어야 한다.

그렇다면 CPU를 어떻게 설계해야 할까?

 

  1. 컴퓨터 부품들은 '클럭 신호'에 맞춰 일사불란하게 움직인다
  2. CPU는 '명령어 사이클'이라는 정해진 흐름에 맞춰 명령어들을 실행한다.

 

클럭 신호가 빠르게 반복되면 CPU를 비롯한 컴퓨터 부품들은 그만큼 빠른 박자에 맞춰 움직인다.

즉, 클럭 속도가 높아지면 CPU는 명령어 사이클을 더 빠르게 반복하고, 다른 부품들도 그에 맞춰 더 빠르게 작동한다.

 

실제로 클럭 속도가 높은 CPU는 일반적으로 성능이 좋다. 그래서 클럭 속도는 CPU속도 단위로 간주되기도 한다.

 

클럭속도는 헤르츠(Hz)단위로 측정한다. 1초에 클럭이 몇 번 반복되는지를 나타낸다.

1초에 한번 반복되면 CPU 클럭 속도는 1Hz인 것이고, 클럭이 1초에 100번 반복되면 CPU 클럭 속도는 100Hz인 셈이다.

 

실제 CPU 클럭 속도는 어떨까?

 

아래 사진을 보면 기본 속도(Base)는 2.5GHz, 최대 속도(Max)는 4.9GHz라는 것을 알 수 있다.

1초에 클럭이 기본적으로 25억(2.5 X 10⁹)번, 순간적으로 49억 (4.9 X 10⁹)번 반복된다는 것이다.

클럭 속도는 일정하지 않다.

기본 클럭속도외 최대 클럭 속도로 나뉘어있는데, CPU는 계속 일정한 클럭 속도를 유지하기보다는 고성능으 ㄹ요하는 순간에는 순간적으로 클럭 속도를 높이고, 그렇지 않을 때는 유연하게 클럭 속도를 낮추기도 한다. 최대 클럭 속도를 강제로 더 끌어올릴 수도 있는데, 이를 오버클럭킹(overclocking)이라고도 한다.

 

그럼 클럭 속도를 무지막지하게 높이면 무조건 CPU가 빨라질까?  No

그래픽이 많이 요구되는 게임이나 영상 편집과 같이 CPU에 무리가 가는 작업을 장시간하면 컴퓨터가 뜨거워지는데,

클럭 속도를 무작정 높이면 이런 발열 문제가 더 심각해진다.

클럭 속도를 높이는 건 분명 CPU를 빠르게 만들지만, 클럭 속도만으로 CPU의 성능을 향상시키는 것은 한계가 있다.

 

 

코어와 멀티 코어

 

CPU의 코어와 스레드 수를 늘리는 것도 CPU 성능을 높이는 방법이다.

 

위에 있는 사진을 다시 보면 8코어라고 나와있는걸 볼 수 있다.

보통 컴퓨터를 구매하기 위해 CPU 사양을 살펴보면 '듀얼 코어', '쿼드 코어'와 같은 용어를 심심찮게 접할 수 있다.

 

그렇다면 코어가 무엇인지 알아보자

 

CPU는 '명령어를 실행하는 부품'이라고 했다. 과거에는 이 부품이 1개만 존재했지만, 오늘날 CPU는 많은 기술 발전을 거듭했고,

그 결과 CPU내부에는 '명령어를 실행하는 부품들'을 얼마든지 만들어낼 수 있게 되었다.

 

지금까지 CPU의 정의로 알고 있던 '명령어를 실행하는 부품'은 코어(core)이다.

즉, CPU는 명령어를 실행하는 부품을 여러 개 포함하는 부품으로 확장되었다.

 

 

코어를 여러 개 포함하고 있는 CPU를 멀티코어 CPU 또는 멀티코어 프로세서라고 부른다.

이는 CPU 내에 명령어를 처리하는 일꾼이 여러 명 있는 것과 같다.

 

당연히 멀티코어의 처리 속도는 단일코어보다 더 빠르다.

예를 들어, 2.4GHz인 단일 코어 CPU와 클럭 속도가 1.9GHz인 멀티코어 CPU를 비교하면 일반적으로 후자의 성능이 더 좋다.

 

CPU의 종류는 CPU안에 코어가 몇 개 포함되어 있는지에 따라 나뉜다.

코어 수 프로세서 명칭
1 싱글 코어(single-core)
2 듀얼 코어(dual-core)
3 트리플 코어(triple-core)
4 쿼드 코어(quad-core)
6 헥사 코어(hexa-core)
8 옥타 코어(octa-core)
10 데카 코어(deca-core)
12 도데카코어(dodeca-core)

 

그러면 코어를 계속 늘리면 연산 처리 속도도 더 빨라질까? No

 

CPU의 연산 속도가 꼭 코어 수에 비례해서 증가하지 않는다.

학교에서 4인 1조로 조별 과제를 할때 모두 똑같이 참여하여 한 사람이 낼 수 있는 생산성의 4배에 가까운 결과물을 만들어내기도 하지만,

그렇지 않은 경우도 있다. 업무가 균등하게 분배되지 않거나 한 두 사람만 열심히 한다면 결과적으로 한 두사람의 생산성만큼 결과물이 나오게 된다. 이처럼 코어마다 처리할 연산이 적절히 분배되지 않으면 코어 수에 비례해서 연산속도가 증가하지 않는다.

 

중요한 것은 코어마다 처리할 명령어들을 얼마나 적절하게 분배하느냐이고, 그에 따라서 연산 속도는 크게 달라진다.

 

스레드와 멀티 스레드

 

CPU의 멀티 스레드 기술을 이해하려면 우선 '스레드'에 대해 정확히 이해해야 한다.

운영체제(10장)과 CPU를 학습하는(5장)에서 스레드가 나온다.

 

스레드의 사전적 의미는 '실행 흐름의 단위'이다. 하지만 이 정의를 활자 그대로 받아들이지 말고 더욱 정교하게 이해해야 한다.

CPU에서 사용되는 스레드와 프로그래밍에서 사용되는 스레드는 용례가 다르기 때문이다.

 

스레드에는 CPU에서 사용되는 하드웨어적 스레드가 있고, 프로그램에서 사용되는 소프트웨어적 스레드가 있다.

 

 

하드웨어적 스레드

 

'하나의 코어가 동시에 처리하는 명령어 단위'를 의미한다

CPU에서 사용하는 스레드는 보통 CPU입장에서 정의된 하드웨어적 스레드를 의미한다.

 

지금 까지 배운 CPU는 CPU는 1코어 1스레드 CPU였다. 즉, 명령어를 실행하는 부품이 하나 있고, 한 번에 하나 씩 명령어를 실행하는 CPU를 가정했다.

 

 

반면, 여러 스레드를 지원하는 CPU는 하나의 코어로도 여러 개의 명령어를 동시에 실행할 수 있다.

예를 들어, 2코어 4스레드 CPU는 아래 그림처럼 명령어를 실행하는 부품을 2개 포함하고, 한 번에 4개의 명령어를 처리할 수 있다.

 

 

이처럼 하나의 코어로 여러 명렁어를 동시에 처리하는 CPU멀티스레드 프로세서 또는 멀티 스레드 CPU라고 한다.

 

맨위에 있는 사진 속 CPU는 8코어 16스레드였다.

명령어를 실행하는 부품을 8개 포함하고, 한 번에 16개 명령어를 처리할 수 있는 CPU를 의미한다.

코어 하나 당 2개의 하드웨어 스레드를 처리한다는 뜻이다.

 

멀티스레드와 함께 자주 접하게 될 용어로 하이퍼스레딩(hyper-threading)이라는 용어도 있다.

인텔의 멀티스레드 기술을 의미한다. 인텔이 자신들의 멀티 스레드 기술에 하이퍼스레딩이라는 명칭을 부여한 것이다.

 

소프트웨어적 스레드

 

'하나의 프로그램에서 독립적으로 실행되는 단위'를 의미한다.

프로그래밍 언어나 운영체제를 학습할때 접하는 스레드는 보통 소프트웨어적 스레드를 의미한다.

 

하나의 프로그램은 실행되는 과정에서 한 부분만 실행될 수도 있지만, 프로그램의 여러 부분이 동시에 실행될 수도 있다.

 

 

워드 프로세서 프로그램을 개발한다고 가정해보자. 그리고 아래 기능이 동시에 수행되길 원한다고 해보자

 

  1. 사용자로부터 입력받은 내용을 화면에 보여주는 기능
  2. 사용자가 입력한 내용이 맞춤법에 맞는지 검사하는 기능
  3. 사용자가 입력한 내용을 수시로 저장하는 기능

 

이 기능들을 작동시키는 코드를 각각의 스레드로 만들면 동시에 실행할 수 있다.

 

 

정리

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

 

한 번에 하나씩 명령어를 처리하는 1코어 1스레드 CPU도 소프트웨어적 스레드를 수십 개 실행할 수 있다.

1코어 1스레드 CPU로도 프로그램의 여러 부분을 동시에 실행할 수 있다.

 

멀티 스레드 프로세서

 

멀티스레드 프로세서는 하나의 코어로 여러 명령어를 동시에 처리하는 CPU라고 했는데, 어떻게 이런게 가능할까?

 

멀티스레드 프로세서를 실제로 설계하는 건 매우 복잡하지만 큰 핵심은 레지스터이다.

하나의 코어로 여러 명령어를 동시에 처리하도록 만들려면 프로그램 카운터, 스택 포인터, 데이터 버퍼 레지스터, 데이터 주소 레지스터와 같이 하나의 명령어를 처리하기 위해 꼭 필요한 레지스터를 여러 개 가지고 있으면 된다.

 

예를 들어, 프로그램 카운터가 2개 있다면 '메모리에서 가져올 명령어 주소'를 2개 지정할 수 있을 것이고, 스택 포인터가 2개 있다면 2개의 스택을 관리할 수 있다.

 

아래 그림을 보면, 하나의 명령어를 실행하기 위해 꼭 필요한 레지스터들을 편의상 '레지스터 세트'라고 표기했다.

레지스터 세트가 1개인 CPU는 한 개의 명령어를 처리하기 위한 정보들을 기억할 뿐이지만, 레지스터 세트가 2개인 CPU는 2개의 명령어를 처리하기 위한 정보들을 기억할 수 있다. 여기서 ALU와 제어장치가 2개의 레지스터 세트에 저장된 명령어를 해석하고 실행하면 하나의 코어에서 2개의 명렁어가 동시에 실행된다.

 

 

하드웨어 스레드를 이용해 하나의 코어로도 여러 명령어를 동시에 처리할 수 있다고 했다. 그러나 메모리 속 프로그램 입장에서 봤을 때 하드웨어 스레드는 마치 '한 번에 하나의 명령어를 처리하는 CPU'나 다름없다. 

 

가령 2코어 4스레드 CPU는 한 번에 4개의 명령어를 처리할 수 있는데,

프로그램 입장에서 봤을 땐 한 번에 하나의 명령어를 처리하는 CPU가 4개가 있는것 처럼 보인다.

그래서 하드웨어 스레드를 논리 프로세서 라고 부른다.

 

 

 

책의 저자는 4코어 8스레드 CPU를 사용한다고 한다.

작업 관리자를 열어 [성능]탭 [CPU]항목을 살펴보면 논리 프로세서가 8임을 확인할 수 있다. (윈도우 기준)

실제 CPU 속에 명령어를 처리하는 부품(코어)은 4개지만, 메모리 속 프로그램이 보기엔 한 번에 하나의 명령어를 처리하는 부품이 마치 여덟개 있는 것 처럼 보이기 때문에 논리 프로세서가 여덟개로 나오는 것이다.

 

 

맥 OS에서는 [System Settings] → 왼쪽 패널에 [General] → 하단의 [System Report] → 왼쪽 패널에 [Hardware] 로 들어가면

"Total Number of Cores" 가 논리 프로세서인것을 알 수 있다.

 

 

논리 프로세스가 8개로 나오는데, 그러면 나는 몇 코어 몇 스레드 인걸까?

터미널에 아래 명령어를 통해 확인해보자.

$ sysctl -n hw.logicalcpu
$ sysctl -n hw.physicalcpu

$ system_profiler SPHardwareDataType | grep "Cores"

 

 

나는 8코어 1스레드인건가..? 책에서는 무조건 코어 개수가 많은 것보다는 1코어 2스레드가 더 낫다고 했는데..

 

참고 블로그 : Mac에 있는 CPU코어 수를 찾는 방법

 

좀 더 찾아봤더니 M2는 8코어로  단일 스레드인것 같다. 그러니까 1코어 1스레드라는 말이다.

 

 

단일 스레드임에도 불구하고 좋은 성능이 나온다고 하니 걱정은 없는거겠지..?

참고 링크 :  애플 M2 단일 스레드 성능 i9-12900 수준 도달, 다중 테스트 스위트에서는 조금 부족

 

 

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

 

2. 명령어 병렬 처리 기법

빠른 CPU를 만들려면 높은 클럭 속도에 멀티코어, 멀티 스레드를 지원하는 CPU를 만드는 것도 좋지만,

CPU가 놀지않고 시간을 알뜰하게 쓰며 작동하게 만드는 것도 중요하다

 

명령어를 동시에 처리하여 CPU를 한시도 쉬지 않고 작동시키는 기법인 명령어 병렬 처리기법(ILP : Instruction-Level Parallelsim)을 알아보자. 대표적으로 명령어 파이프라인, 슈퍼스칼라, 비순차적 명령어 처리 가 있다.

 

명령어 파이프라인

 

명령어 파이프라인을 이해하려면, "하나의 명령어가 처리되는 전체 과정"을 비슷한 시간 간격으로 나누어 보아야 한다.

 

명령어 처리 과정을 클럭단위로 나눈것

  1. 명령어 인출(Instruction Fetch)
  2. 명령어 해석(Instruction Decode)
  3. 명령어 실행(Execute Instruction)
  4. 결과 저장(Write Back)

(물론 이 단계가 정답은 아니지고, 전공서에 따라 다를 수도 있다)

 

여기서 중요한 것은 같은 단계가 겹치지만 않는다면 CPU는 '각 단계를 동시에 실행할 수 있다'는 것이다.

예를 들어 CPU는 한 명령어를 '인출'하는 동안에 다른 명령어를 '실행'할 수 있고, 한 명령어가 '실행'되는 동안에 연산 결과를 '저장'할 수 있다.

 

t1에서 명령어 1, 2를 동시에 처리할 수 있고, t2에는 명령어 1,2,3을 동시에 처리할 수 있다.

이처럼 명령어를 겹쳐서 수행하면 명령어를 하나하나 실행하는 것보다 훨씬 더 효율 적이다

 

 

만약 명령어 파이프라인을 사용하지 않고 모든 명령어를 순차적으로만 처리한다면 아래처럼 비효율적일 것이다.

 

 

파이프라이닝이 높은 성능을 가져오기는 하지만, 특정 상황에서는 성능 향상에 실패하는 경우도 있다.

이러한 상황을 파이프라인 위험이라고 부르고, 3가지가 있다.

 

1) 데이터 위험

 

명령어 간 '데이터 의존성'에 의해 발생한다. 모든 명령어를 동시에 처리할 수는 없다.

어떤 명령어는 이전 명령어를 끝까지 실행해야만 비로소 실행할 수 있는 경우가 있다.

 

예를 들어, 아래 두 명령어를 보자.

편의상 레지스터 이름을 R1, R2, R3, R4, R5라고 하고 '왼쪽 레지스터에 오른쪽 결과를 저장하라'는 ←기호로 표기해보자.

 

명령어 1을 수행해야만 명령어 2를 수행할 수 있다.

즉, R1에 R2 + R3 결괏값이 저장되어야 명령어 2를 수행할 수 있다. 만약 명령어 1 실행이 긑나기 전에 명령어 2를 인출하면 R1에  R2 + R3결과값이 저장되기 전에 R1 값을 읽어 들이므로 원치 않은 R1 값으로 명령어 2를 수행한다.

 

따라서 명령어 2는 명령어 1의 데이터에 의존적이다.

이처럼 데이터 의존적인 두 명령어를 무작정 동시에 실행하려고 하면 파이프라인이 제대로 동작하지 않는 것을 '데이터 위험'이라고 한다.

 

2) 제어 위험

 

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

기본적으로 프로그램 카운터는 '현재 실행 중인 명령어의 다음 주소'로 갱신된다.

하지만 프로그램 실행 흐름이 바뀌어 명령어가 실행되면서 프로그램 카운터 값에 갑작스러운 변화가 생긴다면 명령어 파이프라인에 미리 가지고 와서 처리중이었던 명령어들은 아무 쓸모가 없어지고 이를 제어 위험이라고 한다.

 

이를 위해 사용하는 기술 중 하나가 분기 예측으로, 프로그램이 어디로 분기할지 미리 예측한 후 그 주소를 인출하는 기술이다.

 

3) 구조적 위험

 

명령어들을 겹쳐 실행하는 과정에서 서로 다른 명령어가 동시에 ALU, 레지스터 등과 같은 CPU부품을 사용하려고 할때 발생한다.

자원 위험이라고도 부른다.

 

슈퍼 스칼라

 

파이프라이닝은 단일 파이프라인으로도 구현 가능하지만, 오늘날 대부분의 CPU에서는 여러 개의 파이프라인을 이용한다

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

 

 

명령어 파이프라인을 하나만 두는 것이 마치 공장 생산라인을 한 개 두는 것과 같다면, 슈퍼 스칼라는 공장 생산라인을 여러개 두는 것과 같다.

 

슈퍼스칼라 구조로 명령어 처리가 가능한 CPU를 슈퍼스칼라 프로세서 또는 슈퍼스칼라 CPU라고 부른다.

슈퍼스칼라 프로세서는 매 클럭 주기마다 동시에 여러 명령어를 인출할 수도, 실행할 수도 있어야 한다.

가령 멀티스레드 프로세서는 한 번에 여러 명령어를 인출하고, 해석하고, 실행할 수 있기 때문에 슈퍼스칼라 구조를 사용할 수 있다.

 

슈퍼스칼라 프로세서는 이론적으로 파이프라인 개수에 비례하여 프로그램 처리 속도가 빨라진다

하지만 파이프라인 위험등의 예상치 못한 문제가 있어 실제로는 반드시 파이프라인 개수에 비례하여 빨라지지 않는다.

 

이 때문에 슈퍼 스칼라 방식을 차용한 CPU는  파이프라인 위험을 방지하기 위해 고도로 설계되어야 한다.

여러 개의 파이프라인을 이용하면 하나의 파이프라인을 사용할 때보다 데이터 위험, 제어 위험, 자원 위험을 피하기가 더욱 까다롭기 때문이다.

 

비순차적 명령어 처리

 

보통 OoOE라고 줄여 부른다. 이 기법은 많은 전공서에서 다루지 않지만, 오늘날 CPU 성능 향상에 크게 기여한 기법이자 대부분의 CPU가 차용하는 기법이기에 꼭 알아두는게 좋다.

 

비순차적 명령어 처리 기법 파이프라인의 중단을 방지하기 위해 명령어를 순차적으로 처리하지 않는 것이다.

 

파이프라이닝과 슈퍼스칼라 기법은 모두 여러 명령어를 순차적으로 처리한다.즉, 프로그램을 위에서 아래로 차례차례 실행하는 방식이다.

 

하지만 파이프라인 위험과 같은 예상치 못한 문제들로 인해 명령어는 곧바로 처리되지 못하기도 하고, 모든 명령어를 순차적으로 처리한다면 이런 상황에서 명령어 파이프라인은 멈춰버리게 된다.

 

예를 들어, 아래처럼 명령어들로 이루어진 소스코드가 있다고 가정해보자.

메모리 N번지는 M(N)으로, '메모리 N번지에 M을 저장하라'는 M(N) ← M으로 표기해보자.

 

3번 명령어를 실행하기 위해서는 M(100)값은 물론 M(101)값이 결정되어야 하기에 1번과 2번 명령어 실행이 끝날때 까지 기다려야한다.

2번 명령어 실행이 끝날때 까지 3,4,5,6번 명령어들은 기다리게 된다.

 

그런데 데이터 의존성이 전혀 없는, 순서를 바꿔서 처리해도 수행 결과에 명향을 미치지 않는 명령어들이 있다.

가령 3번은 다음과 같이 뒤의 명령어 순서를 바꾸어 실행해도 크게 문제될 것이 없다.

이렇게 순서를 바꿔서 실행하면 아래처럼 수행된다.

순차적으로 명령어를 처리할때 보다 더 효과적으로 처리할 수 있다.

 

 

하지만 아무 명령어나 순서를 바꿔서 수행할 수는 없다.

 

위 코드에서 3번 명령어와 1번 명령어의 순서를 바꿀수는 없다. 3번 명령어를 수행하기 위해 반드시 M(100)값이 결정되어야 하기때문이다. 마찬가지로 4번 명령어와 1번 명령어를 바꿀 수 없다. 1번 명령어를 토대로 3번 명령어가 수행되고, 3번 명령어를 토대로 4번이 수행되니까.

 

하지만 4번 명령어와 5번 명령어는 순서를 바꾸어 실행할 수 있다.

두 명령어는 어떤 의존성도 없기에 순서를 바꿔도 전체 프로그램의 실행 흐름에는 영향이 없다.

 

 

3. CISC와 RISC

명령어 파이프라이닝과 슈퍼스칼라 기법을 실제로 CPU에 적용하려명 명령어가 파이프라이닝에 최적화되어있어야 한다.

 

'파이프라이닝 하기 쉬운 명령어'란 무엇일까?

명령어가 어떻게 생겨야 파이프라이닝에 유리할까? 이거랑 관련해서 CPU의 언어인 ISA와 각기 다른 성격의 ISA를 기반으로 설계된 CISC와 RISC를 알아보자

 

 

명령어 집합

 

3장에서 학습했던 명령어의 생김새와 주소 지정 방식를 다시 보고오자.

 

이 세상 모든 CPU들이 똑같이 생긴 명령어 일까? 수많은 CPU제조사들이 있고, CPU마다 규격과 기능, 만듦새가 다른데, 모든 CPU가 이해하고 실행하는 명령어들이 똑같이 생겼을까? NO

 

기본적인 구조와 작동원리는 3장에서 학습한 내용과 크게 다르지 않지만, 명령어의 세세한 생김새, 명령어로 할 수 있는 연산, 주소 지정 방식 등은 CPU마다 조금씩 차이가 있다. CPU가 이해할 수 있는 명령어들의 모음을 명령어 집합(Instruction set) 또는 명령어 집합 구조(ISA : Instruction set Architecture)이라고 한다.

(구조라는 단어가 붙인 이유는 CPU가 어떤 명령어를 이해하는지에 따라 컴퓨터 구조 및 설계 방식이 달라지기 때문이다)

 

  • 인텔의 노트북 속 CPU는 x86 혹은 x86-64 ISA를 이해한다.
  • 애플의 아이폰 속 CPU는 ARM ISA를 이해한다

x86 혹은 x86-64와 ARM은 다른 ISA이기 때문에 인텔 CPU를 사용하는 컴퓨터와 아이폰은 서로의 명령어를 이해할 수 없다.

실행 파일은 명령어로 이루어져있고 서로의 컴퓨터가 이애할 수 있는 명령어가 다르기 때문이다.

 

 

3장에서 어셈블리어는 명령어를 읽기 편하게 표현한 언어라고 했다.

ISA가 다르다는건 CPU가 이해할 수 있는 명령어가 다르다는 것이고, 명령어가 달라지면 어셈블리어도 달라진다.

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

 

 

gcc 11.2라는 동일한 컴파일러 사용

 

 

ISA가 같은 CPU끼리는 서로의 명령어를 이해할 수 있지만, ISA가 다르면 서로의 명령어를 이해하지 못한다.

이런점에서 ISA는 일종의 CPU의 언어인 셈이다.

 

CPU가 이해하는 명령어(ISA)들이 달라지면 명령어의 생김새만 달라지는게 아니라, 그에 따른 나비효과로 많은 것이 달라진다.

제어장치가 명령어를 해석하는 방식, 사용되는 레지스터의 종류와 개수, 메모리 관리 방법 등 많은 것이 달라진다.

→ CPU 하드웨어 설계에도 큰 영향을 미친다.

 

우리가 실행하는 프로그램은 명령어로 이루어져있다. 

ISA는 CPU의 언어임과 동시에 CPU를 비롯한 하드웨어가 소프트웨어를 어떻게 이해할지에 대한 약속이라고 볼수도 있다.

 

 

위에서 명령어 병렬 처리 기법들을 학습했는데, 이를 적용하기에 용이한 ISA가 있고, 그렇지 못한 ISA도 있다.

다시 말해 명령어 파이프라인, 슈퍼스칼라, 비순차적 명령어 처리를 사용하기에 유리한 명령어 집합이 있고, 그렇지 못한 명령어 집합도 있다.

 

그렇다면 명령어 병렬 처리 기법을 도입하기 유리한 ISA는 무엇일까?

 

CISC

 

  • Complex Instruction Set Computer의 약자
  • 복잡한 명령어 집합을 활용하는 컴퓨터를 의미. * 여기서 컴퓨터를 CPU라고 생각해도 좋다.
  • 대표적으로 x86, x86-64이 CISC기반의 ISA
  • 다양하고 강력한 기능의 명령어 집합을 활용해서 명령어의 크기와 형태가 다양한 가변 길이 명령어 활용
  • 메모리에 접근하는 주소 지정 방식도 다양해서 아주 특별한 상황에서만 사용되는 독특한 주소 지정 방식 존재

 

 

다양하고 강력한 명령어를 활용한다는 말은 상대적으로 적은 수의 명령어로도 프로그램을 실행할 수 있다는 것을 의미한다.

위에서 컴파일한 x86-64의 어셈블리어 코드를 다시 보면 x86-64코드 길이가 ARM보다 짧다.

ARM 명령어 여러개로 수행할 수 있는 일을 x86-64 명령어 몇개로 수행할 수 있다는 것이다.

 

※ 프로그램을 실행하는 명령어 수가 적다 : 컴파일 된 프로그램 크기가 작다

같은 소스 코드를 컴파일해도 CPU마다 실행 파일의 크기가 다를 수 있다는 것이다.

 

 

▶ 장점 

  • "적은 수의 명령어만으로도 프로그램을 동작시킬 수 있다"는 점은 메모리 공간을 절약할 수 있다는 것을 의미
  • 메모리를 최대한 아끼며 개발해야 했던 시절에 인기가 늘었다.

 

▶ 단점

  • 활용하는 명령어가 워낙 복잡하고 다양한 기능을 제공하는 탓에 명령어의 크기와 실행되기까지 시간이 일정하지 않다
  • 복잡한 명령어때문에 명령어 하나를 실행하는데 여러 클럭 주기를 필요로 한다
  • 명령어의 규격화가 어려워 파이프라인을 구현하기 어렵다
  • 대다수의 복잡한 명령어는 그 사용 빈도가 낮다
    • (1974년 IBM 연구소의 존 코크는 CISC 명령어 집합중 20%정도가 사용된 전체 명령어의 80%를 차지한다고 증명했다)

 

명령어 파이프라인 기법을 위한 이상적인 명령어는 각 단계에 소요되는 시간이(1클럭 기준) 동일해야 한다. 그래야 파이프라인이 마치 공장의 생산라인 처럼 착착착 결과를 낸다. 하지만 CISC가 활용하는 명령어는 수행 시간이 길고 가지각색이기 때문에 파이프라인이 효율적으로 명령어를 처리할 수 없다. 명령어 파이프라인이 제대로 동작하지 않는다는것은 높은 성능을 요구하는 현대 CPU에게 치명적이다.

 

 

 

 

CISC의 단점들로 보완해야할 점을 생각해 볼 수 있다.

 

  • 빠른 처리를 위해 명령어 파이프라인을 십분 활용해야한다
    • 원할한 파이프라이닝을 위해 '명령어 길이와 수행시간이 짧고 규격화'되어야 한다
  • 어차피 자주쓰이는 명령어만 줄곧 사용된다
    • 복잡한 기능을 지원한느 명령어를 추가하기보다 '자주 쓰이는 기본적인 명령어를 작고 빠르게 만드는게' 중요하다

 

RISC

 

 

  • Reduced Instruction Set Computer의 약자다
  • 짧고 규격화된 명령어, 되도록 1클럭 내외로 실행되는 명령어인 고정 길이 명령어 활용
  • 메모리에 직접 접근하는 명령어를 load, store 2개로 제한할 만큼 메모리 접근을 단순화, 최소화함
    • CISC보다 주소 지정 방식의 종류가 적다 (load-store구조)
  • CISC보다 레지스터를 이용하는 연산이 많고, 일반적인 경우보다 범용 레지스터 개수도 더 많다
  • 사용가능한 명령어 개수가 CISC보다 적어서 많은 명령어로 프로그램 작동시킨다
  • 대표적으로 ARM이 RISC기반의 ISA이다.