封装OpenCL类
Posted hbg200
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了封装OpenCL类相关的知识,希望对你有一定的参考价值。
以上一篇《OpenCL入门测试》为基础,将函数封装到类中,方便调用。
#include <cstdlib> #include <iostream> #include <iomanip> #include <cstring> #include <cassert> #include <windows.h> #define CL_USE_DEPRECATED_OPENCL_1_2_APIS // 定义使用OpenCL 1.2 #include <CL/cl.h> using namespace std; class COpenCL { public: //const int Size = 38888888;//大小和内存有关,仅作示例 const int Size = 2073600;//一帧高清点数 float* nums1_h = new float[Size];//动态创建 nums1_h 数组 float* nums2_h = new float[Size];//动态创建 nums2_h 数组 float* sum_h = new float[Size]; //动态创建 sum_h 数组 float* gpu_sum = new float[Size]; void Init(void); // 初始化 void Close(void);// 关闭,释放资源 void CreateBuffer(void);// 创建缓冲区 void CreateProgramSource(void);// 创建异构源代码 void SetKernelArg(void);// 设置核参数 void RunGPU(void);// 运行GPU void RunAsCpu(const float *nums1, const float *nums2, float* sum, const int num);// CPU运行函数 private: cl_mem nums1_d,nums2_d,sum_d; const int mem_size = sizeof(float) * Size;//计算设备所需存储器 size_t global_work_size = Size;//设备需要工作项(线程) cl_int Err; cl_platform_id Selected_Platform_ID; // 已选择平台的ID cl_device_id DevicesID; // GPU设备 cl_context Context; // 设备管理 cl_command_queue CommandQueue; // 命令队列 cl_program Program; // 程序对象 cl_kernel Kernel; // 内核对象 cl_kernel RunAsGpu;//核函数 void SelectedPlatform(void);//选择平台 void CreateDevice(void);// 创建GPU设备 void CreateContext(void);// 创建设备管理 void CreateCommandQueue(void);// 创建命令队列 void GetProgramBuildInfo(void);// 获取异构(设备)编译程序信息 }; // 全局变量 _LARGE_INTEGER g_iSysFrequency,// 系统频率 iStartTestTime; // 开始测试时间 // 错误检查宏 #define CheckErr(Err, PrintStr) if(Err != CL_SUCCESS) { printf(" "); printf(" "); printf(PrintStr); printf(" "); system("pause"); exit(1); } //--------------------------------------------------------------------------- // 核函数源码字符串 const char *RunAsGpu_Source = "__kernel void RunAsGpu_Source(__global const float *nums1, __global const float *nums2, __global float* sum) " "{ " "int id = get_global_id(0); " "sum[id] = nums1[id] + nums2[id]; " "} "; //--------------------------------------------------------------------------- void COpenCL::RunAsCpu(const float *nums1, const float *nums2, float* sum, const int num)// CPU运行函数 { for (int i = 0; i < num; i++) { sum[i] = nums1[i] + nums2[i]; } } void StartTestTime(void)// 开始测量耗时 { QueryPerformanceCounter(&iStartTestTime);//开始计时 } double StopTestTime(int iTimeUnit)// 测量耗时 { _LARGE_INTEGER iStopTime; double fRetTime; QueryPerformanceCounter(&iStopTime);// 读停止时间 switch (iTimeUnit) { case 0: fRetTime = (double)(iStopTime.QuadPart - iStartTestTime.QuadPart); // ns break; case 1: fRetTime = (double)((iStopTime.QuadPart - iStartTestTime.QuadPart) / (g_iSysFrequency.QuadPart / 1000000)); // us break; case 2: fRetTime = (double)((iStopTime.QuadPart - iStartTestTime.QuadPart) / (g_iSysFrequency.QuadPart / 1000)); // ms break; case 3: fRetTime = (double)((iStopTime.QuadPart - iStartTestTime.QuadPart) / g_iSysFrequency.QuadPart); // S break; } return fRetTime; } void COpenCL::SelectedPlatform(void)//选择平台 { cl_uint PlatformCount; //平台数 cl_platform_id *pTotalPlatformtID;//所有平台数ID // 获取平台数目 Err = clGetPlatformIDs(0, 0, &PlatformCount);// 获取平台数 CheckErr(Err, "错误: OpenCL获取平台数错误!"); if (PlatformCount > 0) { cout << "可用平台数量: " << PlatformCount << endl; } else { printf(" 错误: 没有可用OpenCL平台! "); system("pause"); exit(0); } // 获取所有平台ID pTotalPlatformtID = new cl_platform_id[PlatformCount];//动态创建所有平台ID数组 Err = clGetPlatformIDs(PlatformCount, pTotalPlatformtID, NULL);//获取所有平台ID(列表) CheckErr(Err, "错误: OpenCL获取所有平台ID错误。 "); // 列出所有平台名称 printf(" "); cout << "所有平台的名称: "; for (cl_uint i = 0; i < PlatformCount; ++i) { // 获取平台名称的长度 size_t Platform_Name_Length; Err = clGetPlatformInfo(pTotalPlatformtID[i], CL_PLATFORM_NAME, 0, 0, &Platform_Name_Length);// 获取平台名称字符长度 CheckErr(Err, "获取OpenCL平台名称长度错误。 "); // 获取平台名称 char *Platform_Name = new char[Platform_Name_Length];//动态创建各平台名称字符串数组的长度 Err = clGetPlatformInfo(pTotalPlatformtID[i], CL_PLATFORM_NAME, Platform_Name_Length, Platform_Name, 0);// 获取平台名称 CheckErr(Err, "错误: 获取平台名称失败。 "); cout << " [" << i << "] " << Platform_Name << " ";// 输出平台名称 Selected_Platform_ID = pTotalPlatformtID[0];//总是选第一个 delete[] Platform_Name; } delete[] pTotalPlatformtID; } void COpenCL::CreateDevice(void)// 创建GPU设备 { Err = clGetDeviceIDs(Selected_Platform_ID, CL_DEVICE_TYPE_GPU, 1, &DevicesID, NULL);//获得GPU设备数量 CheckErr(Err, "错误: OpenCL创建GPU设备失败!"); } void COpenCL::CreateContext(void)// 创建设备管理 { Context = clCreateContext(0, 1, &DevicesID, NULL, NULL, &Err); CheckErr(Err, "错误: OpenCL创建设备环境失败!"); } void COpenCL::CreateCommandQueue(void)// 创建命令队列 { CommandQueue = clCreateCommandQueue(Context, DevicesID, 0, &Err); CheckErr(Err, "错误: OpenCL创建命令队列失败!"); } void COpenCL::GetProgramBuildInfo(void)// 获取异构(设备)编译程序信息 { char* build_log; size_t log_size; clGetProgramBuildInfo(Program, DevicesID, CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size);// 获取编译信息长度 build_log = new char[log_size + 1]; clGetProgramBuildInfo(Program, DevicesID, CL_PROGRAM_BUILD_LOG, log_size, build_log, NULL);// 查询编译信息 build_log[log_size] = ‘ ‘; printf(" 异构(设备)编译信息: "); cout << build_log << endl; delete[] build_log; } //--------------------------------------------------------------------------- void COpenCL::Init(void)// 初始化 { SelectedPlatform();// 选择平台 CreateDevice();// 创建GPU设备 CreateContext();// 创建设备管理 CreateCommandQueue();// 创建命令队列 } void COpenCL::CreateBuffer(void)// 创建缓冲区 { for (int i = 0; i < Size; i++)//初始化测试数据 { nums1_h[i] = nums2_h[i] = (float)i; } //创建设备缓冲区 StartTestTime(); nums1_d = clCreateBuffer(Context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, mem_size, nums1_h, &Err);//nums1_d设备输入 nums2_d = clCreateBuffer(Context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, mem_size, nums2_h, &Err);//nums2_d设备输入 sum_d = clCreateBuffer(Context, CL_MEM_WRITE_ONLY, mem_size, NULL, &Err);//sum_d设备输出 cout << " CPU:传输数据到GPU耗时: " << StopTestTime(2) << " ms" << endl; if (nums1_d == 0 || nums2_d == 0 || sum_d == 0) { delete[] nums1_h; delete[] nums2_h; delete[] sum_h; clReleaseMemObject(nums1_d); clReleaseMemObject(nums2_d); clReleaseMemObject(sum_d); clReleaseCommandQueue(CommandQueue); clReleaseContext(Context); printf(" 错误:OpenCL创建设备缓冲区失败! "); system("pause"); exit(1);//退出 } } void COpenCL::CreateProgramSource(void)// 创建异构源代码 { size_t Src_size[] = { strlen(RunAsGpu_Source) };//读入源代码数组 Program = clCreateProgramWithSource(Context, 1, &RunAsGpu_Source, Src_size, &Err);// 输入设备源程序 CheckErr(Err, "错误: OpenCL输入设备源程序失败!"); // 编译程序对象(编译异构源代码) Err = clBuildProgram(Program, 1, &DevicesID, NULL, NULL, NULL);// 编译设备源程序 CheckErr(Err, "错误: OpenCL编译设备源程序失败!"); // 创建设备(核)程序函数 RunAsGpu RunAsGpu = clCreateKernel(Program, "RunAsGpu_Source", &Err);// 创建核函数 if (Err != CL_SUCCESS) { delete[] nums1_h; delete[] nums2_h; delete[] sum_h; clReleaseMemObject(nums1_d); clReleaseMemObject(nums2_d); clReleaseMemObject(sum_d); clReleaseCommandQueue(CommandQueue); clReleaseContext(Context); clReleaseKernel(RunAsGpu); printf(" 错误:OpenCL创建核函数失败! "); system("pause"); exit(1);//退出 } GetProgramBuildInfo();// 获取异构(设备)编译程序信息 } void COpenCL::SetKernelArg(void)// 设置核参数 { Err = clSetKernelArg(RunAsGpu, 0, sizeof(cl_mem), &nums1_d); Err |= clSetKernelArg(RunAsGpu, 1, sizeof(cl_mem), &nums2_d); Err |= clSetKernelArg(RunAsGpu, 2, sizeof(cl_mem), &sum_d); CheckErr(Err, "错误: OpenCL输入设备(核)程序函数 RunAsGpu 形参失败!"); } void COpenCL::RunGPU(void)// 运行GPU { StartTestTime(); Err = clEnqueueNDRangeKernel(CommandQueue, RunAsGpu, 1, NULL, &global_work_size, NULL, 0, NULL, NULL);//运行核函数 CheckErr(Err, "错误: OpenCL核运算失败!"); cout << "GPU 计算耗时: " << StopTestTime(0) << " ns" << endl; StartTestTime(); clEnqueueReadBuffer(CommandQueue, sum_d, CL_TRUE, 0, mem_size, gpu_sum, 0, NULL, NULL);//读设备缓冲区 cout << "CPU 读回数据耗时: " << StopTestTime(2) << " ms" << endl; } void COpenCL::Close(void)// 关闭,释放资源 { delete[] gpu_sum; delete[] nums1_h; delete[] nums2_h; delete[] sum_h; clReleaseMemObject(nums1_d); clReleaseMemObject(nums2_d); clReleaseMemObject(sum_d); clReleaseCommandQueue(CommandQueue); clReleaseContext(Context); clReleaseKernel(RunAsGpu); } //--------------------------------------------------------------------------- int main() { COpenCL OpenCL; QueryPerformanceFrequency(&g_iSysFrequency);//读系统频率 OpenCL.Init(); OpenCL.CreateBuffer(); OpenCL.CreateProgramSource(); OpenCL.SetKernelArg(); OpenCL.RunGPU(); StartTestTime(); OpenCL.RunAsCpu(OpenCL.nums1_h, OpenCL.nums2_h, OpenCL.sum_h, OpenCL.Size);// 运行CPU函数 cout << " CPU 计算耗时: " << StopTestTime(2) << " ms" << endl; if (memcmp(OpenCL.sum_h, OpenCL.gpu_sum, OpenCL.Size * sizeof(float)) == 0)// 比较结果,数值比较 { printf(" 比较GPU和CPU计算数值正确。 "); } else { printf(" 比较GPU和CPU计算数值错误! "); system("pause"); exit(1);//退出 } OpenCL.Close();// 关闭,释放资源 // 殿后处理 printf(" "); printf("运行成功! "); printf(" "); system("pause"); }
在 Microsoft Visual C++ 2017 控制台调试通过。
以上是关于封装OpenCL类的主要内容,如果未能解决你的问题,请参考以下文章
VSCode自定义代码片段14——Vue的axios网络请求封装
VSCode自定义代码片段14——Vue的axios网络请求封装