GPU的OPENCL编程1(基础知识和初始化)

  • Post author:
  • Post category:其他




OPENCL 简单介绍

OpenCL是一个为异构平台编写程序的框架,此异构平台可由CPU、GPU或其他类型的处理器组成。通过OpenCL可以通过GPU的并行加速,不过OpenCL的编程思路和标准C语言串行执行有很大区别。OpenCL使用了kernel函数,kernels并行运行在GPU上。



GPU单元和Host关系

在这里插入图片描述

上图对SOC的GPU计算单元的关系理解有很大帮助.

Processing Element:GPU的最小计算单元,一般CPU大概就几个到十几个计算单元,但是GPU可能有几百个不过GPU的计算单元比CPU的简单,适合做定工作综合能力比CPU差很多。Opencl的kernel就是运行在这个计算单元上。多个单元组合在一起共享一个GPU 的内部RAM和workloaddistributor。

Compute Unit:由于设计运行效率的原因Processing Element不能并行多个集成在一起,所以将一定数量的Processing Element集合成Compute Unit,再连接在总线上对外通信形成一个计算节点总合。下图AMD GPU中CU就是计算单元,组成CU Array 也就是Compute Unit,设计Compute Unit可以是1个或者多个。

多个Processing Element再组成芯片。

在这里插入图片描述

Compute Device :图中的HOST可以理解为PC或者是个性能较强的ARM对于,Compute Device可以理解为一块板卡上有一个带GPU加速芯片的PCIE板卡。

在Opencl程序获取平台信息时会有Processing Element、Compute Unit、Compute Device相关的概念,在SOC中GPU因为功耗等因数限制一般总的Processing Element数量不多。而且有的芯片有使用2组Compute Unit用于做不同的计算,每组的Processing Element数量还可以不一样。



OpenCL的基础

OpenCL支持大量不同类型的应用。无论哪一种情况,面向异构平台的应用都必须完成以下步骤:

① 发现构成异构系统的组件;

② 探查这些组件的特征,使软件能够适应不同硬件单元的特定特性;

③ 创建将在平台上运行的指令块(内核);

④ 建立并管理计算中涉及的内存对象;

⑤ 在系统中正确的组件上按正确的顺序执行内核;

⑥ 收集最终结果。

这些步骤通过OpenCL中的一系列API再加上一个面向内核的编程环境来完成。我们将采用一种“分而治之”的策略解释以上步骤的所有工作。我们把问题分解为一下模型:

① 平台模型(platform model):异构系统的高层描述。

② 执行模型(execution model):指令流在异构平台上执行的抽象表示。

③ 内存模型(memory model):OpenCL中的内存区域集合以及一个OpenCL计算期间这些内存区域如何交互。

编程模型(programming model):程序员设计算法来实现一个应用时使用的高层抽象



Opencl CONTEXT 上下文

上下文是 OpenCL 应用程序的核心。上下文提供关联设备、内存对象(例如,缓冲区和图像)和命令队列(提供上下文和单个设备之间的接口)。它是驱动与特定设备以及特定设备之间的通信的上下文,而 OpenCL 定义了它的内存这些方面的模型。每个上下文都从不同的平台创建,并在整个平台上分发工作给相关设备。 OpenCL 内存对象不能被不同的上下文共享,也不能被创建来自相同或不同的平台。 必须软件控制跨上下文之间数据共享。

一般而言,应用程序的 OpenCL 用法类似于以下内容:

1.查询存在哪些平台。

2.查询各平台支持的设备集合:一种。选择使用 clGetDeviceInfo() 在特定设备上选择设备能力。

3.从选择的设备中创建上下文(每个上下文必须使用来自单个平台的设备创建);然后使用上下文,您可以一种。

a.创建一个或多个命令队列

b.创建在一个或多个关联设备上运行的程序

c.从这些程序创建内核

d.分配内存缓冲区和图像,无论是在主机上还是在设备)

e.从特定设备写入或复制数据

f.将内核(设置适当的参数)提交到命令队列以供执行
在这里插入图片描述

上面的东西不太好理解,就简单的用一小段OPENCL的初始化程序说明一下就能明白。平台

bool init(){

   /* Get the available platform. */
    errNum = clGetPlatformIDs(1, &platform, NULL);//获取平台信息 相当于Compute  Device信息
    clmCHECKERROR(errNum, CL_SUCCESS);
    /* Get a GPU device. */
    errNum = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, NULL);//获取设备信息,也就是计算单元Processing Element或者Compute Unit信息。
    clmCHECKERROR(errNum, CL_SUCCESS);
    /* Create the context. */
    context = clCreateContext(0, 1, &device,  &oclContextCallback, NULL, &errNum);//创建计算设备上下文
    clmCHECKERROR(errNum, CL_SUCCESS);
    /* Create a command-queue. */
    commandQueue = clCreateCommandQueue(context, device, 0, &errNum);//创建第一个计算队列
    clmCHECKERROR(errNum, CL_SUCCESS);
    /* Create a command-queue. */
    printf("Running cl_matrix_op\n");
    printf("Creating program...\n");
    size_t sourceLength = strlen(programSources);
    program = clCreateProgramWithSource(context,1,(const char **)&programSources,&sourceLength,                &errNum);//为上下文创建程序对象,并将字符串数组中programSources指定的源代码加载到程序对象中。与程序对象关联的设备是与context关联的设备。
    clmCHECKERROR(errNum, CL_SUCCESS);
    printf("Building program...\n");
    errNum = clBuildProgram(program, 0, NULL, "-cl-fast-relaxed-math", NULL, NULL);//编译创建的OPENCL程序
    clmCHECKERROR(errNum, CL_SUCCESS);
    printf("Creating kernel...\n");
    kernel = clCreateKernel(program, "matrix", &errNum);//创建内核
    clmCHECKERROR(errNum, CL_SUCCESS);

    return 1;
}

初始化基本都是这个套路,初始化后就可以进行clCreateBuffer 建立读写缓存,clSetKernelArg设置内核参数,clEnqueueNDRangeKernel运行内核,clEnqueueReadBuffer读取结果数据等工作。



版权声明:本文为qq_42254853原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。