나무모에 미러 (일반/밝은 화면)
최근 수정 시각 : 2024-10-17 13:05:57

멀티코어 프로세서

멀티코어에서 넘어옴

'''이론 컴퓨터 과학
{{{#!wiki style="display: inline-block; font-family:Times New Roman, serif;font-style:italic"'''
{{{#!wiki style="margin: 0 -10px -5px; min-height: calc(1.5em + 5px)"
{{{#!folding [ 펼치기 · 접기 ]
{{{#!wiki style="margin: -5px -1px -11px"
<colbgcolor=#a36> 이론
기본 대상 수학기초론{수리논리학(논리 연산) · 계산 가능성 이론 · 범주론 · 집합론} · 이산수학(그래프 이론) · 수치해석학 · 확률론통계학 · 선형대수학
다루는 대상과 주요 토픽
계산 가능성 이론 재귀함수 · 튜링 머신 · 람다대수 · 처치-튜링 명제 · 바쁜 비버
오토마타 이론 FSM · 푸시다운 · 튜링 머신(폰노이만 구조) · 정규 표현식 · 콘웨이의 생명 게임 · 형식언어
계산 복잡도 이론 점근 표기법 · 튜링 기계^고전, 양자, 비결정론적, 병렬 임의접근 기계^ · 알고리즘 · 자료구조 · 알고리즘 패러다임(그리디 알고리즘, 동적 계획법)
정보이론 데이터 압축(무손실 압축 포맷 · 손실 압축 포맷) · 채널 코딩(채널 용량) · 알고리즘 정보 이론(AIT) · 양자정보과학
프로그래밍 언어이론 프로그래밍 언어(함수형 언어 · 객체 지향 프로그래밍 · 증명보조기) · 메타 프로그래밍 · 유형 이론 · 프로그래밍 언어 의미론 · 파싱 · 컴파일러 이론
주요 알고리즘 및 자료구조
기초 정렬 알고리즘 · 순서도 · 탐색 알고리즘
추상적 자료형 및 구현 배열^벡터^ · 리스트^연결 리스트^ · 셋(set)^레드-블랙 트리, B-트리^ · 우선순위 큐^, 피보나치 힙^
수학적 최적화 조합 최적화 외판원 순회 문제 · 담금질 기법 · 유전 알고리즘 · 기계학습
볼록 최적화 내부점 방법 · 경사하강법
선형계획법 심플렉스법
계산 수론 및 암호학 밀러-라빈 소수판별법 · Pollard-rho 알고리즘 · 쇼어 알고리즘 · LLL 알고리즘 · 해시(MD5 · 암호화폐 · 사전 공격(레인보우 테이블) · SHA) · 양자 암호
대칭키 암호화 방식 블록 암호 알고리즘(AES · ARIA · LEA · Camellia) · 스트림 암호 알고리즘(RC4)
공개키 암호화 방식 공개키 암호 알고리즘(타원 곡선 암호 · RSA) · 신원 기반 암호 알고리즘(SM9)
계산기하학 볼록 껍질 · 들로네 삼각분할 및 보로노이 도형^Fortune의 line-sweeping 알고리즘^ · 범위 탐색^vp-tree, R-tree^ · k-NN
그래프 이론 탐색^BFS, DFS, 다익스트라 알고리즘, A* 알고리즘^ · 에드몬드-카프 · 크루스칼 알고리즘 · 위상 정렬 · 네트워크 이론
정리
정지 문제대각선 논법 · 암달의 법칙 · P-NP 문제미해결 · 콜라츠 추측미해결
틀:이산수학 · 틀:수학기초론 · 틀:컴퓨터공학 }}}}}}}}}



1. 개요2. 상세
2.1. 역사2.2. 멀티코어 프로세서를 제대로 활용하려면? : 멀티스레드 프로그래밍2.3. 어떤 식으로 구현하는가? : 멀티스레드 프로그래밍 패턴
2.3.1. 공유 메모리 모델2.3.2. 메시지 전달 모델(생산자-소비자 패턴)
2.4. 구현하려면 무엇이 필요하는가? : 지원하는 프로그래밍 언어와 라이브러리2.5. 멀티코어 프로세서의 종류
2.5.1. 멀티코어 CPU2.5.2. 멀티코어 GPU
3. 매니코어 프로세서4. 하이브리드 프로세서
4.1. 관련 기술과 제품들
5. 관련 문서
프로세서의 코어 수에 따른 분류
싱글코어 프로세서 멀티코어 프로세서 매니코어 프로세서 하이브리드 프로세서

1. 개요

파일:attachment/멀티코어 프로세서/multicore.jpg
파일:attachment/멀티코어 프로세서/dualcore.jpg
데카코어, 이론과 현실, 개판 흔한_듀얼코어.jpg[1]

파일:1520512018.gif
[2]

CPU 형태의 하나. 다이 하나에 코어 여러 개가 집적된 일반 CPU, 그리고 CPU를 두 개 이상 장착하는 경우를 의미한다. 물론, 현재에 이르러서 멀티코어 프로세서가 지칭하는 바는 대개 전자에 가깝다.

2016년까지만 해도 메인스트림 시장에서는 4코어가 대중화되어있었지만 2017년, AMD가 라이젠 CPU를 출시해 6코어, 8코어를 메인스트림 시장으로 내리면서 2017년부터는 6코어, 8코어가 대중화되어 있다.

비전공자를 위해 쉽게 쓴 멀티코어 프로세서.

2. 상세

2.1. 역사

싱글코어가 사라진 배경을 보면 멀티코어의 탄생 배경을 알 수 있다. 2000년대 초반, 한계치 이상까지 CPU의 클럭을 끌어올리던 CPU 제조회사들은 2002년에 3 GHz 클럭을 돌파하였다. 문제는 거기서 발생하는 발열, 엄청난 전력소모. 클럭을 올리고 코어의 면적을 넓히는 방식으로 성능향상을 꾀하는 것은 점점 한계를 드러내고 있었다. CPU의 성능이 해마다 기하급수적으로 증가한다고 해도 코어 하나가 처리할 수 있는 작업 속도는 분명히 한계가 있기 때문이다. 물론, CPU 제조회사들도 당연히 이 부분을 알고 있었다. 문제는 당시 기술력으로는 더 이상의 발전이 불가능에 가까울만큼 어려운 것이었고, 그래서 그들은 코어 하나를 극한으로 끌어올려서 성능 향상을 꾀하는 것 보다는 코어 수를 더 늘려서 좀 더 쉽게 CPU 전체의 성능 향상을 도모하는 쪽으로 발전하게 된 것이다.

요약하면, 코어의 개수를 늘리는 쪽으로 CPU가 발전하게 된 것은 폴락의 법칙에 따라 코어의 면적(트랜지스터 수) 증가만으로 성능 향상을 꾀하는 것이 당시 기술력으로는 이미 한계치에 가까웠기 때문이다.

이렇게하여 2005년 5월, 인텔 펜티엄D 시리즈AMD 애슬론 64 X2 시리즈를 필두로 개인용 컴퓨터 시장에 멀티코어 프로세서들이 본격적으로 보급되기 시작했다. 물론, 인텔과 AMD만 그랬던 건 아니라 IBM도 2005년 7월 7일에 POWER4 CPU기반의 일반 가정용 타겟 프로세서인 PowerPC 970MP를 뒤늦게 발표했고, 애플은 PowerPC 970MP를 채택하여 2005년 10월에 Power Mac G5 Late 2005를 내놓았다. 콘솔 게임기도 2005년 11월에 출시된 Xbox 360부터, 2011년 이후에는 스마트폰, 나아가 인터넷 공유기도 멀티코어 프로세서를 사용할 만큼 보편화되었다.

사실 서버나 워크스테이션 등 고성능이 필요한 곳에서는 이미 한참 전부터 메인보드+CPU 조합을 여러 개 설치하여 그룹으로 묶어 병렬처리를 통해 효율을 높이거나, 메인보드 하나에 CPU자체를 여러 개 설치하는 방식인 멀티 프로세서(멀티 CPU) 형태로 성능 향상을 도모했다. 또 멀티코어 프로세서 형태는 이미 2001년에도 있었다.[3] 단지 메인프레임 이상의 대규모 시스템용으로만 공급되어 보기 힘들었을 뿐이다.

하지만 멀티코어 프로세서는 단순히 프로세서를 두 개를 꽂는다고 두 배의 성능을 내는 게 아니다. 프로그램이 처리해야 하는 계산 작업 사이에서 여러 개의 프로세서가 맡아서 처리할 수 없어서 하나의 프로세서만 써야 하는 작업이 생기면 나머지 프로세서는 그 작업이 처리되는 동안 놀고먹는 모양새가 된다.이렇게 프로그램 내부에서 역할 분담(병렬화, Parallelization)이 되지 않는 부분이 많아지면 프로세서를 아무리 많이 때려박아도 성능 향상에 한계가 생긴다. 이를 전문 용어로 조별과제 암달의 법칙(Amdahl's Law)이라 한다. 듀얼코어 시절에는 배부른 소리처럼 들렸겠지만, 지금은 쿼드 코어를 넘어서 헥사/옥타 코어도 시중에 유통되어 있고, 병렬 처리가 생명인 GPU는 프로세서를 수백~수천개 단위로 투입하니 위 법칙이 더욱 체감으로 다가오는 때다. 다만 암달의 법칙 자체는 일반적으로는 훨씬 폭넓은 용어이다. 정확하게는 "시스템 부하의 A%를 차지하는 부분이 아무리 몇배로 개선되어봤자 결과적으로 최대로 얻을 수 있는 이득은 A% 이내일 뿐이다"는 아주 상식적인 소리에 불과하다. 이게 "암달의 법칙"으로 불릴 정도로 유명해진 이유는 (특히 병렬 컴퓨팅 분야에서) 이거 안 지키다가 폭망한 사례가 아주 많아서 그렇다.

이를 피하기 위한 기능으로 인텔 터보 부스트, 유사품 AMD의 터보 코어[4]처럼 놀고 있는 프로세서는 파워게이팅이라고 전력공급을 차단해 버리고 남는 여유분만큼 일하고 있는 코어를 자동으로 추가 클럭을 넣어주는 식으로 싱글코어만 써도 어느 정도 성능 향상이 있도록 했다. 전력 공급 및 발열냉각설계는 멀티코어 모두 풀로 쓰는 기준으로 만들어 놨기 때문에 노는 코어가 있으면 다른 코어가 전력을 더 써도 된다. 단, 오버클럭은 부스트 때문에 성능이 향상되는 이유에 대한 간단한 이해를 돕기 위한 비유일 뿐, 실제 부스트로 들어가는 클럭은 제조과정에서 기본적으로 세팅한 것이므로 오버클럭이 아니다. 그래봤자 기본 설정 클럭에서 10~20%정도 밖에 안 올라가는지라 근본적인 해결과는 거리가 멀다. 물론 없는 것보단 10~20%라도 챙기는 게 확실히 낫기 때문에 세대가 올라갈수록 이 기술도 발전해 왔다. 여기 4번째 댓글에서 설명하는 것처럼, 모든 코어를 다 쓰는 상황에서도 여유가 되면 부스트 클럭이 들어가거나 내장 GPU를 쓰지 않는 경우 거기서 나오는 전력/발열 여유를 CPU 부스트 클럭 유지에 돌리는 등등 조금이나마 추가적인 성능 향상을 계속 가져온다. 특히 노트북이나 저전력판의 경우 전력 제한에 맞추기 위해 기본 클럭이 매우 낮고 성능도 그만큼 낮은데, 부스트 클럭은 상대적으로 그렇게 낮지 않은 경우가 많아서 부스트 클럭을 통해 쾌적한 환경에서 작업이 가능한 경우가 많다. 모바일용 i3와 i5의 가장 두드러지는 차이가 이것으로, i3는 터보부스트가 없으나 i5는 있다. 하지만 저 정도 차이는 어디까지나 노트북용 CPU 사이에서 뒤에 보통 U가 붙는 저전력 모델 한정. 일반적인 노트북 CPU만 해도 기본 클럭이 높은 쪽이 터보부스트를 씹어먹을 정도의 차이가 날 수 있는 경우가 많기 때문에 클럭 높은 놈이 깡패다.

2.2. 멀티코어 프로세서를 제대로 활용하려면? : 멀티스레드 프로그래밍

멀티코어와 멀티스레드 용어를 설명하기에 앞서 멀티코어는 "하드웨어 관점"에서의 물리적 구성 단위, 멀티스레드/멀티스레딩은 "소프트웨어 관점"에서의 논리적 작업 처리 단위라는 차이점이 있다. 당장 멀리 갈 것도 없이 Windows 기준으로 작업 관리자를 열어 보면 실행 중인 프로그램(프로세스)들이 코어 단위가 아닌 스레드 단위로 취급하고 있다. 과거에 코어와 스레드를 같은 개념처럼 취급했던 것은 '코어 개수 = 스레드 개수'인 CPU들만 존재하던 시대였기 때문이다. 그리고 SMT를 경험하려면 멀티 CPU 시스템인 슈퍼컴퓨터나 메인프레임이 사용된 서버, 데이터 센터, 그나마 스케일이 가장 작은 고성능 워크스테이션 말고는 기회가 없었다.

2002년에 인텔이 구현한 하나의 코어에 양방향 SMT 구현체인 하이퍼스레딩부터 일반 소비자들에게도 SMT가 본격적으로 알려지기 시작했지만 적극적으로 활용한 소프트웨어가 전무에 가까웠고, 코어2 시리즈에서는 하이퍼스레딩이 일시적으로 빠진 모습으로 지속되어서 소비자들이 잊고 지내다가, 2008년 1세대 코어 i 시리즈부터 하이퍼스레딩이 다시 도입되면서 '코어 개수 = 스레드 개수'가 항상 성립되는 것이 아님을 일반 소비자들에게 확실히 각인 시켜주었다.

참고로 하나의 코어에 양방향 SMT는 인텔이 먼저 대중화한 것은 맞지만, 하드웨어가 어떤 형태이든 상관없이 SMT 개념 자체는 인텔이 처음 만든 것이 아니고 1960년대에 진행했던 IBM의 ACS 프로젝트를 통해 등장한 오래된 개념이다. 단지, 하이퍼스레딩 덕분에 싱글코어 싱글스레드 CPU만 존재했던 일반 가정용에서도 SMT를 경험할 수 있게 되었을 뿐이다. 그리고 2000년대 초중반에 특수 분야에서 이미 등장한 지금같은 CPU 하나에 코어 여러 개 탑재된 멀티코어 CPU 시스템이 2005년부터 일반 가정용에도 대중화되면서 하이퍼스레딩같은 기능을 굳이 지원하지 않아도 SMT를 경험할 수 있게 되었다. 따라서, 소프트웨어를 만드는 과정인 프로그래밍 관점에서는 코어 단위가 아닌 스레드 단위를 기준으로 취급한다.

"클럭 × IPC = 성능"인 싱글코어와 달리 캐시나 아키텍처의 기여도가 더 높아져서 클럭 × IPC가 스펙만큼 나타내진 못하는 바람에 더 높은 클럭임에도 성능이 오히려 낮은[5] 경우가 있어서 과거와 달리 클럭이 높다고 무조건 좋은 제품이 아니며, 일반유저가 좋은 제품을 고르는게 다소 애매해졌다. 그 대신 전체적으로 어떤 CPU를 선택해도 큰 불편 없이 사용할 수 있는 수준이 되었다.

결국 '코어 하나당 성능 * 코어 개수 * 멀티스레드 활용률'의 세가지 지수를 모두 보아야 CPU 성능을 어느정도 정확하게 가늠할 수 있다('코어 하나당 성능'은 다시 '클럭당 성능(IPC) * 클럭'으로 세분화 할 수 있다.). 펜티엄 20주년 에디션(G3258 AE)을 오버클럭해서 '코어 하나당 성능'을 높이면 i3-4150을 제치고 상당수 게임 성능에서 AMD FX 시리즈는 물론이고 인텔 코어 i7(블룸필드)까지 제치는 모습이 대표적. 하지만 '멀티스레딩 활용률'이 더 높은 게임(배틀필드 4 등)에서는 듀얼코어의 한계를 보이면서 뒤쳐진다. 물론 다른 게임들에서도 위 CPU들도 오버클럭을 하면 다시 상황이 역전되기도 하지만, 배틀필드 4에서는 '멀티스레딩 활용률' 때문에 그럴 필요조차 없이 뒤쳐진다는 것이 포인트.

네이티브 듀얼코어와 쿼드코어의 경우엔 이 방식이 아니고 그냥 다이 하나에 여러 코어를 올린 것보단 전력을 적게 먹으며, L2 캐시 공유 등의 기술을 탑재하고 나오기 때문에 성능이 좀 더 좋아지는 경향이 있으나, AMD 페넘 시리즈의 경우 코어 개개의 성능이 매우 떨어지는 관계로 듀얼코어 두개를 붙여 쿼드코어를 만든 인텔 코어2 쿼드에 처절하게 패배했다. 반면, 코어 개개의 성능이 좋은 편인 인텔 코어 i7(블룸필드)의 경우, 하이퍼스레딩까지 탑재하면서 AMD에게 넘사벽을 선물했다.

대표적인 성공작은 "AMD 애슬론64x2 시리즈", "AMD 옵테론 시리즈", "인텔 코어2 시리즈", "AMD RYZEN 시리즈"이다.

온라인 IT 매거진 PCBee에서 2007년 1월 코어2 쿼드의 런칭에 맞춰 쿼드지수 측정 웹페이지를 제공하기도 했다. 일종의 멀티 스레드 연산 테스트로 기본 클럭 Q6600의 성능을 100으로 치고 유저의 CPU 성능이 어디까지 나오는지를 측정해 준다. 당시에는 꽤 정직한 결과를 보여줘서 대략적인 CPU 성능을 가늠해 볼 수 있는 훌륭한 지표였지만, 시간이 지나 웹 브라우저에서 자바스크립트 엔진 성능에 신경쓰게 되면서 같은 스크립트라고 해도 IE 6 시절보다 몇 배는 빠르게 실행시킬 수 있게 되어 멀쩡한 수치가 나오지 않게 되었다. 같은 노오버 Q6600이라고 해도 IE 9에서 쿼드지수를 측정하면 300점 가량 나온다고 하므로 당시 기준의 점수로 환산하려면 대략 1/3 정도로 계산해주면 될 듯 하다. 물론 IE 역시 11 버전까지 업그레이드되고 크롬 등의 다른 웹 브라우저라면 같은 환경에서 더 높은 점수가 나올 수도 있다. 코어 i5 쿼드코어 제품군을 4GHz 정도까지만 오버해도 600이나 700 같은 정신나간 수치가 나오게 되었고, 2700X+크롬 조합으로 1700점은 그냥 나온다. 덕분에 성능이 아득히 올라가 버린 시스템들의 점수로 인해 TOP 10 그래프는 와장창 깨져 있다. 게다가 AMD RYZEN 시리즈의 득세로 주력 CPU가 헥사코어~옥타코어로 올라가 버려서 해당 사이트의 "쿼드코어를 넘는 것은 쿼드코어 뿐이다" 문구가 무색해진 지 오래.

x86 호환 CPU의 경우 AMD RYZEN 시리즈64코어 128스레드인 스레드리퍼 3990X는 $3,990, 인텔의 18코어 36스레드인 코어-X 시리즈의 i9-10980XE는 $1,000이다. AMD FX 시리즈의 8000 시리즈와 9000시리즈는 8코어 8스레드이며 AMD RYZEN 시리즈의 라이젠 7은 8코어 16스레드이다. FX-8xxx의 경우 네이티브 여부가 이견이 갈린다. 2코어 1모듈이라 실질적으로는 4코어라고 해야 한다며 소송을 당하기도 했다. 서버용으로는 인텔 제온 스케일러블 시리즈 중 최상위 플래티넘 시리즈랑 제온 W-시리즈 중 최상위 라인은 28코어 56스레드를, AMD EPYC에서는 64코어 128스레드까지 출시되어 있다. 이 소켓을 2개 끼운다고 생각해 보자.

그 외에 모바일 ARM 계열로는 퀄컴 스냅드래곤엑시노스 등 여러 종류가 있다. 아키텍처가 달라서 당연히 x86 호환이 안 된다.

2017년 하반기 이후 AMD의 라이젠이 늘어난 코어 수와 함께 대성공하면서 위기의식을 느낀 인텔도 그에 따라 코어 수를 올리기 시작하여 멀티코어의 기준이 4코어에서 6~8코어로 많이 올랐다. 라이젠 이전에는 예전부터 i7마저도 4코어로 유지되었지만 라이젠 이후에는 i5도 6코어로 늘어났으며, 2018년 10월부터는 코어 i9가 일반 데스크탑용 라인에도 나오면서 8코어로 증가되었다. 최고사양을 요구하는 AAA 게임쪽도 이젠 8코어 기준으로 제작하거니와 테스트에 의하면 8코어를 다 쓰면서 CPU 사용률이 4코어에 비해 많이 낮다는 점이다. 당장 엑스박스 원플레이스테이션 4 둘 다 저전력, 저클럭이지만 엄연히 8코어 8스레드 CPU다. 이것 역시 AMD의 작품. 전문 소프트웨어는 이미 오래전부터 멀티스레드에 큰 영향을 받으므로 별 상관없지만 소프트웨어 시장이 큰 변화가 오고 있다는 것. 덕분에 어도비처럼 멀티코어 프로세서를 위한 멀티스레딩 지원 및 패치를 게을리하거나 안 하는 회사들이 점점 욕 얻어먹기 시작하고 있다. 다행히도 어도비 라이트룸처럼 스레드 12개까진 제대로 지원해주는 업데이트가 나온 상태지만 여전히 한계가 존재하고 있다. 이건 소프트웨어를 다시 만들지 않는 이상 힘들 수 밖에 없다.

멀티스레딩을 지원하지 않는 프로그램이라도 멀티코어 프로세서 환경(+OS)에서 어느 정도 성능 향상을 얻을 수 있다. OS에선 자신이 프로그램을 실행하지 않아도 기본적으로 OS에서 알아서 관리하는 수많은 시스템 프로그램이 실행되고 있다. Windows 기준으로 작업 관리자의 프로세스 탭에 몇 개의 프로세스가 있는지 세어 보자. 멀티스레딩을 지원하지 않는 프로그램과 기본적으로 실행되고 있는 프로그램을 다른 스레드로 나눠서 처리하면 성능 상의 이득을 얻을 수 있는 것이다. 코어 한 개 범위 내에서 빨라지는 거긴 하지만 그게 어딘가. 단 그게 최신 게임에서 일어나는 일이라면 확실히 문제일 수도 있다. Python으로 개발된 EVE 온라인 같은 경우인데, Python의 특성 상 단일 동작은 반드시 싱글스레드에서 수행되어야 하기 때문에 위와 같은 방식으로 멀티스레딩에 최적화되어 있고, 과부하가 걸리면 이것도 한계가 오게 된다.

게임용 3D 그래픽 API의 대표격인 DirectX의 Direct3D도 비슷한 문제를 겪고 있다. Direct3D 10 세대까지는 API 구조가 렌더링이 싱글스레드에서 동작하는 것을 상정하고 만들었기 때문에 멀티코어를 사용하기 힘들었다. Direct3D 11부터 Deferred Context가 추가되어 멀티 스레드로 렌더링이 가능해 졌으나, 실제 렌더링 명령은 Immediate Context에서 진행 되기 때문에 전체적인 효율이 아쉬웠는데, Direct3D 12부터 유저 드라이버 모드에도 멀티스레딩을 지원하면서 하드웨어 직접 접근을 지원하면서 전체적인 효율이 개선되었다. Direct3D 12의 발표 자료를 보면, Direct3D 11은 쿼드코어에서 돌릴 경우 첫 번째 스레드(스레드 0)가 다른 스레드보다 오래 걸리는 바람에 그만큼 나머지 3개 스레드들이 놀게 된다. 반면 Direct3D 12는 해당 부분도 4개의 스레드에서 나눠 처리하게 하거나, 아예 해당되는 처리 자체를 줄여서 멀티스레딩의 효율과 속도를 높였다. 관련 문서를 보면 알겠지만 OpenGL도 마찬가지라서 Vulkan을 만들었다. 사실 마이크로소프트는 Vulkan이 핫해지자 마지못해 같은 개념을 적용한 DirectX 12를 내놓았다는 말을 많이 듣는데, 실제로 Vulkan과 DX12 둘 다, 기존 버전에 비해 사용하기 위한 지식과 난이도가 급상승한 데 반해 성능 향상은 잘 알고 쓰지 않으면 미미하거나 오히려 마이너스가 되기 십상이기 때문.
Microsoft DirectX Blog 에 올라온 DirectX 12 정보[6]
파일:attachment/멀티코어 프로세서/Example.jpg
실전에선 Direct3D 12로 구현한다고 항상 위의 그래프대로 뽑을 수 있는 것은 아니다[7]. 베스트 케이스 기반 동작 원리 설명 정도로만 참고할 것.

따라서 CPU에 박힌 코어 여러 개의 성능을 제대로 끌어내려면 여러 개의 코어에게 일거리를 효율적으로 배분하도록 프로그램을 멀티스레딩 구조로 짜 줘야 한다. 멀티스레딩에 최적화가 되어있지 않은 프로그램은 CPU 처리량이 더 필요해도 다른 코어의 도움을 받지 못하고 1번 코어에서만 비비적대며 돌아가거나, 심지어는 일감을 달라고 저희들끼리 싸우는 동안 실행 속도는 오히려 더 떨어져 버리는 참사가 벌어질 수 있다. 스레드를 만들거나 끝내는 것 자체도 CPU의 일을 추가하는 것이기 때문에, 어설프게 갯수만 늘리면 배달차량을 늘리겠답시고 덤볐다가 옥천허브만 창조하는 꼴이 된다. 파이썬 인터프리터가 한 때 이 문제 때문에 까인 적이 있다. 따라서 실행 성능이 중요시되는 프로그램, 특히 게임은 처음 프로그램을 짤 때부터 멀티코어 프로세서를 생각해야 되는 시대가 되었다.

하지만 멀티스레딩을 이용한 병렬 프로그래밍 자체의 어려움과 직렬화에 가까운 게임 프로그래밍의 특성 상 게임은 멀티코어 프로세서가 대중화된 시대임에도 많은 수의 게임들이 동서양을 가리지 않고 멀티코어를 제대로 활용하는 모습을 보기 어렵다. 이는 딱히 기술력이나 돈의 문제 이전에 병렬화로 성능 향상을 꾀할 수 있는 부분이 게임에서 극히 적을 뿐더러, 적용한다고 해도 성능 향상이 없거나 오히려 더 성능이 내려가기 때문이다. 싱글스레딩의 한계를 극복하기 위해 돌리는 시간이 짧은 시뮬레이션은 그냥 싱글스레드용으로 짠 다음에 시간이 긴 구간은 스크립트를 써서 스레드 여러 개를 동시에 돌리는 식의 기법도 사용되고 있으나 효율은 생각보다 좋지 않다.

병렬화 하드웨어 및 소프트웨어 아키텍처의 발달로 인하여 가장 수혜를 본 분야인 비즈니스 솔루션의 경우, 비동기적(Asynchronous) 실행을 지원함으로써 처리량을 비약적으로 향상시키는 것이 가능했다[8]. 예를 들어, 웹으로 접속하는 어느 서비스 (웹 사이트나 온라인 정보요청 기능 등)을 생각하자. 각각의 사용자는 서버 컴퓨터에 요청사항이 담긴 통신을 날리고, 서버 프로그램은 네트워크로 들어온 각각의 데이터를 보고 그에 맞게 데이터를 만들어(예를 들어 웹사이트의 html 파일) 되돌려 보낸다. 이 경우, 서버 프로그램은 주문을 받고-처리하고-결과물을 돌려보내는 한 단위로 깔끔하게 작업을 쪼갤 수 있으며, 처리한 작업의 이후 결과를 추적한다거나 처리 결과끼리의 연관성에 따라 특정 다른 처리작업의 순서혹은 내용이 변한다거나 하는 '얽힘' 이 존재하지 않는다. 그래서 데이터가 들어오는 대로 병렬로 작업을 처리하도록 흐름을 확산시키면 과거 방식의 수 배 내지는 수십 배 이상의 서버 처리량을 달성하는 것이 가능했다.

반면 게임은 실시간으로 모든 요소들이 정확히 동시에, 개발자가 의도한 순서대로 플레이어에게 보여져야 하는 프로그램이다. 코어별로 따로 나눠 작업 돌려서 작업에 차이가 발생하면 플레이어 캐릭터는 등장하지만 NPC 1은 아직 연산이 안되었다고 안 나오고 화면은 나오는데 소리는 안 나오는 이런 상황 만들 수는 없어서 병렬화가 어렵다. 지금도 일부 AAA 게임들만이 4스레드 이상을 지원하는 형편이며, 대다수 게임들은 멀티스레딩을 지원한다 해도 별 의미 없는 경우가 대부분이다.

물론 아예 다른 기능별로 나누는 것은 가능해서 가령 물리연산만 따로 빼서 돌린다던가 하면 싱글스레드만 지원하는 게임보다는 낫겠지만 그런 경우도 물리연산 자체는 스레드 1개만 갈구게 되어 한계가 생기며, 게임 루프 자체의 기본적인 순서는 유지되어야 하므로(모든 유닛의 이동위치 계산이 끝나야 물리연산이나 사정거리 계산을 위한 좌표를 알 수 있다거나, 피격 처리에 의한 HP 계산이 끝나야 특수효과나 능력 발동을 위한 현재 빈사상태 판단을 할 수 있다거나, 해당 프레임의 업데이트가 먼저 이루어져야 해당 프레임에 대응되는 렌더링을 수행할 수 있으니까) 무작정 요소별로 스레드를 뽑아서 돌리면 렌더링은 다 되었는데 업데이트가 아직 안 되어서 버벅거리는 현상이 발생할 수 있다. 이것이 2000년대 중반부터 2010년대 초반까지의 멀티스레딩 지원 게임들로부터 드러난 문제점이었다.

게다가 이 각 요소들이 서로 관계를 맺으면 더욱 더 골치아파진다. 플레이어 캐릭터와 NPC와 아이템이 각각 다른 스레드에서 돌아가고 있다고 가정할 때, 플레이어가 NPC에게 아이템을 주는 장면은 어느 스레드가 맡아야 하는가? 어느 스레드가 맡는다 치면 다른 스레드는 그 결과가 나올 때까지 멀뚱히 기다려야 하는가? 하는 식의 문제이다. 다른 셋이서 협동해서 진행하면 이상적이겠지만 이들간에 약간의 시간차만 나도 플레이어는 아이템을 줬는데 NPC는 못 받았고 아이템은 엉뚱한 데 가버리는 심각한 문제가 발생하게 된다.[9] 게다가 이건 하이젠버그로 나타날 가능성이 높다. 저런 버그는 시간차가 나지 않으면 생기지 않는 버그니까. http://m.dcinside.com/board/rlike/321084 이런 상황을 프로그래머가 전부 예측하는 것은 불가능에 가깝다. 다른 것 보다도 이거 때문에 지원이 어려우며, 특히 이는 싱글스레드 프로그램을 멀티스레드 기반으로 옮기기 아주 힘들게 하는 장벽으로 작용한다. 차라리 새로 짜는게 낫다는 평가가 나올 정도.

우회적인 방법으로, 과거처럼 렌더가 완료되고 게임 로직을 차례대로 돌리는것이 아니고 렌더 스레드와 로직 스레드를 나눈 후 로직 스레드에서 스레드 풀을 구현 하여 렌더에서 사용되는 CPU자원 사용을 줄이고 로직의 불규칙한 처리를 대비해 몇 프레임을 미리 대충 추측해서 렌더링 하는 기법도 있다.[10]

결과적으로 각 코어의 연산 능력도 뛰어나야 하며, 이 코어간 & 스레드간의 데이터 연계 능력이 뛰어나야 좋은 멀티스레딩이 된다.

구식 멀티스레딩의 대표적인 예 중 하나인 스타크래프트 2는 모든 물량을 죄다 CPU로 처리하는 데 고작 스레드 2개까지만 지원한다. 일반전에서는 문제가 없지만 물량이 쏟아져 나오는 협동전에선 고클럭 CPU가 아닌 이상 렉걸린다. 고클럭 CPU도 일부 사령관 조합에서는 버티기 힘든 렉이 걸린다.[11] 처음부터 2스레드 기반으로 설계한 것이 큰 잘못이다. 다른 예론 어도비 계열 소프트웨어들. 산업 표준이라는 말이 나올 정도로 여러 분야에서 압도적으로 많이 쓰이는 프로그램에 멀티스레딩을 아예 지원하지 않는 것은 아니지만 최적화가 정말로 좋지 않고 전문가용 소프트웨어답지 않게 싱글스레드(고클럭 및 높은 IPC) 성능에 의지하고 있다. 이 때문에 싱글스레드 성능이 우수한 일반 데스크탑용 CPU가 현존 8코어가 최다 코어라서 그 이상으로 아무리 코어 개수가 많아봤자 일반 데스크탑용보다 많은 코어 수의 구성을 위해 레이턴시가 늘어져 싱글스레드 성능이 떨어질 수밖에 없는 HEDT/워크스테이션/서버용 CPU는 의미가 없을 정도. 물론 멀티스레딩에 제대로 최적화된 기능은 싱글스레드 성능이 낮더라도 코어 개수만큼 제대로 성능을 내 준다.

2019년 기준으로 테스트한 결과, 최신 게임들은 멀티스레딩을 제대로 지원하고 있다. 이미 2017년부터 스레드 4개는 이젠 더 이상 쓰기 힘들정도로 요구 스펙이 높아졌으며 게임에 따라 스레드 8개에서 최대 16개까지 지원하는 상태다. 평균 프레임만 봐도 6코어 6스레드와 8코어 8스레드간 20 FPS씩이나 차이는 게임도 있으므로 확실히 최신 게임들은 8코어 8스레드 혹은 그 이상을 기준으로 개발되고 있는 셈이다. 물론 최적화나 기타등등까지 따져봐야하므로 성능차가 생길 수 있다. 게임+방송까지 해야한다면 스레드 16개인 CPU나 아예 방송용 컴퓨터를 조립해야할 정도로 요구스펙이 굉장히 높으므로 게임이라도 코어 개수가 많으면 좋을 수 밖에 없는 상황인데 이게 무려 FHD 기준이다. 4K는 말그대로 포기하는 게 좋을정도. 다행히 실시간 인코딩만큼은 CPU가 아닌 그래픽카드에게 전담할 수 있는 있기 때문에 최신 그래픽카드가 있다면 CPU의 요구 사양을 어느 정도 낮춰 실시간 4K 인코딩이 가능해졌다.

이러한 결과는 최신 게임에서는 위에서 언급된 것과는 아예 다른 구조로 처음부터 프로그램을 제작하기 때문이다. 과거에는 싱글코어로 처리하는 프로그램을 뜯어고치려고 해도 데이터 간의 얽힘을 해결하기 어려우니 일단 기능적으로 따로따로 가능한 것들을 분해하자는 식이었고, 그래서 메인 스레드 - 렌더링 스레드 - 물리계산 스레드 - 사운드 스레드 같은 식으로 존재하는 기능의 갯수 정도나 나누는 것이 한계였던 반면, 현대의 최신 게임 아키텍처는 기본적으로 모든 처리를 하나의 흐름에서 흘러가는 것을 전제로 한 채, 데이터 구조와 계산 로직 작성 방법을 연구해서 '1000개의 유닛에 대한 연산을 1000개 작업으로 쪼갤 수 있는 표현법'을 창조하는 데 힘을 쏟았다. 그 결과, 게임 로직의 처리를 커다란 반복작업(굵은 쇠사슬) 대신 자잘하지만 무수한 병렬작업인 하나하나를 연결해 가는(새끼줄) 방식으로 표현할 수 있게 되었다.

이렇게 하면 32코어를 사용하든 128코어를 사용하든, 거의 무조건 작업의 개수가 CPU가 지원하는 스레드 수보다 많게 만드는 것이 가능하기 때문에, 1스레드 당 지푸라기 100가닥씩 처리하느냐, 10가닥씩 처리하느냐 하는 식으로 할당하는 개수만 다르게 하여 항상 최대한의 CPU 스레드에게 일을 시킬 수 있다. (물론, 이런 성과를 얻기 위해서는, 위에서도 언급했듯이 게임의 설계 단계부터 데이터 구조와 처리 로직이 분산처리에 적합하도록 고려해 가며 만들어야 한다.)

2.3. 어떤 식으로 구현하는가? : 멀티스레드 프로그래밍 패턴

프로그래밍에서도 멀티 프로세서나 멀티코어로 인한 성능을 온전히 활용하기 위해 몇 가지의 코드 패턴이 연구되었다. 이해를 돕기 위한 예시를 들어보겠다.
이미 완성된 프로그램이 하나 있다. 해당 프로그램은 이미지를 입력받으면 전체의 픽셀을 반복문으로 순회하며 해당 픽셀의 RGB값을 각각 5씩 낮추는 프로그램이다. 그러나 이 프로그램은 스레드를 하나만 쓰는 싱글 스레드 프로그램이다. 이 프로그램을 멀티코어를 사용하도록 바꾸려면 어떻게 해야 할까?

2.3.1. 공유 메모리 모델

모든 코어/스레드가 하나의 메모리 공간을 공유하는 모델이다. 하나의 코어가 메모리에 쓰기 작업을 하려고 하면 먼저 해당 메모리 공간이 쓰기 가능한지(다른 스레드가 이미 작업 중인지)를 알아보고, 만약 사용 가능하다면 해당 메모리 영역에 잠금(lock)을 걸고 쓰기를 한다. 쓰기 작업이 완료되면 잠금을 해제하여 다른 스레드가 사용 가능하게 한다.

위의 예시로 들자면 잠금을 이미지에 걸고, 픽셀의 값을 읽고 쓰기 전까지 다른 스레드가 픽셀을 건드리지 못 하도록 막는 방법이다. 단순히 잠금장치만 추가하고 해당 일을 하는 스레드를 많이 추가하면 되기에 이미 싱글스레드로 구현된 코드를 멀티스레드로 변환하기 쉽다는 장점이 있으나, 잠금 매커니즘이 관리가 까다롭고 성능 병목이 발생한다는 단점이 있다. 예를 들어 어떤 스레드가 잠금을 획득한 상태로 죽어버리거나(데드락), 두 개의 스레드가 경쟁적으로 잠금을 획득하려고 한다거나(레이스 컨디션), 서로 상대방의 스레드가 '잠가 놓은' 리소스를 획득하기 위해 무한히 대기하는 경우(스타베이션)가 발생할 수 있다. 또한 잠금을 확인하는 시점에서 모든 스레드가 동기화되어야 하기 때문에 가장 느린 스레드의 속도에 다른 모든 스레드의 속도가 맞춰져 버리는 단점이 있다.

만약에 스레드간 공유되는 자원이 아예 없다면 락 없이 빠른 병렬성을 보장한다. 거대한 배열에 관한 작업들은 CPU 캐싱이 잘 되게 짤 수 있어서 더욱 그렇다. 위의 이미지 예시를 들어보자면 이미지 자체를 하나의 리소스로 보지 말고, 행 하나하나를 리소스로 보고 스레드 개수로 분할할 수도 있을 것이다. 물론 사양표나 테스트를 통해 해당 작업이 Thread-safe인지 반드시 확인해야 한다. 만약 800x600인 이미지를 4개의 스레드로 쪼갠다면 각 스레드가 800x150의 영역을 담당하여 스레드 0이 0~150번째 행, 스레드 1이 150~300을 담당하는 식으로 서로간의 간섭(혹은 메시지 통신) 없이 메모리의 독립적인 부분에 대한 처리를 하게 된다. 이렇게 분할해서 가져가면 스레드가 가져간 이미지 조각들도 결국 연속된 배열이기 때문에 CPU 캐시 미스 거의 없이 빠르게 처리된다.

이러한 연산에 아래 항목 같은 메시지 전달 작업 모델을 이용했다간 꽤 느려질 위험성을 내포한다. 첫 번째 이유는 메시지 큐(통신 채널)를 사용하는 오버헤드이다. 현용 메시지 큐는 락 없이 최대한 빠르게 동작하도록 설계되긴 하지만 어쨌든 큐에 일감을 넣고 빼는 작업 자체도 CPU 클락이 소모된다. 실제 작업 자체가 간단한 수식 작업일 수록 큐 작업의 오버헤드의 비율이 커져서 비효율적이게 된다. 두 번째 이유는 각 스레드는 메시지 큐에서 일감을 메모리 영역에 대한 일관성이 없이 가져가기 때문에 CPU의 캐시 미스가 더 많이 일어나서 느릴 수 있다는 것. 따라서 벡터곱, 행렬곱, 텐서곱과 같은 균일한 배열에 대한 연산의 병렬화 모델은 메모리 공유 모델을 사용한다.

GPU는 공유 메모리 모델을 사용한다. 위에서 언급한 잠금 관리의 '까다로운' 부분은 하드웨어와 드라이버(런타임 라이브러리)에서 어느 정도 관리해주기 때문에 CPU보다는 편하게 병렬 프로그램을 작성할 수 있다. 마찬가지로, 최선의 성능을 요구하는 시뮬레이션이나 최신 게임 아키텍처에서는 이 방법으로 성능을 최적화한다.

결과적으로, 데이터를 구조화하거나 처리하는 루틴을 만들 때부터 하드웨어적인 구조를 고려해야 하고, 순수하게 추상적으로만 접근할 수 없어 미적으로는 떨어지지만 그만큼 하드웨어에게 기대할 수 있는 효율성을 더 높게 뽑아낼 수 있는 방식이다. 그 대신 같은 공간에 대한 접근을 터놓기 때문에 아래와는 달리 항상 데이터 오염이나 스레드 예외로 인한 크래쉬, 순차 실행 버그 같은 재현하기도 어렵고 찾기도 어려운 버그의 위험성을 감수해야 하기도 하다.

2.3.2. 메시지 전달 모델(생산자-소비자 패턴)

위의 공유 메모리 모델과 달리 모든 작업 스레드(워커 스레드)가 완전히 격리된 메모리 공간을 할당받는다. 스레드간 데이터 교환은 통신 채널을 통해 서로 메시지를 교환함으로써 이루어진다.

통신 채널은 비동기로 동작하며 워커 스레드는 자신이 메시지를 받을 준비가 되었을 때에 자신의 메일박스(또는 메시지 큐라고 하기도 한다)에 들어온 메시지를 순서대로 읽어 처리한다. 공유하는 메모리가 없기 때문에 잠금 매커니즘을 사용하지 않으며 비동기이기 때문에 빠른 스레드는 느린 스레드의 작업 완료를 기다릴 필요가 없다. 수신자의 메일박스가 가득차 더 이상의 메시지 수신이 불가능할 경우는 예외. 이 경우에는 수신자의 메일박스에 빈 자리가 생길 때까지 송신자 스레드가 대기하거나 또는 메시지를 폐기한다.

위의 예시로 들자면 입력 스레드가 이미지에서 값을 읽어서 5를 빼는 워커 스레드(이 때는 '워커 스레드'가 소비자)에 던져주고, 워커 스레드는 자신의 결과값을 출력 스레드로 던진다(이 때는 '워커 스레드'가 생산자). 이 때 전달하는 메시지에는 픽셀의 x, y 좌표와 픽셀의 현재 값 c 세 개의 숫자값이 포함돼 있어야 한다. 공유 메모리 모델에서는 좌표값이 필요없으나(메모리 주소 자체가 좌표값 역할을 한다) 메시지 전달 모델에서는 어떤 스레드가 작업을 먼저 끝낼지 모르기 때문에 위치와 색상값이 모두 필요하다. 출력 스레드는 워커 스레드가 던진 x, y, c 메시지(여기서 c는 처리가 끝난 즉 5를 뺀 값)를 읽어서 자신의 메모리에 최종 결과를 쓴다.

위에서 보는 바와 같이 메시지 전달 모델에서는 입력, 워커, 출력 스레드가 각자 격리된 메모리 공간을 소유하므로 메모리의 공간적 부담이 늘어나는 단점이 있다. 워커 스레드의 '메모리'는 보통 CPU의 내부 캐시 메모리에서 처리되기에 충분할 정도로 작기 때문에 메모리 통신 대역폭 계산시 보통 무시되는 편이다.

공유하는 메모리가 없으므로 메시지는 CPU 내부 코어간은 물론이고 인접 소켓의 CPU나 네트워크를 통해 다른 컴퓨터의 CPU에까지 무리 없이 전달할 수 있어서 규모 확장이 쉽다.

특성 상 각자 스레드가 자신이 낼 수 있는 최고 속도로 동작할 수 있고(생산자 스레드는 값을 읽어서 던져주기만 하면 끝, 소비자 스레드는 변환해서 다시 던져주기만 하면 끝) 프로세서가 동등한 관계가 아닐 경우에도 유용하게 쓰일 수 있으나(CPU-저장장치간 통신인 파일 저장 코드, CPU-네트워크간 통신인 네트워크 연결 코드 등등) 기존에 구현된 코드를 변환하기에 손이 많이 가고, 위에서 언급했다시피 메모리를 일관성 없이 참조해 CPU 캐시 적중률이 수직 하락하는 단점이 있다. 이렇게 되면 구조적으로 작업이 분배되는 모습은 이상적이지만 정작 CPU에서 단위 작업을 처리하는 퍼포먼스가 최악의 경우에 가깝게 하향 평준화된다.

실행 주체 하나하나가 독자적으로 동작하는 함수형 언어가 병렬 프로그래밍을 잘 지원하는 방식이기도 하다.

2.4. 구현하려면 무엇이 필요하는가? : 지원하는 프로그래밍 언어와 라이브러리

멀티 코어를 이용하는 가장 기초적인 방법은 운영체제가 지원하는 스레드 생성 API를 이용해서 스레드를 생성하고, 일감 분배, 데이터 분산, 처리 및 결과값 도출을 직접 짜는 것이다. 스레드를 각 코어에 올려서 실행시켜주는 것은 운영체제의 몫이며 프로그래머의 역할은 데이터를 각 스레드별로 적절하게 분배해서 싣는 것이다. Unix 환경에서는 POSIX 스레드에서 따온 Pthread라는 멀티스레드 API 중 pthread_create 를 이용하여 스레드를 만들 수 있고, Windows 환경에서는 CreateThread 또는 _beginthread 를 이용한다.

이것은 순수하게 스레드를 만들고 스레드에 일을 지정하는 역할만 하므로, 위에 나와 있는 것과 같은 작업 분배나 스레드 간의 협조 같은 수많은 작업은 온전히 프로그래머의 몫이 된다.

스레드 생성과 관리와 동기화 구현을 컴파일러가 생성하도록 하고 병렬 처리에만 집중하고 싶다면, 다시 말해서 좀 더 쉽게 구현하고 싶다면 OpenMP ARB의 OpenMP나 인텔의 스레드 빌딩 블록(TBB: Thread Building Block), MS의 병렬 패턴 라이브러리(PPL: Parallel Pattern Library) 등을 사용할 수 있다. 기존 C/C++ 문법에 directive 같은 간단한 코드를 추가해서 어떤 루프를 병렬화 할지를 알려주기만 해도 쉽게 병렬화를 할 수 있다. 물론 동기화를 어느 곳에서 해야 하는지 알려 줘야 하며, 사용할 수 있는 범위가 제한되는 제약 조건을 유의해야 한다.

Java, Python, C# 같은 더 고레벨 언어의 추상화된 모델을 사용한다면 각 언어가 지원하는 멀티스레딩, 멀티프로세싱 라이브러리를 사용해야 한다. 가령 파이썬 같은 경우 multiprocessing 모듈의 Process와 Queue를 사용해서 메시지 전달 패러다임을 구현할 수 있다. 만약 배열에 대한 map 연산을 각 코어에 싣고 싶다면 multiprocessing 모듈의 Pool 객체의 map 메서드를 사용하면 잔 코딩 없이도 쉽게 작업을 분배할 수 있다. 자바에서는 병렬 스트림을 구현하는 메소드인 parallel()이나 parallelStream() 등이 있으며, C#에서는 Task에서 비동기 프로그래밍을 지원하며, TPL의 Parallel 클래스를 통해 단위 작업만 지정해 주면 자동으로 최적의 스레드 숫자를 생성하여 작업배분을 해 준다.

C, C++도 C11, C++11 표준부터 굳이 외부 라이브러리를 이용하지 않고도 표준 라이브러리를 통해 멀티스레딩을 구현할 수 있게 되었다. 단, 프로그래머가 병렬 프로그래밍 모델을 직접 수동으로 짜야 하는 단점이 있었으나 C++17부터 일부 표준 라이브러리의 알고리즘 함수들에서 병렬화를 지원하면서 C++에서도 병렬 처리를 어느 정도 간편하게 구현할 수 있게 되었다.
다만 C11, C++11에 포함된 스레드는 생성, 종료와 같은 아주 기본적인 기능만 제공하고 있으므로 Thread Affinity 와 같은 더 세밀한 컨트롤을 위해서는 Win32Thread나 POSIX Threads를 사용하여야 한다.

2.5. 멀티코어 프로세서의 종류

2.5.1. 멀티코어 CPU


각각 일반 데스크톱 CPU 항목의 개수는 코어(C)와 스레드(T) 개수이다.

||<|2> 인텔 CPU ||<|2> 연도 ||<-4> 코어 i 시리즈 ||<|2> 펜티엄 골드 시리즈 ||<|2> 셀러론 시리즈 ||
코어 i9 코어 i7 코어 i5 코어 i3
1세대 2009 - 4C 8T 4C 4T - -
2010 - 2C 4T 2C 4T 2C 2T
2세대 2011 4C 8T 4C 4T 2C 4T 2C 2T
3세대 2012
4세대 2013
5세대 2015 - -
6세대 2015 2C 4T 2C 2T 2C 2T
7세대 2017 2C 4T
8세대 2017 6C 12T 6C 6T 4C 4T 2C 4T
9세대 2018 8C 16T 8C 8T 6C 6T
10세대 2020 10C 20T 8C 16T 6C 12T 4C 8T
11세대 2021 8C 16T 8C 16T 6C 12T - -
12세대 2021 16C 24T 12C 20T 10C 16T[12]
6C 12T[13]
4C 8T 2C 4T 2C 2T
13세대 2022 24C 32T 16C 24T 14C 20T[14]
10C 16T[15]
4C 8T -
14세대 2023 20C 28T


||<|2> 인텔 CPU ||<|2> 연도 ||<-2> 코어 X-시리즈 ||
코어 i9 코어 i7
블룸필드 2008 - 4C 8T
걸프타운 2010 6C 12T
샌디브리지 E 2011
아이비브리지 E 2013
하스웰 E 2014 8C 16T
브로드웰 E 2016 10C 20T
스카이레이크 X 2017 18C 36T 8C 16T
캐스케이드 레이크 X[16] 2019 -



||<|2> AMD CPU ||<|2> 연도 ||<-4> 라이젠 시리즈 ||<|2> 애슬론 시리즈 ||
라이젠 9 라이젠 7 라이젠 5 라이젠 3
1000 시리즈 2017 - 8C 16T 6C 12T
4C 8T
4C 4T 2C 4T
2000 시리즈 2018
3000 시리즈 2019 16C 32T[17]
12C 24T[18]
6C 12T
6C 6T
4C 8T -
5000 시리즈 2020 6C 12T -
7000 시리즈 2022
8000 시리즈 2024 - 6C 12T 4C 8T


|| AMD CPU || 연도 || 라이젠 스레드리퍼 시리즈 ||
1세대 2017 16C 32T
2세대 2018 32C 64T
3세대 2019 64C 128T
4세대 2022
5세대 2023 96C 192T[19]


데카코어까지는 라틴어/그리스어 듀얼코어, 쿼드코어, 옥타코어 식으로 잘 부르지만, 10을 넘어가는 라틴어/그리스어 어근은 영미권에서도 거의 사용하지 않기 때문에 그냥 숫자로 부르는 사람이 더 많다. 예를 들어 16코어는 '헥사데카코어'보다는 '식스틴 코어'라고 부른다. 한국어로 쳤을 때 열, 스물, 서른, ... 일흔, 여든, 아흔 다음에 '백'이라 읽지 '온'이라고 읽지 않는 것과 비슷한 경우다

2.5.2. 멀티코어 GPU

GPU라는 용어가 등장하기 이전부터 RGBA 4가지 채널을 병렬로 대응할 수 있는 SISD 연산 구조의 픽셀 파이프라인이 정립된 상태였고, 1998년 NVIDIARIVA TNT, ATI의 RAGE 128부터 픽셀 파이프라인 자체가 2개가 되어 일종의 멀티코어 형태로 존재했다.

1999년 10월에 출시된 지포스 256부터 조명과 좌표 변환 처리(하드웨어 T&L), 2000년 4월에 출시된 라데온 DDR부터 절단(Clipping) 기능까지 추가된 하드웨어 TCL을 수행하기 위해 폴리곤을 생성할 수 있는 벡터(4-way SIMD) 연산 구조의 버텍스 파이프라인이 추가되면서 그래픽 카드의 프로세서를 GPU라고 부르기 시작했다. 하지만 프로그래머가 제어할 수 없는 영역이라 응용력을 발휘하는데 한계가 있었다.

2001년 지포스 3, 라데온 8500부터 셰이더 프로그래밍이 가능해지고, 2002년 7월에 출시된 라데온 9700부터 표준화된 셰이딩 프로그래밍 언어, 더 높은 정밀도의 부동소수점 실수 연산 지원, 하나의 명령어에 4D 벡터가 아닌 3D 벡터 + 1D 스칼라, 2D 벡터 + 2D 스칼라같은 하이브리드 방식이 도입된 부분적인 MIMD 연산을 지원하면서 연산 효율을 개선해왔지만 이 역시 한계에 봉착했다.

여기까지는 연산 유닛들이 일정한 개수만큼 뭉쳐진 파이프라인 단위로 사용되었다. 구조적으로 보면 CPU 내부 코어도 여러 개의 정수 연산 유닛들과 부동소수점 실수 연산 유닛들이 뭉쳐있으므로, GPU 내부 파이프라인이 CPU 내부 코어에 가까운 구조라고 볼 수 있다.

결국 2006년 11월에 NVIDIA가 지포스 8800 GTX에 사용된 G80을 통해 정수 ALU(Arithmetic Logic Unit) 1개와 FP32 유닛(32-bit Floating Point Unit) 1개씩으로 단순하게 구성된 CUDA 유닛과 특수 연산을 수행하는 SFU(Special Function Unit), 데이터를 저장하고 불러올 수 있는 로드/스토어 유닛(Load/Store Unit), 덧셈과 곱셈을 동시에 지원하는 FMA(Fused Multiply-Add) 기능으로 병렬 연산 능력을 키우고, 종래의 하이브리드 연산을 넘어 범용(GPGPU) 연산에 대응할 수 있는 유연성과 효율성을 키우기 위해 CUDA 유닛별로 고효율의 SIMD 연산과 MIMD 연산까지 가능해졌다. NVIDIA에서는 이를 SIMT라고 부르기도 했다. 이들이 그룹핑된 스트림 멀티프로세서(Stream Multiprocessor)를, 그 SM이 하나가 아닌 복수로 구성하고 SM들을 제어하는 TPC(GPGPU 관점에서는 Thread Processing Cluster, 그래픽 연산 관점에서는 Texture Processing Cluster)를,[21] 그 클러스터들을 제어하는 스레드 프로세서 또는 스케쥴러[22]라는 상위 집합 단위들이 등장하여 이전과는 차원이 다른 거대한 스케일의 GPU를 구현했다. 그야말로 백지 상태의 처음부터 다시 만든 새로운 패러다임의 GPU인 셈. 그 외에도 프론트엔드 단계에 탑재되어 있던 각종 유닛들이 훗날에는 래스터 엔진(Raster Engine)과 폴리모프 엔진(Polymorph Engine)으로 재배치 및 통합되어 현재까지 존속되고 있다.

2007년 상반기에 AMD도 라데온 HD 2900 XT에 사용된 R600을 통해 전통적인 SIMD 구조를 따르는 대신 4개의 ALU와 1개의 SFU씩 묶어서 FMA와 코-이슈(Co-Issue) 기능으로 병렬 연산 능력을 살리고 1D/2D/3D/4D/5D 등 임의의 조합으로 보다 더 다양한 명령어들을 다룰 수 있는 5-Way 슈퍼스칼라 셰이더 프로세싱 유닛(Superscalar Shader Processing Unit)을 발표했다. SSPU들이 모여 하나의 SIMD 어레이(Array)가 제어하고 SIMD 어레이들이 모여 하나의 울트라 스레드 디스페치 프로세서(Ultra Thread Dispatch Processor)가 제어하는 계층 구조는 기존 벡터+스칼라 SIMD 구조의 강화판이자 확장판으로, NVIDIA와 대조적인 발전 방향이지만 댜앙한 명령어들을 한꺼번에 대응할 수 있는 하이브리드 연산 기능은 물론이고, 거대한 스케일로 구현할 수 있다는 점에서 어느 정도 유사한 공통적인 특성을 지닌다고 볼 수 있다. 궁극적인 목적은 동일하지만 구현 방법에 따른 설계 사상이 서로 다르다는 것.

이렇듯 GPU도 일찌감치 멀티코어 시대로 돌입한 후 수 백개의 코어 단위를 넘은 매니코어 프로세서 형태로 발전되었고, 보다 다양한 명령어들을 효율적으로 대응하고 처리할 수 있게 되었다. 또한, 두 칩셋 제조사 모두 픽셀 셰이딩 연산과 버텍스 셰이딩 연산을 따로 두지 않고 하나의 연산기에 픽셀과 버텍스 둘 다 처리할 수 있는 통합 셰이딩 연산기로 발전되었기 때문에 셰이딩 연산 능력을 가늠하는 기준이 달라졌다. 이렇게 하나의 연산기에서 처리할 수 있는 명령어의 종류가 다양해지다 보니 GPU를 더이상 특정 연산 장치라고 부르지 않고 범용(GPGPU) 연산 장치로 취급하기에 이르렀다.

현재는 연산 관련 스펙을 파이프라인 단위로 사용하지 않으며, 연산 유닛 단위로 취급한다. 다만, 연산 유닛들이 일정한 개수만큼 뭉쳐진 단위라는 개념 자체는 존속하고 있는데 NVIDIA의 스트림 멀티프로세서(SM)와 AMD의 컴퓨트 유닛(Compute Unit)이 그것이다. 구성만 따지면 SM과 CU가 파이프라인 단위에 대응된다고 볼 수 있지만, 동작 원리는 다르기 때문에 모든 면에서 파이프라인 단위와 같다고 볼 수는 없다. 특히 CUDA 유닛 자체가 한 가지의 연산 기능이 아닌 정수 연산 기능과 부동소수점 실수 연산 기능이 하나씩 뭉쳐진 구성이기도 하고... 물론 기능적으로는 동작시 양자택일로만 동작할 수 있었다가, 2017년 볼타 마이크로아키텍처부터 정수 연산 유닛과 부동소수점 실수 연산 유닛이 동시에 동작할 수 있게 되면서 기능적인 면에서도 SM이 파이프라인 단위에 부합되지 않는다고 보면 된다.

활용하는 프로그램(작업의 성격) 별로 가능한 최대 효율이 다르고 칩셋 제조사마다 설계 사상이 다르므로 게이밍 성능을 판단하려면 해당 게임의 실측 자료를 통해 판단하는 것이 좋다. 여기서는 '세대를 거듭하면서 단일 GPU 내부의 코어 개수가 대체로 증가한다'는 정도로만 참고할 것. 과거에는 1개의 파이프라인(현재는 코어)에 4-Way SIMD로 갖춘 4D 구조였으나 현세대에는 1개의 코어에 1D 구조로 대응해서 코어 카운팅하고 있기 때문에 명시된 파이프라인 개수와 코어 개수만 놓고 직접적으로 비교하기 곤란하므로, 개수를 비교할거면 연산기의 개수로 환산해서 비교하는 것이 타당하다.

3. 매니코어 프로세서

근본적으로 매니코어 프로세서는 멀티코어 프로세서의 특수한 형태의 일부이다. 매니코어 프로세서를 구분짓는 특징으로는 매니코어 프로세서가 아닌 일반적인 멀티코어 프로세서와 싱글코어 프로세서의 코어가 동시대의 매니코어 프로세서 보다 상대적으로 적은 코어 갯수를 가지고 있기에 특별히 멀티스레드 프로그램이 아니라 싱글 스레드의 프로그램이여도 무난한 성능으로 동작한다. 그에 비해 매니코어 프로세서는 상대적으로 낮은 성능의 코어가 최소 수십개 이상 달려 있고 이를 통해 극한으로 병렬화 된 프로그램을 실행하는 것을 목적으로 한 프로세서이다. 이 때문에 멀티코어 프로세서에선 MIMD/MPMD 모델이 효율적으로 동작하는것에 비해 매니코어는 SIMD 연산에 더 효율적이다.

이 때문에 매니코어 프로세서에서 병렬화가 부족한 프로그램을 실행하는 경우 프로세서의 성능을 크게 이끌어 낼 수 없게 된다.

대표적인 매니코어 프로세서는 GPU를 꼽을 수 있고, 그 외의 매니코어 프로세서가 적용되는 곳은 TILE64 프로세서와 같이 하드웨어 네트워크 장비에서 주로 사용된다.

그 특징상 멀티코어 프로세서가 64코어를 달성한 시기는 2018년 이후에서 AMD가 첫 선을 보였지만 매니코어 시장에서는 64코어는 이미 2007년에 달성한지 오래였다.
기술의 발전으로 집적도가 증가하여 일반적인 고성능 멀티코어 프로세서들 또한 코어 수가 증가하는 추세지만 동시대의 매니코어 프로세서에 비하면 매우 적은 코어를 가지고 있다.
멀티코어 프로세서인 AMD EPYC 7773X가 64코어를 가지고 있지만 동시대의 매니코어 프로세서인 AMD Instinct MI250X와 NVIDIA RTX A6000이 각각 14080, 10752개의 코어를 가지고 있는 것이 그 예이다.

하드웨어
소프트웨어

4. 하이브리드 프로세서

멀티코어와 매니코어 프로세서의 공통점은 동일한 설계의 코어 유닛이 n개 만큼 존재하지만 하이브리드 프로세서의 경우 전혀 다른 실리콘 로직이 탑재 된 경우를 하이브리드 프로세서로 지칭한다.

다른 실리콘 로직의 조건은 같은 ISA를 가지고 있지만 낮은 소비전력의 저성능 코어와 높은 소비전력을 가진 고성능 코어를 합친 제품이거나[28] 전혀 다른 ISA를 해석하는 프로세서들이 통합된 HSA 또한 하이브리드 프로세서의 범주에 포함할 수 있다.

특히 소비전력, 성능, 확장성 (Scalability)의 관계는 경제학의 불가능의 삼각정리가 보여주는 특성을 고스란히 가지고 있으므로 이러한 하이브리드 프로세서가 자주 사용되는 모바일 프로세서들의 경우 이를 극복하기 위해 특성화된 코어들을 탑재하여 사용 환경에서 최대한의 효율을 가져다 주기 위한 목적으로 사용되는 편이다.

4.1. 관련 기술과 제품들

5. 관련 문서


[1] 그리고 역사적인 현실판. 엄밀히 말하면 뇌는 PC 본체, 정신은 운영체제이므로 이는 2CPU가 아니고 그냥 2 PC(그리드 컴퓨팅)에 가까우며, 운영체제가 서로 다르니 하이브 마인드가 아니면 많을수록 '조별 과제' 문서 내용처럼 배가 산으로 갈 수 있다.[2] 짤방의 의미는 멀티코어 미지원 게임 또는 무늬만 멀티코어일 뿐, 싱글코어에 가까운 게임들이 코어 하나만 갈구고 나머지 코어들은 놀게 냅두는 걸 비꼬는 것이다. 다만 이 짤방에 들어간 게임인 월드 오브 탱크는 2018년 3월 자 대규모 패치로 멀티코어 지원 능력이 향상되었기 때문에 과거에는 저랬다는 걸로 이해하면 된다.[3] IBMPOWER4 프로세서[4] 터보 부스트가 먼저 나왔다.[5] 불도저 기반 AMD FX 시리즈, 셀러론 시리즈 등등.[6] 전체 슬라이트 직링크, 직링크 출처 및 전체 발표 내용[7] 아래에서 언급되는 원리로, 1번 스레드의 App logic(녹색)이 2번 스레드 App logic과 관련이 있다면? 3번 스레드와 4번 스레드의 처리가 서로 데이터를 교환해가면서 결과에 맞춰서 변하는 거라면? 하는 식으로, 막상 스레드 별로 분리를 하려고 하면 쪼갤 수 없는 이유 투성이가 된다.[8] 비동기 실행은 멀티스레드(병렬 실행) 과는 동일한 개념은 아니라는 점에 유의. 극단적으로, 싱글코어 CPU를 잘 활용해서 비동기적 프로그램을 돌리는 것으로 아래의 예에서 나오는 것 같은 원하는 결과를 얻을 수 있다.[9] 간단한 방법으로는 '미리 메세지를 보낸 다음 전달한다'가 있지만, 컴퓨터 내에서 미리 메세지를 보낸다는 행동 자체가 그냥 연산하는 것보다 상당한 시간 지연을 부른다. 무작정 여기에만 의존할 수가 없는 것.[10] 다만 이런 경우 엄밀히 따지면 사용자에게 보여지는 화면은 내부 게임 로직에 비해 몇프레임 전의 과거를 보게 된다.[11] 그리고 스레드 2개 중에 하나는 어째서인지 신나게 렉걸리는 와중에도 늘 로드율 100퍼를 찍지 않는다. 즉, 가뜩이나 코어 둘 밖에 없는데 하나는 직무유기하여 사실상 1.5~1스레드 수준의 효과밖에 볼 수 없다는 의미이다. 심지어 이 때 GPU 로드율은 오히려 떨어진다. 고사양 그래픽 카드를 달면, 물량이 별로 없는 초반에는 70~90%까지 찍다가 물량이 늘면 오히려 50% 언저리로 떨어지는 기현상이 생긴다.[12] 12600K(F)[13] 12600K(F)를 제외한 나머지 모델[14] 1x600K(F) & 1x600 & 1x500[15] 1x400(F)[16] 10세대 이후로는 모종의 이유로 코어-X 시리즈를 출시하지 않고 사실상 워크스테이션용 W-시리즈 제온에 통합되었다.[17] ☆950X(3D)[18] ☆900(X, X3D)[19] AMD64기반 데스크탑 CPU중 가장 많은 코어와 스레드를 보유하고있다. 서버까지 포함하면 4위[20] 일반 가정용 최초의 8코어 CPU로 알려졌으나, 2015년 11월부터 2019년 8월까지 소송 기간 끝에 완전한 8코어가 아닌 CPU로 인정되었다.[21] 훗날에는 그래픽 프로세싱 클러스터(Graphics Processing Cluster)로 계승되었다.[22] 훗날에는 기가 스레드 엔진(Giga Thread Engine)으로 계승되었다.[23] 이때부터 연산 특화 제품군 명칭인 TESLA가 빠졌다.[24] 최초로 10,000코어(FP32코어만카운트시 5,000코이)를 넘어선 제품이다.[25] 이 GPU는 본래 한 PCB에 2개의 다이가 인피니티 패브릭으로 연결되어 있으므로, x2를 해야 실제 코어수가 나온다.[26] 라데온 RX에서는 1번째로, 모든 소비자용 GPU를 통틀어선 2번째로 스트림 프로세서 5천개와 FP32 연산을 수행할수 있는 유닛 1만개를 넘어선 제품이다.[27] 이 GPU 같은 경우에는 GCD(Graphics Compute Die) 두 개가 인피니티 패브릭으로 연결되어서 1개의 다이를 구성하는 방식이다.[28] 인텔의 골드몬트처럼 동일 ISA 지만 일부 명령어를 지원하지 않는 경우도 있다.