Opencl編程的標準開發流程
- 前言
- OpenCL執行流程
- 模板
前言
在前面的內容中介紹 了opencl編程環境的搭建方式環境搭建,本篇文章以為例講述opencl編程的標準開發流程
編程環境:VS2015 + Intel? UHD Graphics 620
OpenCL執行流程
1.創建OpenCL程式第一步是要確定其執行的平臺,clGetPlatFormIDs:
cl_int clGetPlatFormIDs(cl_uint num_entries, cl_platform _id * platforms,cl_uint *num_platforms)
2.在確定平臺之后確定執行計算的設備,使用函式clGetDeviceIDs:
cl_int clGetDeviceIDs(cl_platform_id platform,cl_device_type device_type, cl_uint num_entries, cl_device_id *devices, cl_uint *num_devices);
3.確定設備后創建背景關系,背景關系為關聯的設備、命令佇列、程式物件、內核物件提供了一個容器,其所關聯的設備必須來自同一平臺,使用函式clCreateContext:
cl_context clCreateContext(const cl_context_properties * properties, cl_uint num_devices, const cl_device_id * devices, (void)(*pfn_notify) (const char * errinfo, const void *private_info ,size_t cb, void *user_data), void *user _data, cl_int * errcode_ret);
4.創建命令佇列,在背景關系中對物件的操作需要依賴命令佇列,主機將命令提交到命令佇列中,命令佇列將命令發送給設備,命令佇列和設備滿足一對一的關系,函式clCreateCommandQueue:
cl_command_queue clCreateCommandQueue(cl_context context, cl_device_id device, cl_command_queue_properties properties,cl_int *errcode_ret)
5.創建記憶體物件,函式clCreateBuffer:
cl_mem clCreateBuffer(cl_context context,cl_mem_flags flags,size_t size,void *host_ptr,cl_int *errcode_ret)
6.創建程式物件,可以通過傳入OpenCL C 源代碼文本,也可以利用程式二進制來創建,本人更習慣使用第一種方法,clCreateProgramWithSource:
cl_program clCreateProgramWithSource (cl_context context,cl_uint count,const char **strings,const size_t *lengths,cl_int *errcode_ret)
7.編譯程式物件,clBuildProgram 會為指定的所有設備構建程式物件,等價于在C程式上呼叫編譯器與聯結器,
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)
8.創建內核物件,內核物件可以是一個通過命令佇列發送到設備上執行的函式,創建函式clCreateKernel:
cl_mem clCreateBuffer(cl_context context,cl_mem_flags flags,size_t size,void *host_ptr,cl_int *errcode_ret)
9.設定內核引數,內核函式的引數需要通過clSetKernelArg來傳遞,
cl_int clSetKernelArg(cl_kernel kernel, cl_uint arg_index,size_t arg_size, const void *arg_value)
10.執行內核,在所有的準備作業已經做好之后,便可以讓設備來執行內核函式,clEnqueueNDRangeKernel:
cl_int clEnqueueNDRangeKernel(cl_command_queue command_queue,cl_kernel kernel, cl_uint work_dim,const size_t *global_work_offset,const size_t *global_work_size,const size_t *local_work_size,cl_uint num_events_in_wait_list,const cl_event *event_wait_list, cl_event *event)
11.OpenCL設備執行完計算后,將資料拷貝回主機端并銷毀分配的資源,
以上就是整個的開發流程,
模板
根據此程序,自己撰寫了一套通用模板
#include<stdio.h>
#include<stdlib.h>
#include<CL/cl.h>
#include<string.h>
#include <iostream>
#pragma warning( disable : 4996 )s
#define MAX_SOURCE_SIZE (0x100000)
int main(void) {
cl_int err = 0;
//查詢第一個平臺
cl_platform_id platform;
err = clGetPlatformIDs(1, &platform, NULL);
if (err < 0) {
perror("Couldn't find any platforms");
exit(1);
}
//查詢平臺上的設備
cl_device_id device;
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, NULL);
if (err < 0) {
perror("Couldn't find any DEVICE");
exit(1);
}
//創建背景關系
cl_context context = clCreateContext(NULL, 1, &device, NULL, NULL, &err);
if (NULL == context)
{
perror("Couldn't create context");
exit(1);
}
//創建命令佇列
cl_command_queue CommandQueue = clCreateCommandQueue(context,device, 0, NULL);
if (NULL == CommandQueue)
{
perror("Couldn't create command queue");
exit(1);
}
//創建輸入輸出記憶體物件
// 創建輸入記憶體物件
int len;
const char* input;//輸入字串
cl_mem memInutBuffer = clCreateBuffer(
context,
CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, // 輸入記憶體為只讀,并可以從宿主機記憶體復制到設備記憶體
(len + 1) * sizeof(char), // 輸入記憶體空間大小
(void *)input,
NULL);
// 創建輸出記憶體物件
cl_mem memOutputBuffer = clCreateBuffer(
context,
CL_MEM_WRITE_ONLY, // 輸出記憶體只能寫
(len + 1) * sizeof(char), // 輸出記憶體空間大小
NULL,
NULL);
if ((NULL == memInutBuffer) || (NULL == memOutputBuffer))
{
perror("Error creating memory objects");
exit(1);
}
//讀取CL程式原始碼,將cl檔案中的代碼轉為字串
FILE* fp = fopen("*.cl", "rb");
if (fp == NULL) {
perror("Couldn't find the program file");
exit(1);
}
fseek(fp, 0, SEEK_END);
size_t filesize = ftell(fp);
fseek(fp, 0, SEEK_SET);
rewind(fp);
char *program_buffer=(char*)malloc(filesize+1);
program_buffer[filesize] = '\0';
fread(program_buffer, sizeof(char), filesize, fp);
fclose(fp);
//創建CL程式
cl_program program= clCreateProgramWithSource(context, 1,&program_buffer,&filesize, &err);
if (err < 0) {
perror("Couldn't create the program");
exit(1);
}
//編譯CL程式
const char options[] = "-cl-finite-math-only -cl-no-signed-zeros";
err = clBuildProgram(program, 1, &device, options, NULL, NULL);
if (err < 0) {
/* Find size of log and print to std output */
char *program_log;
size_t log_size;
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG,0, NULL, &log_size);
program_log = (char*)malloc(log_size + 1);
program_log[log_size] = '\0';
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG,log_size + 1, program_log, NULL);
printf("%s\n", program_log);
free(program_log);
exit(1);
}
//創建CL內核
cl_kernel kernel = clCreateKernel(program, "kernelname", &err);
if (err < 0) {
perror("Couldn't create the kernel");
exit(1);
}
//設定內核引數,根據實際的Kernel修改
err = clSetKernelArg(kernel, 0,sizeof(memInutBuffer),(void *)memInutBuffer);
err = clSetKernelArg(kernel, 1, sizeof(memInutBuffer), (void *)memOutputBuffer);
//計算,引數值按照 實際 修改
size_t global_work_size[] = {100};
size_t local_work_size[] = { 1 };
err = clEnqueueNDRangeKernel(CommandQueue, kernel, 1, NULL,global_work_size, local_work_size,0, NULL, NULL);
//讀取結果
err = clEnqueueReadBuffer(CommandQueue, memOutputBuffer, CL_TRUE, 0, len * sizeof(char), memOutputBuffer,0, NULL, NULL);
//輸出資料
//釋放資源
err = clReleaseKernel(kernel);
err = clReleaseProgram(program);
err = clReleaseMemObject(memInutBuffer);
err = clReleaseMemObject(memOutputBuffer);
err = clReleaseCommandQueue(CommandQueue);
err = clReleaseContext(context);
}
以上均為原創內容 如需轉載,請注明出處 如有問題,還請指正,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/266718.html
標籤:區塊鏈
