요약 : 단일 스레드 프로그램에서 (명령 수준) 병렬 처리 를 찾아서 이용하는 것은 하드웨어에서 실행중인 CPU 코어에 의해 순수하게 수행됩니다. 그리고 대규모 재정렬이 아닌 수백 가지 명령의 창 이상.
단일 스레드 프로그램 은 단일 스레드 작업에서 시간을 허비하지 않고 다른 코어에서 다른 작업을 실행할 수 있다는 점을 제외하고 멀티 코어 CPU의 이점을 얻지 못합니다 .
OS는 모든 스레드의 명령을 서로 기다리지 않는 방식으로 구성합니다.
OS는 스레드의 명령 스트림 내부를 찾지 않습니다. 스레드 만 코어에 예약합니다.
실제로 각 코어는 다음에 수행 할 작업을 파악해야 할 때 OS의 스케줄러 기능을 실행합니다. 스케줄링은 분산 알고리즘입니다. 멀티 코어 머신을 더 잘 이해하려면 각 코어가 커널을 개별적으로 실행하는 것으로 생각하십시오. 멀티 스레드 프로그램과 마찬가지로 커널은 한 코어의 코드가 다른 코어의 코드와 안전하게 상호 작용하여 실행할 준비가 된 스레드 목록과 같은 공유 데이터 구조를 업데이트 할 수 있도록 작성되었습니다.
어쨌든 OS는 멀티 스레드 프로세스 가 멀티 스레드 프로그램을 수동으로 작성하여 명시 적으로 노출되어야하는 스레드 수준 병렬 처리를 이용하는 데 도움이 됩니다 . (또는 OpenMP 등 을 사용하는 자동 병렬 컴파일러로 ).
그런 다음 CPU의 프론트 엔드는 하나의 스레드를 각 코어에 분배하여 해당 명령어를 추가로 구성하고 열려있는주기마다 각 스레드에서 독립적 인 명령어를 분배합니다.
CPU 코어는 중지되지 않은 경우 하나의 명령 스트림 만 실행합니다 (예 : 다음 인터럽트까지 잠자기 (예 : 타이머 인터럽트)). 종종 스레드이지만, 커널 인터럽트 처리기 또는 커널이 처리 및 인터럽트 또는 시스템 호출 후 이전 스레드로 돌아 가기 이외의 작업을하기로 결정한 경우 기타 커널 코드 일 수도 있습니다.
HyperThreading 또는 기타 SMT 설계에서 물리적 CPU 코어는 여러 "논리적"코어처럼 작동합니다. 쿼드 코어와 하이퍼 스레딩 (4c8t) CPU 및 일반 8 코어 머신 (8c8t)의 OS 관점과의 유일한 차이점은 HT 인식 OS가 스레드를 물리적 코어를 분리하도록 스케줄링하려고 시도한다는 것입니다. 서로 경쟁하지 마십시오. 하이퍼 스레딩에 대해 알지 못한 OS는 8 개의 코어 만 표시합니다 (BIOS에서 HT를 비활성화하지 않으면 4 개만 감지).
" 프론트 엔드" 라는 용어 는 기계어 코드를 가져 와서 명령어를 해독하여 코어의 비 순차적 부분으로 발행하는 CPU 코어 부분을 의미합니다 . 각 코어에는 자체 프론트 엔드가 있으며 코어 전체의 일부입니다. 그것이 가져 오는 지침 입니다 CPU가 현재 실행중인 것.
코어의 비 순차적 부분 내에서 명령 (또는 uops)은 입력 피연산자가 준비되고 사용 가능한 실행 포트가있을 때 실행 포트로 전달됩니다. 이것은 프로그램 순서로 발생하지 않아도되므로 OOO CPU 가 단일 스레드 내 에서 명령 수준 병렬 처리를 활용할 수있는 방법 입니다.
아이디어에서 "핵심"을 "실행 단위"로 바꾸면 정확합니다. 그렇습니다. CPU는 독립적 인 명령어 / UOP를 실행 유닛에 병렬로 배포합니다. (하지만 실제로는 CPU의 명령 스케줄러 (예약 스테이션이라고도 함)가 실행 준비가 된 명령을 선택하는 경우 "프론트 엔드"라고 말했기 때문에 용어 혼합이 있습니다.)
비 순차적 실행은 두 개의 독립 루프 사이가 아니라 매우 짧은 로컬 수준에서만 최대 200 개의 명령어 만 ILP를 찾을 수 있습니다.
예를 들어, 이것과 동등한 asm
int i=0,j=0;
do {
i++;
j++;
} while(42);
Intel Haswell에서 카운터 하나만 증가시키는 동일한 루프만큼 빠르게 실행됩니다. i++
의 이전 값 에만 의존 i
하는 반면, 의 이전 값 j++
에만 의존 j
하므로 두 개의 종속 체인 은 프로그램 순서로 실행되는 모든 것을 환영하지 않고 병렬로 실행될 수 있습니다.
x86에서 루프는 다음과 같습니다.
top_of_loop:
inc eax
inc edx
jmp .loop
Haswell에는 4 개의 정수 실행 포트가 있으며 모든 포트에는 가산기 장치가 있으므로 inc
모두 독립적 인 경우 클럭 당 최대 4 개의 명령 처리량을 유지할 수 있습니다 . (지연 시간이 1 인 경우 4 개의 inc
명령을 비행 상태로 유지하여 처리량을 최대화하려면 4 개의 레지스터 만 필요합니다 . 벡터 -FP MUL 또는 FMA와 대조 : 지연 시간 = 5 처리량 = 0.5는 10 개의 FMA를 비행하기 위해 10 개의 벡터 누산기가 필요합니다. 각 벡터는 256b 일 수 있으며 8 개의 단 정밀도 부동 소수점을 보유합니다.
가져온 분기 처리량도 병목 현상입니다. 분기당 처리량은 클럭 당 1로 제한되므로 루프는 항상 반복 당 하나 이상의 전체 클럭을 사용합니다. 또한 읽기 / 쓰기 eax
또는 edx
종속성 체인을 연장 하지 않는 한 성능 저하없이 루프 안에 명령을 하나 더 넣을 수 있습니다. 루프에 2 개의 명령어를 추가하면 (또는 하나의 복잡한 다중 Uop 명령어) 프런트 엔드에 병목 현상이 발생합니다. 비 순차적 코어에는 클럭 당 4 개의 UOP 만 발행 할 수 있기 때문입니다. ( 4 uops의 배수가 아닌 루프에서 발생하는 일에 대한 자세한 내용 은 이 SO Q & A 를 참조하십시오 : 루프 버퍼 및 uop 캐시는 흥미로운 일입니다.)
더 복잡한 경우, 병렬 처리를 찾으려면 더 큰 명령 창을 살펴 봐야 합니다. (예를 들어 10 개의 명령이 모두 서로 의존하는 명령이있을 수 있으며, 일부는 독립적 인 명령이있을 수 있습니다).
재주문 버퍼 용량은 비 순차적 창 크기를 제한하는 요소 중 하나입니다. Intel Haswell에서는 192 개입니다. ( 레지스터 이름 바꾸기 용량 (레지스터 파일 크기)과 함께 실험적으로 측정 할 수도 있습니다 .) ARM과 같은 저전력 CPU 코어는 비 순차적 실행을 수행 할 경우 ROB 크기가 훨씬 작습니다.
또한 CPU는 비 순차적 일뿐만 아니라 파이프 라인되어야합니다. 따라서 실행중인 명령보다 먼저 명령을 페치 및 디코딩해야합니다. 페치주기가 누락 된 후 버퍼를 리필하기에 충분한 처리량으로 처리하는 것이 좋습니다. 지점이 어떤 방식으로 진행되는지 모르는 경우 어디에서 가져와야할지 모르기 때문에 지점이 까다로워집니다. 이것이 분기 예측이 중요한 이유입니다. (그리고 현대 CPU가 추론 적 실행을 사용하는 이유 : 브랜치가 어느 방향으로 가고 명령 스트림을 페치 / 디코딩 / 실행하기 시작하는지 추측합니다. 잘못된 예측이 감지되면 마지막으로 성공한 상태로 롤백하고 거기서부터 실행됩니다.)
CPU 내부에 대한 자세한 내용을 보려면 Agner Fog의 마이크로 아치 안내서 및 Intel 및 AMD CPU 다이어그램이있는 David Kanter의 자세한 글을 포함 하여 Stackoverflow x86 태그 위키에 링크가 있습니다. 그의 Intel Haswell 마이크로 아키텍처 작성에서 , 이것은 칩 전체가 아닌 Haswell 코어의 전체 파이프 라인의 최종 다이어그램입니다.
이것은 단일 CPU 코어 의 블록 다이어그램입니다 . 쿼드 코어 CPU에는 칩에 4 개가 있으며 각각 L1 / L2 캐시 (L3 캐시, 메모리 컨트롤러 및 시스템 장치에 대한 PCIe 연결 공유)가 있습니다.
나는 이것이 엄청나게 복잡하다는 것을 알고 있습니다. Kanter의 기사는 또한 예를 들어 실행 유닛 또는 캐시와 별도로 프론트 엔드에 대해 설명하기 위해이 부분을 보여줍니다.