OpenCL platform, device, context, command-queue, program
OpenCL Reference
https://www.khronos.org/registry/cl/
기본 표준
- OpenCL 아키텍처(architecture) 대한 전반적인 설명
- Host program에서 사용하는 API 함수 설명(동작 방식, 파라미터(parameter), 리턴 값, 오류 코드 등)
- OpenCL 프로그램을 작성하기 위한 OpenCL C 언어 설명
OpenCL application execution process
OpenCL Host datatype
CL/cl_platform.h에 선언되어 있습니다.
cl_typename 타입 : 아키텍처마다 data type의 크기가 다를 수 있기 때문에 정의되어 있습니다.
cl_char 8 bit
cl_short 16 bit
cl_int 32 bit
cl_long 64 bit
cl_half 16 bit half-precision floating-point value
cl_float 32 bit single-precision floating-point value
cl_double 64 bit double-precision floating-point value
OpenCL의 data structure
CL/cl.h에 선언되어 있습니다. 내부적으로는 모두 포인터로 선언되어 있습니다.
- cl_platform_id
- cl_device_id
- cl_context
- cl_command_queue
- cl_program
- cl_kernel
- cl_mem
- cl_sampler
- cl_event
Platform and device
OpenCL 프레임워크마다 하나 이상의 플랫폼(platform)을 제공합니다.
시스템에 여러 vendor(AMD, Intel, NVIDIA)의 OpenCL 프레임워크가 설치되어 있으면, platform도 여러개 입니다.
Get platform id and number of platform
platform의 id와 개수를 가져옵니다.
cl_int clGetPlatformIDs (cl_uint num_entries, cl_platform_id *platforms, cl_uint *num_platforms) |
리턴 값은 에러 정보를 의미합니다. 에러 코드별 의미는 CL/cl.h 파일에 정의되어 있습니다.
platform의 개수를 확인하고, platform id를 가져오는 코드는 다음과 같습니다.
cl_uint num_platforms; |
Check Error
- CL_SUCCESS(0) 이면 성공입니다.
- 음수이면 실패입니다.
#define CHECK_ERROR(err) \ |
Get platform Information
platform의 정보를 가져옵니다.
cl_int clGetPlatformInfo (cl_platform_id platform, cl_platform_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) param_name: CL_PLATFORM_{PROFILE, VERSION}, CL_PLATFORM_{NAME, VENDOR, EXTENSIONS}, CL_PLATFORM_HOST_TIMER_RESOLUTION, CL_PLATFORM_ICD_SUFFIX_KHR [Table 4.1] |
- CL_PLATFORM_NAME : platform 이름
- CL_PLATFORM_VENDOR : platform vendor 이름
- CL_PLATFORM_VERSION : platform이 지원하는 OpenCL 버전
- CL_PLATFORM_EXTENSIONS : platform이 지원하는 extension의 리스트
#define PLATFORM_NAME 256 |
Get Device ID and number of device
device와 ID와 개수를 가져옵니다.
cl_int clGetDeviceIDs (cl_platform_id platform, cl_device_type device_type, cl_uint num_entries, cl_device_id *devices, cl_uint *num_devices) device_type: [Table 4.2] CL_DEVICE_TYPE_{ACCELERATOR, ALL, CPU}, CL_DEVICE_TYPE_{CUSTOM, DEFAULT, GPU} |
device type에 ID를 얻어올 device의 종류를 지정해 줍니다.
- CL_DEVICE_TYPE_ALL
- CL_DEVICE_TYPE_CPU
- CL_DEVICE_TYPE_GPU
- CL_DEVICE_TYPE_ACCELERATOR : FPGA
- CL_DEVICE_TYPE_CUSTOM
- CL_DEVICE_TYPE_DEFAULT
- CL_DEVICE_TYPE_CPU | CL_DEVICE_TYPE_GPU
// Get number of devices |
Get device Information
device의 정보를 가져옵니다.
cl_int clGetDeviceInfo (cl_device_id device, cl_device_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) param_name: [Table 4.3] CL_DEVICE_ADDRESS_BITS, CL_DEVICE_AVAILABLE, CL_DEVICE_BUILT_IN_KERNELS, CL_DEVICE_COMPILER_AVAILABLE, CL_DEVICE_{DOUBLE, HALF, SINGLE}_FP_CONFIG, CL_DEVICE_ENDIAN_LITTLE, CL_DEVICE_EXTENSIONS, CL_DEVICE_ERROR_CORRECTION_SUPPORT, CL_DEVICE_EXECUTION_CAPABILITIES, CL_DEVICE_GLOBAL_MEM_CACHE_{SIZE, TYPE}, CL_DEVICE_GLOBAL_MEM_{CACHELINE_SIZE, SIZE}, CL_DEVICE_GLOBAL_VARIABLE_PREFERRED_TOTAL_SIZE, CL_DEVICE_IL_VERSION, CL_DEVICE_IMAGE_MAX_{ARRAY, BUFFER}_SIZE, CL_DEVICE_IMAGE_SUPPORT, CL_DEVICE_IMAGE2D_MAX_{WIDTH, HEIGHT}, CL_DEVICE_IMAGE3D_MAX_{WIDTH, HEIGHT, DEPTH}, CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT, CL_DEVICE_IMAGE_PITCH_ALIGNMENT, CL_DEVICE_LINKER_AVAILABLE, CL_DEVICE_LOCAL_MEM_{TYPE, SIZE}, … |
param_name에 어떤 정보를 얻을 지 지정합니다.
- CL_DEVICE_NAME : device 이름
- CL_DEVICE_VENDOR : device vendor 이름
- CL_DEVICE_MAX_COMPUTE_UNITS : device의 CU 개수
- CL_DEVICE_MAX_WORK_GROUP_SiZE : work-group 하나의 work-item 개수 제한
- CL_DEVICE_GLOBAL_MEM_SIZE : global memory 크기
- CL_DEVICE_LOCAL_MEM_SIZE : local memory 크기
- CL_DEVICE_MAX_MEM_ALLOC_SIZE : memory object 크기 제한
- CL_DEVICE_HOST_UNIFIED_MEMORY : host와 device가 메모리를 공유하는지
#define DEVICE_NAME 256 |
OpenCL ICD(Installable Client Driver)
동시에 여러 vendor의 platform을 얻어올 수 있습니다.
/etc/OpenCL/vendors 디렉터리 안에 시스템에 설치된 OpenCL 프레임워크들이 나열되어 있습니다.
OpenCL Context
kernel이 실행되는 환경입니다. 다른 객체들을 관리하기 위한 최상위 객체입니다.
context 단위로 command 간 동기화 및 메모리 관리르 수행합니다.
해당 context 안에서 사용할 device를 지정해야합니다. nvidia, amd 다른 platform은 context를 지정해야 합니다.
Create context
cl_context clCreateContext ( const cl_context_properties *properties, cl_uint num_devices, const cl_device_id *devices, void (CL_CALLBACK*pfn_notify) (const char *errinfo, const void *private_info, size_t cb, void *user_data), void *user_data, cl_int *errcode_ret) |
2, 3번째 parameter가 유용
// Get platform |
한계
- 하나의 context에서 여러 platform의 device를 동시에 사용할 수 없습니다.
- device 사이에 데이터 복사, 동기화 등이 불가능합니다.
OpenCL Command-Queue
device마다 하나의 command-queue를 만들어 주어야 합니다.
하나의 device에 여러 개의 command-queue를 연결 할 수도 있습니다.
Create command_queue
cl_command_queue clCreateCommandQueueWithProperties ( cl_context context, cl_device_id device, const cl_command_queue_properties *properties, cl_int *errcode_ret) *properties: Points to a zero-terminated list of properties and their values: [Table 5.1] CL_QUEUE_SIZE, CL_QUEUE_PROPERTIES (bitfield which may be set to an OR of CL_QUEUE_* where * may be: OUT_OF_ORDER_EXEC_MODE_ENABLE, PROFILING_ENABLE, ON_DEVICE[_DEFAULT]), CL_QUEUE_THROTTLE_{HIGH, MED, LOW}_KHR (requires the cl_khr_throttle_hint extension), CL_QUEUE_PRIORITY_KHR (bitfield which may be one of CL_QUEUE_PRIORITY_HIGH_KHR, CL_QUEUE_PRIORITY_MED_KHR, CL_QUEUE_PRIORITY_LOW_KHR (requires the cl_khr_priority_hints extension)) |
command_queue 종류
- In-order : command 들이 enqueue된 순서대로 실행합니다.
> 앞의 커맨드가 끝나야 다음 커맨드가 시작됩니다.
> 기본 실행 모드입니다.
> gpu는 대부분 많이 사용합니다.
- out-of-order : command 들이 enqueue된 순서와 무관하게 실행합니다.
> command의 사이의 순서를 맞춰주려면 별도의 동기화 기능 사용해야 합니다.
> GPU에서는 순서만 변경될 뿐 병렬 처리가 되는 것은 아닙니다.
> properties에 CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE을 지정해야 합니다.
cl_command_queue queues[2]; |
OpenCL program object
OpenCL 프로그램의 binary
- IR(Intermediate Representation)일 수도 있고, device에서 실제 실행 가능한 코드일 수도 있습니다.
- 소스 코드를 입력을 준 다음 컴파일해서 실행 가능한 binary로 만들거나, 처음부터 binary를 입력으로 줄 수 있습니다.
소스 코드로부터 프로그램 오브젝트 만들기
cl_program clCreateProgramWithSource ( cl_context context, cl_uint count, const char **strings, const size_t *lengths, cl_int *errcode_ret) |
const char *source_code = "..." |
이 방법은 잘 사용하지 않습니다.
대부분 kernel.cl 이라는 파일을 작성하고 읽어와 만듭니다.
char *get_source_code(const char *file_name, size_t *len) { |
OpenCL program build
프로그램을 빌드(build) 합니다.
cl_int clBuildProgram (cl_program program, cl_uint num_devices, const cl_device_id *device_list, const char *options, void (CL_CALLBACK*pfn_notify) (cl_program program, void *user_data), void *user_data) |
내부적으로 OpenCL 프레임워크의 OpenCL C 컴파일러 호출합니다.
컴파일을 수행할 device 리스트를 지정해주어야 합니다.
인자로 주어진 device 마다 각각 컴파일을 수행합니다.
빌드하지 않은 device에서는 kernel 실행이 불가합니다.
N이 정해져 있다면, -D N=1000
cl_device_id devices[4]; |
Build options
-D name : 매크로 name을 1로 정의합니다.
-D name=definition : 매크로 name을 definition으로 정의합니다.
-cl-opt-disable : 모든 컴파일러(compiler) 최적화를 끕니다.
-cl-unsafe-math-optimizations : 실수 연산의 에러 체크를 없애는 등의 방법으로 최적화를 합니다.
-cl-finite-math-only : 실수 값과 연산 결과가 NaN이나 무한대가 아니라고 가정합니다.
cl_device_id device; CHECK_ERROR(err); |
cl_int clGetProgramBuildInfo ( cl_program program, cl_device_id device, cl_program_build_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret) param_name: [Table 5.18] CL_PROGRAM_BINARY_TYPE, CL_PROGRAM_BUILD_{STATUS, OPTIONS, LOG}, CL_PROGRAM_BUILD_GLOBAL_VARIABLE_TOTAL_SIZE |
컴파일 에러 발생 시에 에러 메시지 확인으로 사용합니다.
특정 디바이스에 대해서 다른 컴파일을 수행하므로 하나의 device를 넣어 수행합니다.
// Build program |
OpenCL kernel object
Kernel object를 앞에서 만든 프로그램 object에서 특정 kernel 함수만 분리합니다.
프로그램이 build된 다음에 만들어야 합니다.
나중에 kernel object를 사용해 kernel을 실행시킵니다.
cl_kernel clCreateKernel (cl_program program, const char *kernel_name, cl_int *errcode_ret) |
// Build program |
Reference Count
객체가 몇 군데서 참조되었는지 확인합니다.
Reference Count가 0이 되면 알아서 해당 객체가 저장된 메모리가 해제됩니다.
객체를 사용하는 중에는 reference count를 0보다 크게 유지해야합니다.
Reference count 증가 +1
- cl_int clRetainContext(cl_context context)
- cl_int clRetainCommandQueue(cl_command_queue command_queue)
- cl_int clRetainProgram(cl_program program)
- cl_int clRetainKernel(cl_kernel kernel)
- cl_int clRetainMemObject(cl_mem mem)
Reference count 감소 -1
- cl_int clReleaseContext(cl_context context)
- cl_int clReleaseCommandQueue(cl_command_queue command_queue)
- cl_int clReleaeseProgram(cl_program program)
- cl_int clReleaseKernel(cl_kernel kernel)
- cl_int clReleaseMemObject(cl_mem mem)
OpenCL Host program
host 코드 작성 시 cl.h 헤더 파일을 추가해야 합니다.
#include <CL/cl.h>
컴파일(링킹)
- 링킹 옵션에 -lOpenCL 추가합니다.
- 컴파일 예
gcc -o opencl_app opencl_app.c -lOpenCL
OpenCL Github Code
밑에 있는 코드들은 다음의 github에 올려놓았습니다.
https://github.com/KimJeongChul/opencl
OpenCL Skeleton Code
#include <stdio.h> |
Platform의 정보를 가져오는 코드입니다.
#include <stdio.h> |
$ gcc -o opencl_info opencl_info.c -lOpenCL
$ thorq --add --mode single --device gpu/7970 ./opencl_info
$ cat task_NUM.stdout
이번에는 디바이스 정보도 가져와보겠습니다.
$ vi opencl_info.c
#include <stdio.h> |
$ gcc -o opencl_info opencl_info.c -lOpenCL
$ thorq --add --mode single --device gpu/7970 ./opencl_info
$ cat task_NUM.stdout
'OpenCL' 카테고리의 다른 글
OpenCL [0] introduction (0) | 2018.08.27 |
---|---|
OpenCL[3] Memory Object, Kernel Execution (0) | 2018.08.23 |
OpenCL [1] concept (0) | 2018.08.21 |