首页 数据库 mysql教程 OpenCL 学习step by step (2) 一个简单的OpenCL的程序

OpenCL 学习step by step (2) 一个简单的OpenCL的程序

Jun 07, 2016 pm 03:36 PM
step 学习 我们 现在 程序 简单

现在,我们开始写一个简单的OpenCL程序,计算两个数组相加的和,放到另一个数组中去。程序用CPU和GPU分别计算,最后验证它们是否相等。OpenCL程序的流程大致如下: 下面是source code中的主要代码: int main(int argc, char* argv[]) { //在host内存中创建

现在,我们开始写一个简单的OpenCL程序,计算两个数组相加的和,放到另一个数组中去。程序用CPU和GPU分别计算,最后验证它们是否相等。OpenCL程序的流程大致如下:

OpenCL 学习step by step (2) 一个简单的OpenCL的程序

下面是source code中的主要代码:

int main(int argc, char* argv[])

    {

    //在host内存中创建三个缓冲区

    float *buf1 = 0;

    float *buf2 = 0;

    float *buf = 0;

    buf1 =(float *)malloc(BUFSIZE * sizeof(float));

    buf2 =(float *)malloc(BUFSIZE * sizeof(float));

    buf =(float *)malloc(BUFSIZE * sizeof(float));

    //用一些随机值初始化buf1和buf2的内容

    int i;

    srand( (unsigned)time( NULL ) );

    for(i = 0; i

        buf1[i] = rand()%65535;

    srand( (unsigned)time( NULL ) +1000);

    for(i = 0; i

        buf2[i] = rand()%65535;

    //cpu计算buf1,buf2的和

    for(i = 0; i

        buf[i] = buf1[i] + buf2[i];

    cl_uint status;

    cl_platform_id platform;

    //创建平台对象

    status = clGetPlatformIDs( 1, &platform, NULL );

注意:如果我们系统中安装不止一个opencl平台,比如我的os中,有intel和amd两家opencl平台,用上面这行代码,有可能会出错,因为它得到了intel的opencl平台,而intel的平台只支持cpu,而我们后面的操作都是基于gpu,这时我们可以用下面的代码,得到AMD的opencl平台。

cl_uint numPlatforms;<p>std::string platformVendor;</p><p>status = clGetPlatformIDs(0, NULL, &numPlatforms);</p><p><span>if</span>(status != CL_SUCCESS)</p><p>{</p><p><span>return</span> 0;</p><p>}</p><p><span>if</span> (0 </p><p>{</p><p>cl_platform_id* platforms = <span>new</span> cl_platform_id[numPlatforms];</p><p>status = clGetPlatformIDs(numPlatforms, platforms, NULL);</p><p><span>char</span> platformName[100];</p><p><span>for</span> (<span>unsigned</span> i = 0; i </p><p>{</p><p>status = clGetPlatformInfo(platforms[i],</p><p>CL_PLATFORM_VENDOR,</p><p><span>sizeof</span>(platformName),</p><p>platformName,</p><p>NULL);</p><p>platform = platforms[i];</p><p>platformVendor.assign(platformName);</p><p><span>if</span> (!strcmp(platformName, <span>"Advanced Micro Devices, Inc."</span>))</p><p>{</p><p><span>break</span>;</p><p>}</p><p>}</p><p>std::cout "Platform found : " "\n";</p><p><span>delete</span>[] platforms;</p><p>}</p>
登录后复制

    cl_device_id device;

    //创建GPU设备

   clGetDeviceIDs( platform, CL_DEVICE_TYPE_GPU,  1,  &device,  NULL);

    //创建context

   cl_context context = clCreateContext( NULL,  1,  &device,  NULL, NULL, NULL);

    //创建命令队列

    cl_command_queue queue = clCreateCommandQueue( context,

        device,

        CL_QUEUE_PROFILING_ENABLE, NULL );

    //创建三个OpenCL内存对象,并把buf1的内容通过隐式拷贝的方式

    //拷贝到clbuf1,buf2的内容通过显示拷贝的方式拷贝到clbuf2

    cl_mem clbuf1 = clCreateBuffer(context,

        CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,

        BUFSIZE*sizeof(cl_float),buf1,

        NULL );

    cl_mem clbuf2 = clCreateBuffer(context,

        CL_MEM_READ_ONLY ,

        BUFSIZE*sizeof(cl_float),NULL,

        NULL );

   cl_event writeEvt;

    status = clEnqueueWriteBuffer(queue, clbuf2, 1, 0, BUFSIZE*sizeof(cl_float), buf2, 0, 0, 0);

上面这行代码把buf2中的内容拷贝到clbuf2,因为buf2位于host端,clbuf2位于device端,所以这个函数会执行一次host到device的传输操作,或者说一次system memory到video memory的拷贝操作,所以我在该函数的后面放置了clFush函数,表示把command queue中的所有命令提交到device(注意:该命令并不保证命令执行完成),所以我们调用函数waitForEventAndRelease来等待write缓冲的完成,swaitForEventAndReleae 是一个用户定义的函数,它的内容如下,主要代码就是通过event来查询我们的操作是否完成,没完成的话,程序就一直block在这行代码处,另外我们也可以用opencl中内置的函数clWaitForEvents来代替clFlush和swaitForEventAndReleae。

<span>//等待事件完成</span><p><span>int</span> waitForEventAndRelease(cl_event *event)</p><p>{</p><p>cl_int status = CL_SUCCESS;</p><p>cl_int eventStatus = CL_QUEUED;</p><p><span>while</span>(eventStatus != CL_COMPLETE)</p><p>{</p><p>status = clGetEventInfo(</p><p>*event,</p><p>CL_EVENT_COMMAND_EXECUTION_STATUS,</p><p><span>sizeof</span>(cl_int),</p><p>&eventStatus,</p><p>NULL);</p><p>}</p><p>status = clReleaseEvent(*event);</p><p><span>return</span> 0;</p><p>}</p>
登录后复制

     status = clFlush(queue);

     //等待数据传输完成再继续往下执行

     waitForEventAndRelease(&writeEvt);

    cl_mem buffer = clCreateBuffer( context,

        CL_MEM_WRITE_ONLY,

        BUFSIZE * sizeof(cl_float),

        NULL, NULL );

kernel文件中放的是gpu中执行的代码,它被放在一个单独的文件add.cl中,本程序中kernel代码非常简单,只是执行两个数组相加。kernel的代码为:

__kernel <span>void</span> vecadd(__global <span>const</span> <span>float</span>* A, __global <span>const</span> <span>float</span>* B, __global <span>float</span>* C)<p>{</p><p><span>int</span> id = get_global_id(0);</p><p>C[id] = A[id] + B[id];</p><p>}</p>
登录后复制

   //kernel文件为add.cl

    const char * filename  = "add.cl"

    std::string  sourceStr;

    status = convertToString(filename, sourceStr);

convertToString也是用户定义的函数,该函数把kernel源文件读入到一个string中,它的代码如下:

<span>//把文本文件读入一个string中,用来读入kernel源文件</span><p><span>int</span> convertToString(<span>const</span> <span>char</span> *filename, std::string& s)</p><p>{</p><p>size_t size;</p><p><span>char</span>*  str;</p><p>std::fstream f(filename, (std::fstream::in | std::fstream::binary));</p><p><span>if</span>(f.is_open())</p><p>{</p><p>size_t fileSize;</p><p>f.seekg(0, std::fstream::end);</p><p>size = fileSize = (size_t)f.tellg();</p><p>f.seekg(0, std::fstream::beg);</p><p>str = <span>new</span> <span>char</span>[size+1];</p><p><span>if</span>(!str)</p><p>{</p><p>f.close();</p><p><span>return</span> NULL;</p><p>}</p><p>f.read(str, fileSize);</p><p>f.close();</p><p>str[size] = <span>'\0'</span>;</p><p>s = str;</p><p><span>delete</span>[] str;</p><p><span>return</span> 0;</p><p>}</p><p>printf(<span>"Error: Failed to open file %s\n"</span>, filename);</p><p><span>return</span> 1;</p><p>}</p>
登录后复制

    const char * source    = sourceStr.c_str();

    size_t sourceSize[]    = { strlen(source) };

    //创建程序对象

    cl_program program = clCreateProgramWithSource(  context,  1,  &source,  sourceSize,  NULL);

    //编译程序对象

    status = clBuildProgram( program, 1, &device, NULL, NULL, NULL );

    if(status != 0)

        {

        printf("clBuild failed:%d\n", status);

        char tbuf[0x10000];

        clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0x10000, tbuf, NULL);

        printf("\n%s\n", tbuf);

        return -1;

        }

    //创建Kernel对象

    cl_kernel kernel = clCreateKernel( program, "vecadd", NULL );

    //设置Kernel参数

    cl_int clnum = BUFSIZE;

    clSetKernelArg(kernel, 0, sizeof(cl_mem), (void*) &clbuf1);

    clSetKernelArg(kernel, 1, sizeof(cl_mem), (void*) &clbuf2);

    clSetKernelArg(kernel, 2, sizeof(cl_mem), (void*) &buffer);

注意:在执行kernel时候,我们只设置了global work items数量,没有设置group size,这时候,系统会使用默认的work group size,通常可能是256之类的。

    //执行kernel,Range用1维,work itmes size为BUFSIZE

    cl_event ev;

    size_t global_work_size = BUFSIZE;

    clEnqueueNDRangeKernel( queue,  kernel,  1,  NULL,  &global_work_size,  NULL, 0, NULL, &ev);

   status = clFlush( queue );

   waitForEventAndRelease(&ev);

    //数据拷回host内存

    cl_float *ptr;

    cl_event mapevt;

    ptr = (cl_float *) clEnqueueMapBuffer( queue,  buffer,  CL_TRUE,  CL_MAP_READ,  0,  BUFSIZE * sizeof(cl_float),  0, NULL, NULL, NULL );

   status = clFlush( queue );

   waitForEventAndRelease(&mapevt);

   

    //结果验证,和cpu计算的结果比较

    if(!memcmp(buf, ptr, BUFSIZE))

        printf("Verify passed\n");

    else printf("verify failed");

    if(buf)

        free(buf);

    if(buf1)

        free(buf1);

    if(buf2)

        free(buf2);

程序结束后,这些opencl对象一般会自动释放,但是为了程序完整,养成一个好习惯,这儿我加上了手动释放opencl对象的代码。

    //删除OpenCL资源对象

    clReleaseMemObject(clbuf1);

    clReleaseMemObject(clbuf2);

    clReleaseMemObject(buffer);

    clReleaseProgram(program);

    clReleaseCommandQueue(queue);

    clReleaseContext(context);

    return 0;

    }

程序执行后的界面如下:

OpenCL 学习step by step (2) 一个简单的OpenCL的程序

完整的代码请参考:

工程文件gclTutorial1

代码下载:http://files.cnblogs.com/mikewolf2002/gclTutorial.zip

原文作者:迈克老狼

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何在iPhone中使Google地图成为默认地图 如何在iPhone中使Google地图成为默认地图 Apr 17, 2024 pm 07:34 PM

iPhone上的默认地图是Apple专有的地理位置提供商“地图”。尽管地图越来越好,但它在美国以外的地区运行不佳。与谷歌地图相比,它没有什么可提供的。在本文中,我们讨论了使用Google地图成为iPhone上的默认地图的可行性步骤。如何在iPhone中使Google地图成为默认地图将Google地图设置为手机上的默认地图应用程序比您想象的要容易。请按照以下步骤操作–先决条件步骤–您必须在手机上安装Gmail。步骤1–打开AppStore。步骤2–搜索“Gmail”。步骤3–点击Gmail应用旁

最简便的硬盘序列号查询方式 最简便的硬盘序列号查询方式 Feb 26, 2024 pm 02:24 PM

硬盘序列号是硬盘的一个重要标识,通常用于唯一标识硬盘以及进行硬件识别。在某些情况下,我们可能需要查询硬盘序列号,比如在安装操作系统、查找正确设备驱动程序或进行硬盘维修等情况下。本文将介绍一些简单的方法,帮助大家查询硬盘序列号。方法一:使用Windows命令提示符打开命令提示符。在Windows系统中,按下Win+R键,输入"cmd"并按下回车键即可打开命

iPhone中缺少时钟应用程序:如何修复 iPhone中缺少时钟应用程序:如何修复 May 03, 2024 pm 09:19 PM

您的手机中缺少时钟应用程序吗?日期和时间仍将显示在iPhone的状态栏上。但是,如果没有时钟应用程序,您将无法使用世界时钟、秒表、闹钟等多项功能。因此,修复时钟应用程序的缺失应该是您的待办事项列表的首位。这些解决方案可以帮助您解决此问题。修复1–放置时钟应用程序如果您错误地从主屏幕中删除了时钟应用程序,您可以将时钟应用程序放回原位。步骤1–解锁iPhone并开始向左侧滑动,直到到达“应用程序库”页面。步骤2–接下来,在搜索框中搜索“时钟”。步骤3–当您在搜索结果中看到下方的“时钟”时,请按住它并

无法允许访问 iPhone 中的摄像头和麦克风 无法允许访问 iPhone 中的摄像头和麦克风 Apr 23, 2024 am 11:13 AM

您在尝试使用应用程序时是否收到“无法允许访问摄像头和麦克风”?通常,您可以在需要提供的基础上向特定对象授予摄像头和麦克风权限。但是,如果您拒绝权限,摄像头和麦克风将无法工作,而是显示此错误消息。解决这个问题是非常基本的,你可以在一两分钟内完成。修复1–提供相机、麦克风权限您可以直接在设置中提供必要的摄像头和麦克风权限。步骤1–转到“设置”选项卡。步骤2–打开“隐私与安全”面板。步骤3–在那里打开“相机”权限。步骤4–在里面,您将找到已请求手机相机权限的应用程序列表。步骤5–打开指定应用的“相机”

揭秘C语言的吸引力: 发掘程序员的潜质 揭秘C语言的吸引力: 发掘程序员的潜质 Feb 24, 2024 pm 11:21 PM

学习C语言的魅力:解锁程序员的潜力随着科技的不断发展,计算机编程已经成为了一个备受关注的领域。在众多编程语言中,C语言一直以来都备受程序员的喜爱。它的简单、高效以及广泛应用的特点,使得学习C语言成为了许多人进入编程领域的第一步。本文将讨论学习C语言的魅力,以及如何通过学习C语言来解锁程序员的潜力。首先,学习C语言的魅力在于其简洁性。相比其他编程语言而言,C语

一起学习word根号输入办法 一起学习word根号输入办法 Mar 19, 2024 pm 08:52 PM

在word中编辑文字内容时,有时会需要输入公式符号。有的小伙们不知道在word根号输入的方法,小面就让小编跟小伙伴们一起分享下word根号输入的方法教程。希望对小伙伴们有所帮助。首先,打开电脑上的Word软件,然后打开要编辑的文件,并将光标移动到需要插入根号的位置,参考下方的图片示例。2.选择【插入】,再选择符号里的【公式】。如下方的图片红色圈中部分内容所示:3.接着选择下方的【插入新公式】。如下方的图片红色圈中部分内容所示:4.选择【根式】,再选择合适的根号。如下方的图片红色圈中部分内容所示:

Pygame入门指南:全面安装和配置教程 Pygame入门指南:全面安装和配置教程 Feb 19, 2024 pm 10:10 PM

从零开始学习Pygame:完整的安装和配置教程,需要具体代码示例引言:Pygame是一个使用Python编程语言开发的开源游戏开发库,它提供了丰富的功能和工具,使得开发者可以轻松创建各种类型的游戏。本文将带您从零开始学习Pygame,并提供完整的安装和配置教程,以及具体的代码示例,让您快速入门。第一部分:安装Python和Pygame首先,确保您的计算机上已

脚本化诊断本机主机已停止工作[修复] 脚本化诊断本机主机已停止工作[修复] Mar 11, 2024 am 09:37 AM

在运行程序或进行故障排除时,如果出现指示脚本诊断本地主机已停止工作的错误消息,这可能是由于多种原因引起的。在Windows11/10PC上修复这个问题可能需要采取不同的方法,因为每台计算机的情况可能不同。一种常见的原因是脚本程序本身存在错误或损坏,导致其无法正常运行。解决这个问题的方法可能包括修复或重装脚本程序,或者尝试使用其他版本的脚本程序。另一种可能的原因是系统文件损坏或缺失,这可能会影响脚本的运行。在这种情况下,您可以尝试运行系统文件检查工具来修复任何受损的文件,或者进行系统恢复以恢复到之

See all articles