东方耀AI技术分享

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 2705|回复: 0
打印 上一主题 下一主题

[C/C++] 数组之和_opencl实现示例

[复制链接]

1365

主题

1856

帖子

1万

积分

管理员

Rank: 10Rank: 10Rank: 10

积分
14449
QQ
跳转到指定楼层
楼主
发表于 2021-7-28 10:04:03 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式



数组之和_opencl实现示例


  1. CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
  2. PROJECT(main_cl)
  3. #FIND_PACKAGE(CUDA REQUIRED)
  4. FIND_PACKAGE(OpenCL REQUIRED)
  5. ADD_EXECUTABLE(main_cl 数组之和_opencl实现.cpp)
  6. #TARGET_LINK_LIBRARIES(main_cl)
  7. #target_link_libraries(main_cl -lboost_system -lboost_thread)
  8. target_link_libraries(main_cl OpenCL)

  9. #Looking for CL_VERSION_1_2 - found
  10. #Found OpenCL: /usr/lib/x86_64-linux-gnu/libOpenCL.so (found version "1.2")
复制代码

  1. __kernel void hello_kernel(__global const float *a,
  2.         __global const float *b,
  3.         __global float *result)
  4. {
  5.         int gid = get_global_id(0);

  6.         result[gid] = a[gid] + b[gid];
  7. }
复制代码


  1. #include <iostream>
  2. #include <fstream>
  3. #include <sstream>
  4. #include <CL/cl.h>

  5. const int ARRAY_SIZE = 1000;

  6. //https://blog.csdn.net/jaccen2012/article/details/78810546

  7. //一、 选择OpenCL平台并创建一个上下文
  8. cl_context CreateContext()
  9. {
  10.         cl_int errNum;
  11.         cl_uint numPlatforms;
  12.         cl_platform_id firstPlatformId;
  13.         cl_context context = NULL;

  14.         //选择可用的平台中的第一个
  15.         errNum = clGetPlatformIDs(1, &firstPlatformId, &numPlatforms);
  16.         if (errNum != CL_SUCCESS || numPlatforms <= 0)
  17.         {
  18.                 std::cerr << "Failed to find any OpenCL platforms." << std::endl;
  19.                 return NULL;
  20.         }

  21.         std::cerr << "发现的openCL平台数目=" << numPlatforms << std::endl;

  22.         //创建一个OpenCL上下文环境
  23.         cl_context_properties contextProperties[] =
  24.         {
  25.                 CL_CONTEXT_PLATFORM,
  26.                 (cl_context_properties)firstPlatformId,
  27.                 0
  28.         };
  29.         context = clCreateContextFromType(contextProperties, CL_DEVICE_TYPE_GPU,
  30.                 NULL, NULL, &errNum);

  31.         return context;
  32. }


  33. //二、 创建设备并创建命令队列
  34. cl_command_queue CreateCommandQueue(cl_context context, cl_device_id *device)
  35. {
  36.         cl_int errNum;
  37.         cl_device_id *devices;
  38.         cl_command_queue commandQueue = NULL;
  39.         size_t deviceBufferSize = -1;

  40.         // 获取设备缓冲区大小
  41.         errNum = clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &deviceBufferSize);

  42.         if (deviceBufferSize <= 0)
  43.         {
  44.                 std::cerr << "No devices available.";
  45.                 return NULL;
  46.         }

  47.         std::cout << "设备缓冲区大小=" << deviceBufferSize << std::endl;

  48.         // 为设备分配缓存空间
  49.         devices = new cl_device_id[deviceBufferSize / sizeof(cl_device_id)];
  50.         errNum = clGetContextInfo(context, CL_CONTEXT_DEVICES, deviceBufferSize, devices, NULL);

  51.         //选取可用设备中的第一个
  52.         commandQueue = clCreateCommandQueue(context, devices[0], 0, NULL);

  53.         *device = devices[0];
  54.         delete[] devices;
  55.         return commandQueue;
  56. }


  57. // 三、创建和构建程序对象
  58. cl_program CreateProgram(cl_context context, cl_device_id device, const char* fileName)
  59. {
  60.         cl_int errNum;
  61.         cl_program program;
  62.     std::cout << "文件名(这里要用绝对路径):" << fileName << std::endl;
  63.         // 并行计算:两个数组求和
  64.         std::ifstream kernelFile(fileName, std::ios::in);

  65.         //如果打开操作失败,open函数的返回值为0(假),
  66.         //如果是用调用构造函数的方式打开文件的,则流对象的值为0。可以据此测试打开是否成功

  67.         if (!kernelFile.is_open())
  68.         {
  69.                 std::cerr << "打开文件失败了: " << fileName << std::endl;
  70.                 return NULL;
  71.         }

  72.         std::ostringstream oss;   // 输出的字符串流
  73.         oss << kernelFile.rdbuf();  // 这个api干啥的?

  74.         std::string srcStdStr = oss.str();
  75.         const char *srcStr = srcStdStr.c_str();
  76.         // 用源码创建并行的程序
  77.         program = clCreateProgramWithSource(context, 1,
  78.                 (const char**)&srcStr,
  79.                 NULL, NULL);

  80.         errNum = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);

  81.         return program;
  82. }

  83. //创建和构建程序对象
  84. bool CreateMemObjects(cl_context context, cl_mem memObjects[3],
  85.         float *a, float *b)
  86. {
  87.         memObjects[0] = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
  88.                 sizeof(float) * ARRAY_SIZE, a, NULL);
  89.         memObjects[1] = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
  90.                 sizeof(float) * ARRAY_SIZE, b, NULL);
  91.         memObjects[2] = clCreateBuffer(context, CL_MEM_READ_WRITE,
  92.                 sizeof(float) * ARRAY_SIZE, NULL, NULL);
  93.         return true;
  94. }


  95. // 释放OpenCL资源
  96. void Cleanup(cl_context context, cl_command_queue commandQueue,
  97.         cl_program program, cl_kernel kernel, cl_mem memObjects[3])
  98. {
  99.         for (int i = 0; i < 3; i++)
  100.         {
  101.                 if (memObjects[i] != 0)
  102.                         clReleaseMemObject(memObjects[i]);
  103.         }
  104.         if (commandQueue != 0)
  105.                 clReleaseCommandQueue(commandQueue);

  106.         if (kernel != 0)
  107.                 clReleaseKernel(kernel);

  108.         if (program != 0)
  109.                 clReleaseProgram(program);

  110.         if (context != 0)
  111.                 clReleaseContext(context);
  112. }

  113. //数组之和_opencl实现示例
  114. int main(int argc, char** argv)
  115. {
  116.         cl_context context = 0;
  117.         cl_command_queue commandQueue = 0;
  118.         cl_program program = 0;
  119.         cl_device_id device = 0;
  120.         cl_kernel kernel = 0;
  121.         cl_mem memObjects[3] = { 0, 0, 0 };
  122.         cl_int errNum;

  123.         // 一、选择OpenCL平台并创建一个上下文
  124.         context = CreateContext();

  125.         // 二、 创建设备并创建命令队列
  126.         commandQueue = CreateCommandQueue(context, &device);

  127.         //创建和构建程序对象
  128.         program = CreateProgram(context, device, "/home/jiang/jjj_opencl_works/HelloWorld.cl");

  129.         // 四、 创建OpenCL内核并分配内存空间
  130.         kernel = clCreateKernel(program, "hello_kernel", NULL);

  131.         //创建要处理的数据
  132.         float result[ARRAY_SIZE];
  133.         float a[ARRAY_SIZE];
  134.         float b[ARRAY_SIZE];
  135.         for (int i = 0; i < ARRAY_SIZE; i++)
  136.         {
  137.                 a[i] = (float)i;
  138.                 b[i] = (float)(ARRAY_SIZE - i);
  139.         }

  140.         //创建内存对象
  141.         if (!CreateMemObjects(context, memObjects, a, b))
  142.         {
  143.                 Cleanup(context, commandQueue, program, kernel, memObjects);
  144.                 return 1;
  145.         }

  146.         // 五、 设置内核数据并执行内核
  147.         errNum = clSetKernelArg(kernel, 0, sizeof(cl_mem), &memObjects[0]);
  148.         errNum |= clSetKernelArg(kernel, 1, sizeof(cl_mem), &memObjects[1]);
  149.         errNum |= clSetKernelArg(kernel, 2, sizeof(cl_mem), &memObjects[2]);

  150.         size_t globalWorkSize[1] = { ARRAY_SIZE };
  151.         size_t localWorkSize[1] = { 1 };

  152.         errNum = clEnqueueNDRangeKernel(commandQueue, kernel, 1, NULL,
  153.                 globalWorkSize, localWorkSize,
  154.                 0, NULL, NULL);

  155.         // 六、 读取执行结果并释放OpenCL资源
  156.         errNum = clEnqueueReadBuffer(commandQueue, memObjects[2], CL_TRUE,
  157.                 0, ARRAY_SIZE * sizeof(float), result,
  158.                 0, NULL, NULL);

  159.         std::cout << "程序执行计算结果:" << std::endl;
  160.         for (int i = 0; i < ARRAY_SIZE; i++)
  161.         {
  162.                 std::cout << result[i] << " ";
  163.         }
  164.         std::cout << std::endl;
  165.         std::cout << "Executed program succesfully." << std::endl;
  166.         getchar();
  167.         Cleanup(context, commandQueue, program, kernel, memObjects);

  168.         return 0;
  169. }
复制代码




opencl88.png (47.59 KB, 下载次数: 90)

opencl88.png
让天下人人学会人工智能!人工智能的前景一片大好!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|人工智能工程师的摇篮 ( 湘ICP备2020019608号-1 )

GMT+8, 2024-6-16 00:01 , Processed in 0.190822 second(s), 21 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表