2011-10-07 5 views

답변

7

글쎄 GPGPU가 SIMD 실행 만 지원한다는 것은 정확하지 않습니다. 많은 GPU에는 비 SIMD 구성 요소가 있습니다. 하지만 전반적으로 GPU를 최대한 활용하려면 SIMD 코드를 실행해야합니다.

은 반드시 SIMD 명령어를 쓰는 것은 아닙니다. 나는. GPU SIMD는 이 아니며은 CPU SIMD와 동일합니다. 즉, x86 SSE (Stream SIMD Extensions) 등을 활용하는 코드 작성과 동일하지 않습니다. 실제로 CPU SIMD를 사용하는 사람들 중 한 사람인 것처럼 인텔 MMX에 처음 참여한 사람은 FP SIMD 로의 진화를 따라했습니다.) 나는 종종 인텔과 같은 CPU가 SIMD 명령어를 가지고 있다고 말하는 사람들을 바로 잡아야한다고 느낍니다. 저는 사람들이 그 이름을 오용했기 때문에 마지 못해 그들을 SIMD로 포장 된 벡터 명령 세트라고 부르지 만, 그것들을 벡터화 된 명령으로 포장하는 것을 선호합니다. 또한 MMX 나 SSE와 같은 CPU SIMD 명령 세트에는 정수 및 부동 소수점 ALU 등 SIMD로 묶인 벡터 실행 단위가있을 수 있지만 SIMD 제어 흐름이 없으며 일반적으로 SIMD 메모리 액세스가없는 것으로 강조합니다 (일명 scatter/gather (Intel Larrabee가 그 방향으로 움직이고 있었음에도 불구하고)). 이것에 대해 내 comp-arch.net 위키

일부 페이지 (내 취미 컴퓨터 아키텍처에 대해 쓸) : - http://semipublic.comp-arch.net/wiki/SIMD - http://semipublic.comp-arch.net/wiki/SIMD_packed_vector - http://semipublic.comp-arch.net/wiki/Difference_between_vector_and_packed_vector - http://semipublic.comp-arch.net/wiki/Single_Instruction_Multiple_Threads_(SIMT) 나는 아직 페이지를 작성하는 데 있지 사과 있지만, Intel MMX 또는 SIMD에서와 같이 SIMD로 패키징 된 벡터 명령어 sers에 대해 설명합니다.

하지만 위와 같은 내용을 모두 읽지는 않을 것으로 예상됩니다. 설명하려고 노력하겠습니다.

는 다음과 같이 보입니다 코드의 조각을 가지고 상상, 간단한, 스칼라, 같은 방법으로 기입 할 때 :

// operating on an array with one million 32b floating point elements A[1000000] 
for i from 0 upto 999999 do 
    if some_condition(A[i]) then 
      A[i] = function1(A[i]) 
    else 
      A[i] = function2(A[i]) 
기능 1()와 기능 2가() 인라인 정도로 간단

- 말 function1 (x) = x * x 및 function2 (x) = sqrt (x).

CPU에서. SSE와 같은 것을 사용하려면 (1) 배열을 청크로 나누고, 256 비트 AVX의 크기를 말하고, (2) 마스크 등을 사용하여 직접 IF 문을 처리해야합니다. 다음과 같이 입력하십시오 :

for i from 0 upto 999999 by 8 do 
    register tmp256b_1 = load256b(&A[i]) 
    register tmp256b_2 = tmp256b_1 * tmp256b_1 
    register tmp256b_3 = _mm_sqrt_ps(tmp256b_1) // this is an "intrinsic" 
               // a function, possibly inlined 
               // doing a Newton Raphson to evaluate sqrt. 
    register mask256b = ... code that arranges for you to have 32 1s in the "lane" 
         where some_condition is true, and 0s elsewhere... 
    register tmp256b_4 = (tmp256b_1 & mask) | (tmp256b_3 | ~mask); 
    store256b(&A[i],tmp256b_4) 

당신이 생각하기에는별로 좋지 않을 수도 있지만, 이것은 간단한 예입니다. 여러 중첩 된 IF 등을 상상해보십시오. 또는, 당신이 사진을 얻을 수 있다고 생각 ... 당신이 모든 기능 1 또는 모든 기능 2 인 섹션을 건너 뛰어 불필요한 계산을 많이 절약 할 수 있도록 "some_condition는"덩어리 진 것을

for i from 0 upto 999999 by 8 do 
    register mask256b = ... code that arranges for you to have 32 1s in the "lane" 
         where some_condition is true, and 0s elsewhere... 
    register tmp256b_1 = load256b(A[i]) 
    if mask256b == ~0 then 
     register tmp256b_2 = tmp256b_1 * tmp256b_1 
     store256b(&A[i],tmp256b_2) 
    else mask256b == 0 then 
     register tmp256b_3 = _mm_sqrt_ps(tmp256b_1) // this is an "intrinsic" 
     store256b(&A[i],tmp256b_3) 
    else 
     register tmp256b_1 = load256b(&A[i]) 
     register tmp256b_2 = tmp256b_1 * tmp256b_1 
     register tmp256b_3 = _mm_sqrt_ps(tmp256b_1) 
     register tmp256b_4 = (tmp256b_1 & mask) | (tmp256b_3 | ~mask); 
     store256b(&A[i],tmp256b_4) 

상상? 또한 배열이 여러 개있을 때 더욱 복잡해지며 때로는 데이터가 256 비트 경계에 정렬되는 경우가 있습니다 (일반적으로 스텐실 계산에서는 모든 정렬에 대해 연산이 수행됩니다).

자, 여기가 GPU처럼 뭔가 모양을 대략입니다 :

// operating on an array with one million 32b floating point elements A[1000000] 
for all i from 0 upto 999999 do 
    if some_condition(A) then 
      A = function1(A) 
    else 
      A = function2(A) 

가 원래 스칼라 코드와 같은 더 많은 보지합니까? 유일한 차이점은 배열 인덱스 A [i]를 잃어버린 것입니다. (실제로, 일부 GPGPU 언어는 배열 인덱스를 유지하지만, 대부분 내가 아는 것은 아님)

이제는 (a) Open/CL의 C와 유사한 구문, (b) 모든 설정 Open/CL 코드를 C 또는 C++ 코드에 연결해야합니다 (CUDA 또는 OpenCL보다 훨씬 우수한 언어가 있습니다 - 이들은 많은 어려움을 겪고 있지만 CPU와 GPU 모두에서 여러 곳에서 사용할 수 있습니다) [**]). 그러나 나는 그 문제의 핵심을 제시했다고 생각한다 :

GPGPU 계산의 핵심은 SIMD, 데이터 병렬 추위를 쓰는 것이다. 그러나 CPU 스타일 SSE 코드를 작성하는 것보다 더 높은 수준에서 작성합니다. 컴파일러 내장 함수보다 더 높은 수준입니다. 첫째, GPGPU 컴파일러, 예를 들어, GPGPU 컴파일러는 다음과 같다. OpenCL 또는 CUDA 컴파일러는 등 뒤에서 많은 데이터 관리를 처리합니다. 컴파일러는 제어 흐름, tghe IF 문 등을 조정합니다.

그런데 [가끔] 소위 SIMD GPGPU 컴파일러는 [**]로 표시했기 때문에 실행되는 코드를 생성 할 수 있습니다 CPU와 GPU 모두. 나는. SIMD 컴파일러는 CPU SIMD 명령어 세트를 사용하는 코드를 생성 할 수 있습니다.

그러나 GPU 자체는 CPU SIMD 명령어를 사용하여 CPU에서 실행할 수있는 것보다 훨씬 빨리이 SIMD 코드를 실행하는 특수 하드웨어 지원을 적절하게 컴파일합니다. 가장 중요한 점은 GPU가 더 많은 실행 단위를 보유하고 있다는 것입니다. AMD 불도저와 같은 CPU는 2 세트의 128 비트 폭 FMACS를 가지며, 즉 사이클 당 8 개의 FMAC를 수행 할 수있다. 칩 당 CPU 수를 곱한 값 - 예를 들어 8 - 사이클 당 64를 제공 할 수 있습니다. 현대 GPU는 매주기 2,048 32b FMAC를 가질 수 있습니다. 클럭 속도의 1/2 또는 1/4에서 실행되는 경우에도 큰 차이가 있습니다.

어떻게 GPU가 하드웨어를 더 많이 가질 수 있습니까? 글쎄, 우선, 그들은 보통 CPU보다 큰 칩입니다. 그러나 또한 CPU는 CPU가 소비하는 큰 캐시 및 순서가 잘못된 실행과 같은 것에 하드웨어를 낭비하지 않는 경향이 있습니다. CPU는 하나 또는 몇 가지 계산을 빠르게하려고하는 반면 GPU는 병렬로 많은 계산을하지만 CPU보다 개별적으로 느립니다. 하지만 GPU가 초당 처리 할 수있는 총 계산 수는 CPU가 수행 할 수있는 것보다 훨씬 큽니다.

FGPU에는 다른 하드웨어 최적화 기능이 있습니다. 예를 들어 CPU보다 많은 스레드를 실행합니다. Intel CPU에는 CPU 당 2 개의 하이퍼 스레딩이 있지만 8 개의 CPU 코어 칩에 16 개의 스레드를 제공하는 반면 GPU에는 수백 개의 스레드가있을 수 있습니다. 등등.

컴퓨터 아키텍트로서 가장 흥미로 우며, 많은 GPU는 SIMD 제어 흐름을위한 특별한 하드웨어 지원을 제공합니다. SSE를 실행하는 CPU보다 훨씬 효율적으로 마스크를 조작합니다.

등등.


어쨌든, 나는

  • 당신이이 (OpenCL을 같이) GPGPU 시스템에서 실행하는 SIMD 코드를 작성해야 할 동안 내 지점을 만들었습니다 바랍니다.

  • Intel SSE를 이용하려면이 종류의 SIMD와 사용자가 작성해야하는 SIMD 코드를 혼동하지 마십시오.

훨씬 더 깨끗합니다.

점점 더 많은 컴파일러가 동일한 코드를 DCPU와 GPU에서 실행할 수 있습니다. 나는. 그들은 MMX와 ​​SSE 및 AVX를 지금까지 활용하는 데 필요한 가짜 "의사 -SymD"코딩 스타일보다는 깨끗한 "실제 SIMD"코딩 스타일을 지원하고 있습니다. 이것은 좋은 일입니다 - 그런 코드는 CPU와 GPU 모두에서 똑같이 "좋은"프로그램입니다. 그러나 GPU는 종종이를 훨씬 빠르게 실행합니다. 인텔은 "100X GPU 대 CPU 신화 : CPU 및 GPU의 처리량 계산 평가"에 대해 http://www.hwsw.hu/kepek/hirek/2010/06/p451-lee.pdf이라고 불렀습니다. GPU는 평균 2.5 배 빠른 "단"이라고합니다. 그러나 그것은 많은 적극적인 최적화를 거친 것입니다. GPU 코드는 종종 작성하기가 더 쉽습니다. 그리고 나는 당신에 대해서 잘 모르지만, "단지"2.5 배 빠르다고 생각하면 재채기가별로 없습니다. 특히 GPGPU 코드는 읽기가 더 쉽기 때문에 특히 그렇습니다.

이제 무료 점심 식사가 제공되지 않습니다. 귀하의 코드가 자연스럽게 병렬 데이터라면. 그러나 어떤 회랑은 그렇지 않습니다. 그것은 고통이 될 수 있습니다.

그리고 모든 머신과 마찬가지로 GPU에도 버릇이 있습니다.

코드가 자연스럽게 데이터 병렬 인 경우 코드가 훨씬 읽기 쉽고 속도가 빨라질 수 있습니다.

저는 CPU 디자이너입니다. GPU에서 남성 CPU가 더 빨리 돌아가고, 그 반대의 경우도 아이디어를 많이 빌릴 것으로 기대됩니다.

관련 문제