• 【并行计算-CUDA开发】Windows下opencl环境配置


    首先声明我这篇主要是根据下面网站的介绍, 加以修改和详细描述,一步一步在我自己的电脑上实现的,

    首先要将显卡驱动更新到最新版,以支持opencl 。 要看显卡支不支持opencl,可以下一个 GPU_Caps_Viewer_Setup  软件看一看

    首先要下载安装opencl库。我这里下载的是英特尔的。英伟达和AMD的也都差不多。
    首先下载INTEL版的opencl驱动:
    直接安装即可。
    然后下载intel版本的opencl开发工具包
    我这里默认安装到  G:Program FilesIntelOpenCL SDK  目录下。
    安装完成后  G:Program FilesIntelOpenCL SDK3.0  目录下出现以下文档 (include和lib等
    Windows下opencl环境配置

    安装好VC 2012
    Alt+F7 进行属性设置,或者建完项目后右键项目进行属性设置。
    新建Win控制台空项目。右键进行属性设置。

    在属性页里面找到“C/C++”的“常规”项,点击,右边有“附加包含目录”,然后编辑,添加目录:
    Windows下opencl环境配置



    .在属性页里面找到“连接器”,点击其“常规”项,右边有“附加库目录”,然后也是编辑,添加目录:
    Windows下opencl环境配置

     在输入选项只用,右边“附加依赖项”,编辑,添加lib文件:OpenCL.lib
    Windows下opencl环境配置

    这里要注意一点, 如果你用的是64位的系统的话,如果你把OpenCL.lib 的目录指定为......//lib/x64 的话,很很可能还是不能正常编译。这是因为
    A fresh install of Visual Studio (even 2010) uses 32-bit by default, so unless you've explicitly set your project to be 64-bit (in configuration manager -> platform -> x64) it will be 32-bit. 
    所以说如果编译不能正常通过的话试着把OpenCL.lib 的目录指定为......//lib/x86  或者......//lib/Win32 试试。
    但是目录还是C:Program Files  不是C:Program Files(x86)

    比如如果用NVDIA 的CUDA可以这样设定目录
    C:Program FilesNVIDIA GPU Computing ToolkitCUDAv7.0libWin32



    然后添加源文件,源文件如下:

     #include
     #include //包含CL的头文件
     using namespace std;
     
     //根据参数,判断设备类别。是CPU、GPU、ACCELERATOR或其他设备
     const char* GetDeviceType(cl_device_type it)
     {
         if(it == CL_DEVICE_TYPE_CPU)
             return "CPU";
         else if(it== CL_DEVICE_TYPE_GPU)
             return "GPU";
         else if(it==CL_DEVICE_TYPE_ACCELERATOR)
             return "ACCELERATOR";
         else
             return "DEFAULT";
      
     }
      
     int main()
     {
         char dname[512];
         cl_device_id devices[20];
         cl_platform_id* platform_id = NULL;
         cl_uint num_devices;
         cl_device_type int_type;
         cl_ulong long_entries;
         cl_uint num_platform;
         cl_int err;
      
         //查询系统上可用的计算平台,可以理解为初始化
         err = clGetPlatformIDs(0,NULL,&num_platform);
      
         if(err!=CL_SUCCESS)
         {
             cout<<"clGetPlatformIDs error"<<endl;
             return 0;
         }
      
         cout<<"PlatForm num:"<<num_platform<<endl;
      
        unsigned int st=0;
      
         platform_id = new cl_platform_id[num_platform];
      
         err = clGetPlatformIDs(num_platform,platform_id,NULL);
      
         if(err!=CL_SUCCESS)
         {
             cout<<"clGetPlatformIDs error"<<endl;
             return 0;
         }
      
     
    for(st=0;st
         {
             cout<<endl<<"----------------------------------"<<endl;
             cout<<"Platform "<<st+1<<endl;
      
             //获取可用计算平台的名称
             clGetPlatformInfo(platform_id[st],CL_PLATFORM_NAME,512,dname,NULL);
             cout<<"CL_PLATFORM_NAME:"<<dname<<endl;
      
             //获取可用计算平台的版本号,即OpenCL的版本号
             clGetPlatformInfo(platform_id[st],CL_PLATFORM_VENDOR,512,dname,NULL);
             cout<<"CL_PLATFORM_VERSION:"<<dname<<endl;
      
             //获取可用计算平台的设备数目
             clGetDeviceIDs(platform_id[st],CL_DEVICE_TYPE_ALL,20,devices,&num_devices);
             cout<<"Device num:"<<num_devices<<endl<<endl;
      
             unsigned int n=0;
      
             //循环两次,检测两个设备的属性
             for(n=0;n
             {
                 cout<<endl<<"Device "<<n+1<<endl;
                 //获取设备名称
                 clGetDeviceInfo(devices[n],CL_DEVICE_NAME,512,dname,NULL);
                 cout<<"Device :"<<dname<<endl;
      
                 //获取设备类别
                 clGetDeviceInfo(devices[n],CL_DEVICE_TYPE,sizeof(cl_device_type),&int_type,NULL);
                 cout<<"Device Type:"<<GetDeviceType(int_type)<<endl;
      
                 //获取设备版本号
                 clGetDeviceInfo(devices[n],CL_DRIVER_VERSION,512,dname,NULL);
                 cout<<"Device version:"<<dname<<endl;
      
                 //获取设备全局内存大小
                 clGetDeviceInfo(devices[n],CL_DEVICE_GLOBAL_MEM_SIZE,sizeof(cl_ulong),&long_entries,NULL);
                 cout<<"Device global mem(MB):"<<long_entries/1024/1024<<endl;
      
                 //获取设备CACHE内存大小
                 clGetDeviceInfo(devices[n],CL_DEVICE_GLOBAL_MEM_CACHE_SIZE,sizeof(cl_ulong),&long_entries,NULL);
                 cout<<"Device global mem cache(KB):"<<long_entries/1024<<endl;
      
                 //获取本地内存大小
                 clGetDeviceInfo(devices[n],CL_DEVICE_LOCAL_MEM_SIZE,sizeof(cl_ulong),&long_entries,NULL);
                 cout<<"Device Locale mem(KB) :"<<long_entries/1024<<endl;
      
                 //获取设备频率
                 clGetDeviceInfo(devices[n],CL_DEVICE_MAX_CLOCK_FREQUENCY,sizeof(cl_ulong),&long_entries,NULL);
                 cout<<"Device Max clock(MHz) :"<<long_entries<<endl;
      
                 //获取最大工作组数
                 clGetDeviceInfo(devices[n],CL_DEVICE_MAX_WORK_GROUP_SIZE,sizeof(cl_ulong),&long_entries,NULL);
                 cout<<"Device Max Group size :"<<long_entries<<endl;
      
                 //获取最大计算核心数
                 clGetDeviceInfo(devices[n],CL_DEVICE_MAX_COMPUTE_UNITS,sizeof(cl_ulong),&long_entries,NULL);
                 cout<<"Device Max parallel cores:"<<long_entries<<endl;
      
             }
         }
      
         return 0;
     }

    以上程序是检测当前计算机的可用计算平台的相关信息,运行结果如下。
    Windows下opencl环境配置

    提示复制本代码,编译后若发现提示: 检测到 Mac 文件格式: 请将源文件转换为 DOS 格式或 UNIX 格式, 则在VS中,点文件->高级保存选项,然后在行尾选项中选择windows(CR LF),重新编译,ok。
    还有在查找替换时,在查找选项中启用 正则表达式选项 ,注意windows下的换行符是 /n 而不是  


    opencl编码流程

    摘自opencl异构计算:

      (1)初始化opencl 平台(调用两次clGetPlatformIDs函数)

                         第一次获取可用的平台数量,第二次获取一个可用的平台。

    (2) 选择设备(调用两次clGetDeviceIDs函数)

                        第一次获取可用的设备数量,第二次获取一个可用的设备。

    (3)创建上下文(调用clCreateContext函数)

    Context:环境上下文,一个Context包含几个device(单个Cpu或GPU),一个Context就是这些device的一个联系纽带,只有在一个Context上的那些Device才能彼此交流工作,你的机器上可以同时存在很多Context。你可以用一个CPu创建context,也可以用一个CPU和一个GPU创建一个。

    (4)创建命令队列(调用clCreateCommandQueue函数)

    (5)创建数据缓冲区(调用clCreateBuffer函数)

    (6)将 host数据写进设备缓冲区(调用clEnqueueWriteBuffer函数)

    (7)创建程序对象(调用clCreateProgramWithSource函数)并编译内核源码(调用clBuildProgram函数,如果编译成功,则把编译代码存储在程序对象中

    (8)创建kernel(调用clCreateKernel函数)

    (9)设置内核参数(调用clSetKernelArg函数)

    (10)Configure the work-item structure(设置worksize)//只在分组的时候用到,只调用全局id的时候不要设置

    (11)内核入队执行(调用clEnqueueNDRangeKernel函数)

    (12)取回计算结果。Read  the output buffer back to the host(调用clEnqueueReadBuffer函数)

    (13)Release OpenCL resources(至此结束整个运行过程)

    中间有很多地方需要结合实际情况进行设定。


      //step 1:初始化OpenCL

        err = clGetPlatformIDs(1,&platform_id,NULL);

     

        if(err!=CL_SUCCESS)

        {

            cout<<"clGetPlatformIDs error"<<endl;

            return 0;

        }

     

        ////step 2:创建上下文。这次我们只用CPU来进行并行运算,当然你也可以该成GPU

        clGetDeviceIDs(platform_id,CL_DEVICE_TYPE_CPU,1,&device,NULL);

     

        //step 3:创建上下文

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

     

        //step 4:创建命令队列

        cmdQueue = clCreateCommandQueue(context,device,0,NULL);

     

         //step 5:创建数据缓冲区,即创建内存对象,内存对象分配在设备内存中,可以有内核函数直接调用

        bufferA = clCreateBuffer(context,

                                 CL_MEM_READ_ONLY,

                                 datasize,NULL,NULL);

     

        bufferB = clCreateBuffer(context,

                                 CL_MEM_READ_ONLY,

                                 datasize,NULL,NULL);

     

        //step 6:将数据上传到缓冲区,注意这里只传A,相当于赋值,B 是结果,不需要初始化了

        clEnqueueWriteBuffer(cmdQueue,

                             bufferA,CL_FALSE,

                             0,datasize,

                             buf_A,0,

                             NULL,NULL);

     

     

     

        //step 7:由内核源代码创建程序对象.

     

        program = clCreateProgramWithSource(context,1,

                                            (const char**)&buf_code,

                                            NULL,NULL);

     

       

    //调用clBuildProgram函数,编译内核源代码。如果编译成功,则把编译代码存储在程序对象中

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

        

    //step 8:创建内核对象

        kernel = clCreateKernel(program,"transposition",NULL);


        //step 9:设置参数,执行内核

        clSetKernelArg(kernel,0,sizeof(cl_mem),&bufferA);

        clSetKernelArg(kernel,1,sizeof(cl_mem),&bufferB);

     

        //step 10:内核入队执行。注意这里第三个参数已经改成2,表示二维数据。

      clEnqueueNDRangeKernel(cmdQueue,kernel,

                               2,NULL,

                               globalWorkSize,

                               NULL,0,NULL,NULL); 

       //step 11:取回计算结果

        clEnqueueReadBuffer(cmdQueue,bufferB,CL_TRUE,0,

                            datasize,buf_B,0,NULL,NULL);

     

        //输出计算结果

        for(n=0;n

        {

            for(m=0;m

            {

                cout<< buf_A[m][n] <<",";

            }

            cout<<endl;

        }

     

        cout<<endl<<"====transposition===="<<endl<<endl;

     

        for(n=0;n

        {

            for(m=0;m

            {

                cout<< buf_B[m][n] <<",";

            }

            cout<<endl;

        }

     

        //step 12:释放所有调用和内存

     

        clReleaseKernel(kernel);

        clReleaseProgram(program);

        clReleaseCommandQueue(cmdQueue);

        clReleaseMemObject(bufferA);

        clReleaseMemObject(bufferB);

        clReleaseContext(context);

     

        delete buf_code;

        return 0;

  • 相关阅读:
    320 Generalized Abbreviation
    319. Bulb Switcher
    三条用人原则
    Go 编码问题的解决方案
    C# MVC js 跨域
    apidoc接口文档的快速生成
    go语言学习
    C#系统之垃圾回收
    WCF项目启动时错误处理
    XML之XPath
  • 原文地址:https://www.cnblogs.com/huty/p/8517946.html
Copyright © 2020-2023  润新知