수색…


소개

이 항목에서는 OpenCL을 완전히 이해하고 활용하는 데 필요한 병렬 컴퓨팅의 기본 핵심 메커니즘을 소개합니다.

쓰레드와 실행

병렬 처리의 핵심은 여러 스레드를 사용하여 문제를 해결하는 것입니다 (단점). 그러나 스레드가 어떻게 구성되어 있는지에 대한 고전적인 다중 스레드 프로그래밍에는 몇 가지 차이점이 있습니다.

우선 간단한 GPU에 대해 이야기 해 보겠습니다.

GPU는 많은 프로세싱 코어를 가지고있어 다수의 스레드를 병렬로 실행하는 것이 이상적입니다. 이러한 코어는 스트리밍 프로세서 (SM, NVidia 용어)로 구성되며 GPU에는 주어진 번호가 있습니다.

SM 내부에서 실행되는 모든 스레드를 '스레드 블록'이라고합니다. 코어에는 코어보다 많은 스레드가있을 수 있습니다. 코어의 수는 소위 '워프 크기'(NVidia 용어)를 정의합니다. 스레드 블록 내부의 스레드는 소위 말하는 '워프'로 예약됩니다.

후속 예제 : 일반적인 NVidia SM은 32 개의 프로세싱 코어를 가지고 있으므로 워프 크기는 32입니다. 이제 내 스레드 블록에 128 개의 스레드가 있으면 4 개의 워프 (4 개의 워프 * 32 개의 워프 크기 = 128 스레드).

나중 스레드 수를 선택할 때 워프 크기가 ​​중요합니다.

단일 워프 내의 모든 스레드는 단일 명령 카운터를 공유합니다. 즉, 모든 스레드가 동시에 모든 명령을 실행한다는 점에서 32 개의 스레드가 실제로 동기화된다는 의미입니다. 여기에 성능상의 함정이 있습니다 : 이것은 커널의 브랜칭 문장에도 적용됩니다!

예 : if 문과 두 개의 분기가있는 커널이 있습니다. 워프 내부 스레드 16 개가 분기 1을 실행하고 다른 16 개 분기가 실행됩니다. if 문까지는 워프 내부의 모든 스레드가 동기화됩니다. 이제 그들 중 절반이 다른 지점을 선택합니다. 잘못된 문장이 처음 16 개 스레드에서 실행을 마칠 때까지 나머지 절반은 휴면 상태가됩니다. 그런 다음 해당 스레드는 다른 16 개의 스레드가 분기를 완료 할 때까지 휴면 상태가됩니다.

보시다시피, 나쁜 분기 습관은 병렬 코드를 심각하게 늦출 수 있습니다. 두 문장 모두 최악의 경우에 실행되기 때문입니다. 워프 내의 모든 스레드가 명령문 중 하나만 필요하다고 결정하면 다른 스레드는 완전히 건너 뛰고 지연이 발생하지 않습니다.

쓰레드 동기화 또한 간단한 문제가 아닙니다. 단일 SM과 스레드를 동기화 할 수 있습니다. SM 외부의 모든 것은 커널 내부에서 동기화 할 수 없습니다. 당신은 별도의 커널을 작성하고 차례로 시작해야합니다.

GPU 메모리

GPU는 6 개의 서로 다른 메모리 영역을 제공합니다. 대기 시간, 크기 및 액세스 가능성이 각기 다른 스레드에서 다릅니다.

  • 전역 메모리 : 사용 가능한 가장 큰 메모리이며 호스트와 데이터를 교환하는 몇 안되는 메모리 중 하나입니다. 이 메모리는 가장 높은 대기 시간을 가지며 모든 스레드에서 사용할 수 있습니다.
  • Constant Memory : 전역 메모리의 읽기 전용 부분. 다른 스레드에서만 읽을 수 있습니다. 이점은 전역 메모리에 비해 대기 시간이 짧다는 것입니다.
  • 텍스처 메모리 : 또한 텍스처 용으로 특별히 고안된 상수 메모리의 일부입니다.
  • 공유 메모리 :이 메모리 영역은 SM에 가깝게 배치되며 단일 스레드 블록에서만 액세스 할 수 있습니다. 이 방법은 전역 메모리보다 대기 시간이 짧고 상수 메모리보다 대기 시간이 짧습니다.
  • 레지스터 : 단 하나의 스레드 만 액세스 할 수 있으며 가장 빠른 메모리가 모두 액세스 할 수 있습니다. 그러나 컴파일러가 커널에 필요한 레지스터가 충분하지 않다는 것을 감지하면 변수를 로컬 메모리에 아웃소싱합니다.
  • 로컬 메모리 : 전역 메모리 영역의 스레드 전용 액세스 가능한 메모리 부분입니다. 가능한 경우 레지스터의 백업으로 사용되므로 피해야합니다.

메모리 액세스

메모리 사용에 대한 일반적인 시나리오는 원본 데이터와 처리 된 데이터를 전역 메모리에 저장하는 것입니다. 스레드 블럭이 시작되면 먼저 레지스터에 파트를 가져 오기 전에 모든 관련 파트를 공유 메모리에 복사합니다.

메모리 액세스 대기 시간은 메모리 전략에 따라 다릅니다. 데이터에 맹목적으로 액세스하면 최악의 성능을 얻을 수 있습니다.

서로 다른 추억은 이른바 '은행'으로 조직되어 있습니다. 뱅크에 대한 각 메모리 요청은 단일 클록 사이클에서 처리 될 수있다. 공유 메모리의 뱅크 ​​수는 워프 크기와 동일합니다. 단일 워프 내에서 충돌하는 뱅크 액세스를 피함으로써 메모리 속도를 높일 수 있습니다.

공유 메모리를 전역 메모리에서 또는 전역 메모리로 복사하는 가장 빠른 방법은 메모리 호출을 '정렬'하는 것입니다. 즉, 워프의 첫 번째 스레드는 공유 메모리와 전역 메모리 모두의 뱅크에있는 첫 번째 요소에 액세스해야합니다. 두 번째 스레드는 두 번째 요소와 같은 식으로 진행됩니다. 이 호출은 전체 뱅크를 대상 메모리에 한 번에 복사하는 단일 메모리 전송 명령어로 최적화됩니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow