본문 바로가기
MultiProcessing/OpenCL

OpenCL의 기본개념

by 능지처참 2020. 9. 28.

< 이종 플랫폼에서 실행되는 OpenCL 응용 프로그램의 처리과정 >

1. 이종 시스템을 구성하는 컴포넌트들을 탐색(예: Intel cpu, nvidia 1050, arm cortex등)

2. 소프트웨어가 서로 다른 하드웨어의 속성을 잘 이용할 수 있도록 컴포넌트의 특성을 조사(예: 최대 그룹 차원)

3. 플랫폼에서 실행될 커널을 작성

4. 계산에 필요한 메모리 객체(글로벌 아이템, 그룹 등등)들을 생성 및 관리

5. 커널들을 시스템의 올바른 컴포넌트에 올리고 올바른 순서로 실행

6. 최종 결과를 수집

 

< OpenCL을 설명하는 방법 - 모델 >

  • 플랫폼 모델: 이종 시스템에 대한 상위 수준의 기술(추상적 기술)
  • 실행 모델: 이종 플랫폼에서 명령어 스트림이 어떻게 실행되는지에 대한 추상적인 표현
  • 메모리 모델: OpenCL안의 메모리 영역들과 계산이 실행되는동안 이 메모리들이 어떻게 상호 연동되는지의 모델
  • 프로그래밍 모델: 응용을 구현을 위한 알고리즘을 설계할 때 프로그래머가 사용하는 상위 수준의 추상화

< 플랫폼 모델 >

  • 하나의 host와 한 개 이상의 OpenCL 디바이스(계산 디바이스, 예: CPU, GPU, DSP)로 구성
  • OpenCL 디바이스들은 계산 유닛들로 구성되고 이들은 한 개 이상의 PE(Processing Element)들로 구성됨 -> 실제적인 계산은 PE에서 수행됨

< 메모리 모델 >

  • 계산 디바이스(Compute device, OpenCL device): Intel i5 CPU, Nvidia 1080 GPU, DSP모듈과 같이 연산을 수행할 수 장치.
  • 계산 유닛(CU, Compute unit): 디바이스가 가지고 있는 코어.
  • Processing element(PE): 각 코어별로 실제로 계산을 수행하는 요소.
  • 디바이스가 GPU라면 PE는 SP(Streaming processor), CU는 SM(Streaming multiprocessor)으로 불리며 NVIDIA의 경우는 SP를 CUDA core라고 부른다. 이것 때문에 종종 혼동을 일으키는 것이 CUDA core를 CPU의 코어 처럼 생각하는 것이다. 다시 말하지만 코어는 실질적으로 SM에 대응된다고 할 수 있다. 이건 NVIDIA의 코어수 부풀리기 꼼수.
  • 실제로 CU에는 PE뿐만 아니라 여러가지 요소(부품)들이 포함되는데, 이것들은 심지어 플랫폼에 따라서도 상이하다. 하지만 OpenCL이 알아서 처리하기 때문에 우리가 이것들을 전부 알 필요는 없다(이런걸 상위 수준의 추상화라고 함).  그렇기 때문에 디바이스가 GPU라고 해서 PE를 SP라고 지칭할 필요가 없다. SP안에 어떻게 이루어졌는지 전부 알 필요도 없다(아는게 도움되는건 맞음).

 

  • 호스트 메모리(Host memory): 호스트쪽 메모리. 디바이스는 접근 불가능. -> 그래서 Buffer나 Image object를 사용해 데이터 전달
  • 전역 메모리(Global memory): 모든 작업-아이템(work-item)과 작업-그룹(work-group)이 할당되는 메모리. 모든 PE가 접근할 수 있으며 전역적인 메모리. 모든 PE가 접근하려 하기 때문에 병목현상이 발생하므로 느림.
  • 상수 메모리(Constant memory): 전역 메모리의 일부로 존재. 호스트에서 할당 및 초기화한 뒤 커널이 실행되는 동안 변하지 않음. 당연하게도 이 메모리에 대해 작업-아이템은 읽기 권한만을 가짐.
  • 지역 메모리(Local memory):  각 작업-그룹에 지역적으로 할당된 메모리. OpenCL 디바이스 전용으로(별도로) 구현되어 있을수도 있고 전역 메모리의 일부를 지역 메모리로 매핑해 구현되어 있을수도 있음.
  • 사유 메모리(Private memory): 하나의 작업-아이템이 개별적으로 소유하고 있는 메모리로 개별 계산에 필요한 정보를 담는 메모리이기 때문에 사실상 알 필요가 없는 메모리
  • Global/Constant memory cache: CU와 전역 메모리 사이를 완충하는 캐시. 디바이스에 따라서 있을수도 없을수도.
  • 인덱스 공간은 작업-아이템과 데이터의 매핑을 결정한다.
  • 작업-아이템은 PE, 작업-그룹은 CU에 대응된다고 할 수 있다. 이때 작업-그룹의 크기는 CU의 크기를 넘을 수가 없다. 하지만 작업-아이템의 크기에는 사실상 제한이 없다(작업-그룹의 개수는 작업-그룹과 작업-아이템의 크기를 지정하면 자동으로 정해지기 때문에 따로 정하지 않음). 이러한 이유는 작업-아이템은 아무리 커도 OpenCL이 적당히 분할해서 순차적으로 할당하면 되는데, 작업-그룹이 CU보다 커버리면 분할한다고 해도 너무 복잡하고 비효율적이기 때문이다. 참고로 작업-아이템은 작업-그룹의 배수로 할당해야 한다. 그래야 작업 그룹의 개수가 딱 나누어 떨어지기 때문이다. 여기서 앞의 내용을 잘 이해했다면 알 수 있겠지만 작업-그룹의 개수도 제한이 없는데 왜냐면 마찬가지로 OpenCL일 알아서 분할해 순차적으로 할당하면 되기 때문이다.
  • 작업-아이템을 크게 할당해봐야 CU와 PE의 개수가 제한되기 때문에 작업-아이템이 절대 1:1로 PE와 대응되는 것이 아님을 알 수 있다.
  • 작업-그룹의 크기를 따로 지정하지 않으면 마치 작업-그룹이 없는 것 처럼 알아서 CU에 작업을 할당한다. 참고로 작업-그룹의 크기를 따로 지정하지 않으려면 cl::Nullrange를 넣으면 된다.

댓글