CPU
CPU 또는 중앙처리장치는 컴퓨터의 특정 메모리에서 특정 데이터 값(코드)을 가져와 해석하고 그에 대응되는 연산을 처리한 후 레지스터/주기억장치 등지에 연산 결과 값을 기억하도록 제어하는 폰 노이만 구조[1]에 기반하여 설계된 집적 회로 부품을 말한다.
컴퓨터 내부에서는 기억장치(RAM, 플래시 메모리, 하드디스크, ROM 등)와 함께 사실상 컴퓨터 그 자체라고 말할 수 있는 두 장치 중 하나다.
CPU의 성능은 크게 신호를 전달하는 타이밍을 정하는 클럭 속도, 한번에 처리 가능한 명령어 수를 결정하는 IPC, 그리고 병렬적인 데이터 연산 능력을 결정하는 코어 수에 따라 결정된다. 여기에 추가로 전력 공급량이나 CPU 내 트랜지스터의 과열로 인한 고장을 예방할 수 있는 발열 제어 같은 부수적 요소가 따라붙는다.
한번에 처리 가능한 데이터의 비트 수에 따라 n비트 프로세서라고 일컫는다.
구조와 원리[편집 | 원본 편집]
CPU는 크게 역할 순서대로 배치되어 데이터를 보관하는 Datapath와 그 데이터가 갈 위치를 정하는 Control Unit을 내장하고 있다.
ISA[편집 | 원본 편집]
명령어 집합 구조(Instruction Set Architecture)는 CPU가 수행할 명령어를 모은 집합의 구조로 그 CPU의 프로그램이 어떤 구조의 기계어로 실행되는지 정의한다.
ISA의 효율은 ISA가 기억 공간, 사용 빈도, 데이터/코드의 대역폭 측면에서 명령어 처리 능력의 효율을 보여주는 척도다. 함수 연산 기능과 기타 연산의 기능 비율로 계산하며, 주소 지정 방식에도 영향을 받는다.[2]
파이프라인[편집 | 원본 편집]
레지스터[편집 | 원본 편집]
CPU 내부에서 CPU가 계산하는 값을 저장하는 메모리 유닛이다. 보통 범용 레지스터(General Purpose Register, GPR)와 시스템 레지스터로 구분되며, 시스템 레지스터는 다시 명령 레지스터, 주소 레지스터(예: Stack pointer), 상태 레지스터(예: Program status word)로 구분된다. 과거 CISC 설계가 CPU 설계 방법론에 남아있었을 당시에는 마이크로코드에 따라 특정 방식으로만 연산 가능한 전용 레지스터[3]가 있었으나, CPU 작동 속도가 빨라진 현재에는 다른 명령어로 대체 가능하기 때문에 쓸모 없어지면서 디코더 유닛을 쓸데없이 크게 만들고 프로그래밍 학습 난이도를 높인다는 이유로 전용 레지스터 개념이 사실상 없어졌다.
CPU가 주기억장치에서 읽어온 현재 명령어를 기억하는 인스트럭션 레지스터(Instruction Register, IR)과 그 다음에 읽을 번지수(Address Number)를 기억하는 프로그램 카운터(Program Counter, PC)를 레지스터로 보는 경우도 있으나 이들은 별도의 하드웨어 로직으로 치고 일반적인 레지스터 연산 명령어와는 다른 전용 분기 명령어를 써서 값을 바꾼다.
캐시 메모리[편집 | 원본 편집]
한편 주기억장치로 쓰이는 축전기 기반 DRAM 및 보조 기억 장치(하드디스크 및 플래시 메모리)의 느린 읽고 쓰기 속도로 인한 CPU의 성능 저하를 보완하기 위해 현대 CPU에는 상대적으로 빠르지만 비싼 플립플롭 기억 소자를 사용하는 저용량의 SRAM 또는 특수한 DRAM에 주기억장치에 담긴 일부 데이터를 저장하여 CPU로 데이터를 빨리 끌어서 쓸 수 있도록 하는 조치가 되어있는데, 이런 조치가 되어 있는 설계를 메모리 계층이라고 하며 메모리 계층에 사용된 저용량 RAM을 캐시 메모리라고 부른다.
캐시 메모리를 수직 계층화하여 몇 단계의 Multi-Level 캐시 메모리를 만들 수 있다. 이렇게 하는 이유는 캐시 메모리의 용량이 클 수록 데이터 검색에 걸리는 시간이 길어지기 때문에 최근에 썼거나 자주 쓰는 데이터는 Level 1 캐시 메모리 등에 저장하고 좀 덜 쓰는 데이터는 Level 2 이상 캐시 메모리에 저장하여 캐시 메모리의 효용을 높이는 것이다. 여기에 폰 노이만 구조의 발전형으로 CPU 명령어용 메모리와 일반 데이터용 메모리를 구분하는 하버드 구조의 적용이 쉬워지는 것은 덤이다(Level 1 캐시 메모리에만 적용하면 된다). 이때 CPU의 가까운 레벨의 캐시 메모리(L1)가 먼 쪽 레벨의 캐시 메모리(L2 이상)의 데이터를 포함할 것이냐(Inclusive), 제외할 것이냐(Exclusive)를 설정할 수 있다. 현대에는 용량 문제로 Exclusive한 데이터 기록 정책이 좀 더 자주 쓰인다.
캐시 메모리는 데이터 저장 방식에 따라 메인 메모리 주소의 데이터와 일대일 대응을 하는 Direct-mapped Cache나 다대일 대응을 하는 n-way Associative Cache 등으로 나뉘며 캐시 메모리가 다 차거나 중복된 위치에 데이터를 채워야 할 경우(cache miss)에 새 데이터를 배치하는 각종 방법론(Least Recently Used, Random 및 기타 등등)이 있다.
- Belady's Algorithm: 앞으로 가장 오래 안 쓸 캐시 메모리 내 데이터부터 갈아 치우는 알고리즘이다. 특정 데이터가 캐시에 기록된 시점부터 캐시 내에 존재하는 시간을 세서 Cache Miss가 날 때마다 접근이 가장 나중에 있을 데이터부터 갈아치우는 것이다. 하지만 이건 이상적 알고리즘이므로 현실에서는 사용 불가다.
- Random Replacement(RR): 그냥 아무거나 고르면 된다. 철저하게 성능 향상 효과를 운빨에 의존한다(…)
- FIFO / LIFO: 먼저 들어온 데이터가 먼저 캐시에서 퇴출되는 알고리즘과 나중에 들어온 데이터가 먼저 캐시에서 퇴출되는 알고리즘이다. 간단하다.
- Least Recently Used(LRU): 가장 오래 전에 Hit한 데이터부터 Miss시에 퇴출한다. 반대 버전인 MRU(Most Recently Used)가 사실상 삽질에 가까운데 이건 의외로 잘 먹히는 편이다.
- Time aware least recently used(TLRU): 벨라디 알고리즘과 LRU를 반반 섞은 알고리즘
- Segmented LRU: 캐시 메모리를 두 부류로 나누어 한쪽은 LRU에 의한 교체를 빠르게 하고, 거기서 오래 버티는 데이터를 발견하면 다른 영역으로 옮겨서 LRU에 의한 교체가 덜 일어나게 한다. 그리고 LRU에 의한 교체가 덜 일어나는 영역은 Most Recently Used 정책에 따라 다시 빠른 교체가 일어나는 영역으로 이동할 수 있다.
- Least Frequently Used(LFU): 가장 덜 쓰인 데이터를 교체한다.
그 외에도 다른 캐시 데이터 교체 정책들이 있다.
Out of order 프로세싱[편집 | 원본 편집]
한편 몇몇 명령어는 먼저 실행해야 할 다른 명령어가 없이 명령어 레벨에서 각각 독립적으로 실행 가능한 경우가 생기는데, 이때 실행 순서를 재배치하여 몇몇 명령어들을 선제적으로 처리할 수 있는 구조를 Out of Order 프로세싱이라고 한다. 이때에는 Fetch와 Decode라는 단계 대신 Issue라는 단계를 거쳐 토마술로 알고리즘 등에 의해 먼저 실행할 명령어들의 순서를 결정한다.
분기 예측[편집 | 원본 편집]
조건문이나 반복문 같이 조건 분기를 하는 경우 조건 분기에 의한 메모리 위치 이동(이하 점프)가 일어날 때까지 Fetch/Decode에 대응하는 부분은 놀게 되는데, 성능 향상을 위해 다음에 들어올 명령어를 예측할 수 있는 몇 가지 방법을 분기 예측이라고 한다.
반복문의 경우 분기 예측의 적중률이 매우 높기에[4] 분기 예측은 CPU 성능 향상에 중요한 역할을 맡는다.
파이프라인 단계가 지나치게 많을 경우 분기 예측 실패로 인한 파이프라인 비우기가 오래 걸리기 때문에 성능에 오히려 악영향을 주게 된다.
MMU와 가상 메모리[편집 | 원본 편집]
모든 CPU는 한번에 처리 가능한 데이터 비트 수에 따라 메모리에 접근 가능한 최대 주소 값이 정해져 있다. 예를 들어 한번에 32비트 데이터를 처리하는 x86 / v7 이하 ISA 사용 ARM CPU는 최대 4GB의 RAM까지만 온전히 사용할 수 있다.
문제는 실제로 시스템에 설치된 RAM이 그보다 작을 경우이다. 이 경우 OS 위 각종 소프트웨어가 RAM 공간 확보를 소프트웨어 단계에서 직접 처리하는 것은 번거롭고 프로세스의 컨텍스트 스위칭까지 생각하면 DOS 시절처럼 직접 프로그램이 RAM 하드웨어를 생각하며 메모리를 차지하면 시스템 동작이 꼬이기 쉽기 때문에 CPU 차원에서 데이터 처리 비트 수에 따른 이론 상의 메모리 공간(가상 메모리)을 실제 물리 RAM 용량에 맞게 매핑하고 그 상태를 관리하며 소프트웨어에게는 모든 프로세스에게 가상의 메모리 공간을 자유롭게 쓸 수 있는 것처럼 보장하는 MMU(Memory Management Unit)라는 장치를 쓴다.
보통 페이지(Page)라 부르는 메모리 공간의 단위 조각(Frame)을 각 프로세스가 요구하는 Memory 양에 맞춰 OS가 CPU에게 메모리 접근 명령을 호출하면 CPU가 MMU를 이용해 RAM 상의 데이터를 가상 주소(Virtual Address)를 페이지 테이블에서 사용하는 논리 주소 -> 물리 주소 순으로 변환해 접근하는 식으로 내부 레지스터로 읽고 쓴다. 프로세스(또는 태스크)의 컨텍스트 스위칭이 일어나면 현재 CPU에 실행 중인 프로세스가 바뀌며 가상 메모리 주소가 바뀐다. 만일 한 프로세스가 자신에게 사용 가능하도록 허용한 유저 메모리 영역이 아닌 커널 영역(OS에서 사용자 프로그램에게 OS 차원의 기능 접근을 용이하게 하기 위해 미리 공개해 놓은 OS 커널 코드가 있는 공간)을 침범하는 등 비정상적 메모리 접근을 할 경우 MMU는 메모리 보호 위반을 감지하고 오류가 발생했다는 인터럽트를 CPU 제어부에 날린다.
물리 메모리를 다 썼는데 추가적으로 프로세스가 메모리 확보 요청을 날리면 프로세스는 MMU->CPU->OS 순으로 처리되는 Out Of Memory 에러 신호를 마주치게 될 것이다. 만일 메모리 Swap 기능(윈도우의 가상 메모리 파일, 리눅스의 스왑 파일/스왑 파티션 등)이 있는 OS라면 보조 기억 장치에 현재 실행하고 있지 않은 프로세스의 메모리 영역 데이터를 백업하는 식으로 가용 메모리 공간(물론 RAM 상에서)를 확보할 수 있다. 반대로 RAM이 충분히 크면 보조 기억 장치에 데이터를 저장하지 않고 RAM의 일부를 파일 데이터 저장용으로 쓸 수도 있는데, 이를 램 디스크라고 한다.
CPU와 주변 장치의 통신[편집 | 원본 편집]
CPU의 주기억장치 접근[편집 | 원본 편집]
한편 프로세서와 메인 메모리가 통신하는 연결 구조인 토폴로지도 여러 종류가 있다. 만일 모든 프로세서(또는 프로세서 내 코어)가 같은 메모리에 연결되어 있다면 Uniform Memory Access(UMA)라고 한다. 그렇지 않고 프로세서 별로 접근 가능한 메모리가 다른 경우 Non-Uniform Memory Access(NUMA)라고 한다. 보통 현대의 CPU는 프로세서를 적절히 분할하여 RAM 채널을 할당하는 노드 단위의 NUMA를 쓰며, NUMA에서 한 프로세서가 자신에게 할당된 RAM이 아닌 다른 RAM 장치의 데이터를 가져와야 할 경우에는 UMA에 비해 데이터 페치가 오래 걸리게 된다. 하지만 현대에는 CPU의 고속 동작으로 인해 CPU와 RAM 사이 데이터 통신에 병목이 매우 잘 걸리기에 대역폭 문제로 NUMA 구조에 캐시 동기화 구조를 추가하는 ccNUMA(cache coherent NUMA)가 보편적이며, ccNUMA의 구현의 어려움 때문에 CPU 내 메모리 컨트롤러/캐시 컨트롤러 제작의 난이도가 올라갔다.
분류[편집 | 원본 편집]
- 플린 분류: SISD, SIMD, MISD, MIMD
설계 및 제조사[편집 | 원본 편집]
- ARM 계열: 삼성전자, 퀄컴, 미디어텍 및 기타 제조사들
- x86 및 AMD64 계열: 인텔, AMD, VIA 등
- MIPS: MIPS 테크놀로지의 CPU
- POWER: IBM의 메인프레임/서버용 CPU이다. 일반 사용자용 PowerPC도 있었으나 현재는 IBM에서 해당 프로젝트를 버렸다.
- SPARC, 옐브루스 프로세서 : 썬 마이크로시스템즈가 만든 SPARC은 현재 대가 사실상 끊겼으나 러시아에서 개발한 CPU인 옐브루스 프로세서에 SPARC에 쓰인 각종 전자공학적 기술이 들어갔다.
- RISC-V: UC 버클리에서 개발중인 새로운 RISC 명령어셋 기반 CPU이다.
- 모토로라 68000
각주
- ↑ 프로그램이라는 코드 묶음을 메모리에 저장하여 컴퓨터 내에 내장시키고 프로세서로 프로그램을 가져와 가공하는 컴퓨터 구조
- ↑ 명령어 비트 내에 주소값이 들어있는 직접 주소 지정이 주소값이 가리키는 메모리 공간의 값을 찾아 진짜 주소값을 알아내야 하는 간접 주소 지정보다 ISA 효율이 좋다.
- ↑ Memory Address Register나 Memory Buffer Register 등. x86 계열 CPU의 경우 레지스터 이름과 몇몇 Instruction에 그 잔재가 남아 AX 레지스터는 누산('A'ccumulator) 연산 전용, BX는 프로시저의 호출 지점으로의 복귀(Return)를 위한 베이스 메모리 주소('B'ase Address Register) 관련 연산, CX는 루프 카운터('C'ounter)로 쓰는 것을 강제하는 명령어들이 남아 있다.
- ↑ 상식적으로 n번의 반복 후 나가야 하는 코드의 경우 단 한번만 틀리면 되므로 n에 들어가는 값이 클수록 적중률이 올라간다