详细程序注解学OpenCL一 环境配置和入门程序

来源:互联网 发布:收银软件会中毒 编辑:程序博客网 时间:2024/05/17 07:04

本专栏是通过注解程序的方法学习OpenCL,我觉得一个一个地去抠原理也不是办法,干脆直接学习程序,然后把相关原理都直接注解到程序语句当中。

原创地址:http://blog.csdn.net/kenden23/article/details/14101657

一开始要配置好环境,我的是nvidia,所以就按照我的电脑举例,AMD应该也差不多。

1. 首先要到nvidia网站下载适合你显卡的最新驱动,安装好

2. 还是在nvidia网站下载好CUDA开发包,安装好

3. 如果默认安装路径的话,路径应该是在:C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.0

4. 打开这个目录会发现里面有include和lib文件夹,这就是我们需要配置在visual studio中的文件

5. 打开visual studio(版本基本都无关系,我用的是vs2012),新建一个win32空项目。按下alt+F7打开项目属性,也可以点击项目文件右键,选择属性。

6. 在属性页里面找到“C/C++”的“常规”项,点击,右边有“附加包含目录”,然后编辑,添加目录:C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.0\include

7.在属性页里面找到“连接器”,点击其“常规”项,右边有“附加库目录”,然后也是编辑,添加目录:C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.0\lib\Win32,如果是64位系统可以是:C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.0\lib\x64。

8. 在属性页里找到“常规”项, 右边“附加依赖项”,编辑,添加lib文件:OpenCL.lib

9. 然后就可以新建源文件,在源文件里面添加相关的OpenCl程序,就可以调试OpenCL程序了。

下面就可以开始学习程序了。

下面是个入门程序,已经注释好了,注释包括了基本原理的解析,可以通过直接阅读和调试程序学习OpenCL了。

本程序是读取电脑中的支持OpenCL的硬件nvidia和intel和AMD等信息,然后显示在屏幕上。

[cpp] view plain copy print?
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4. #include <iostream>  
  5.   
  6. #ifdef MAC  
  7. #include <OpenCL/cl.h>  
  8. #else  
  9. #include <CL/cl.h>  
  10. #endif  
  11.   
  12. int main() {  
  13.   
  14.     /* Host data structures */  
  15.     cl_platform_id *platforms;  
  16.     //每一个cl_platform_id 结构表示一个在主机上的OpenCL执行平台,就是指电脑中支持OpenCL的硬件,如nvidia显卡,intel CPU和显卡,AMD显卡和CPU等  
  17.     cl_uint num_platforms;  
  18.     cl_int i, err, platform_index = -1;  
  19.   
  20.     /* Extension data */  
  21.     char* ext_data;                           
  22.     size_t ext_size;     
  23.     const char icd_ext[] = "cl_khr_icd";  
  24.   
  25.     //要使platform工作,需要两个步骤。1 需要为cl_platform_id结构分配内存空间。2 需要调用clGetPlatformIDs初始化这些数据结构。一般还需要步骤0:询问主机上有多少platforms  
  26.   
  27.     /* Find number of platforms */  
  28.     //返回值如果为-1就说明调用函数失败,如果为0标明成功  
  29.     //第二个参数为NULL代表要咨询主机上有多少个platform,并使用num_platforms取得实际flatform数量。  
  30.     //第一个参数为1,代表我们需要取最多1个platform。可以改为任意大如:INT_MAX整数最大值。但是据说0,否则会报错,实际测试好像不会报错。下面是步骤0:询问主机有多少platforms  
  31.     err = clGetPlatformIDs(5, NULL, &num_platforms);          
  32.     if(err < 0) {          
  33.         perror("Couldn't find any platforms.");           
  34.         exit(1);                              
  35.     }                                     
  36.   
  37.     printf("I have platforms: %d\n", num_platforms); //本人计算机上显示为2,有intel和nvidia两个平台  
  38.   
  39.     /* Access all installed platforms */  
  40.     //步骤1 创建cl_platform_id,并分配空间  
  41.     platforms = (cl_platform_id*)                     
  42.         malloc(sizeof(cl_platform_id) * num_platforms);   
  43.     //步骤2 第二个参数用指针platforms存储platform  
  44.     clGetPlatformIDs(num_platforms, platforms, NULL);         
  45.   
  46.     /* Find extensions of all platforms */  
  47.     //获取额外的平台信息。上面已经取得了平台id了,那么就可以进一步获取更加详细的信息了。  
  48.     //一个for循环获取所有的主机上的platforms信息  
  49.     for(i=0; i<num_platforms; i++)   
  50.     {  
  51.         /* Find size of extension data */  
  52.         //也是和前面一样,先设置第三和第四个参数为0和NULL,然后就可以用第五个参数ext_size获取额外信息的长度了。  
  53.         err = clGetPlatformInfo(platforms[i],             
  54.             CL_PLATFORM_EXTENSIONS, 0, NULL, &ext_size);      
  55.         if(err < 0)   
  56.         {  
  57.             perror("Couldn't read extension data.");              
  58.             exit(1);  
  59.         }     
  60.   
  61.         printf("The size of extension data is: %d\n", ext_size);//我的计算机显示224.  
  62.   
  63.         /* Access extension data */    
  64.         //这里的ext_data相当于一个缓存,存储相关信息。  
  65.         ext_data = (char*)malloc(ext_size);   
  66.         //这个函数就是获取相关信息的函数,第二个参数指明了需要什么样的信息,如这里的CL_PLATFORM_EXTENSIONS表示是opencl支持的扩展功能信息。我计算机输出一大串,机器比较新(专门为了学图形学而购置的电脑),支持的东西比较多。  
  67.         clGetPlatformInfo(platforms[i], CL_PLATFORM_EXTENSIONS,       
  68.             ext_size, ext_data, NULL);                
  69.         printf("Platform %d supports extensions: %s\n", i, ext_data);  
  70.   
  71.         //这里是输出生产商的名字,比如我显卡信息是:NVIDIA CUDA  
  72.         char *name = (char*)malloc(ext_size);  
  73.         clGetPlatformInfo(platforms[i], CL_PLATFORM_NAME,     
  74.             ext_size, name, NULL);                
  75.         printf("Platform %d name: %s\n", i, name);  
  76.   
  77.         //这里是供应商信息,我显卡信息:NVIDIA Corporation  
  78.         char *vendor = (char*)malloc(ext_size);  
  79.         clGetPlatformInfo(platforms[i], CL_PLATFORM_VENDOR,       
  80.             ext_size, vendor, NULL);                  
  81.         printf("Platform %d vendor: %s\n", i, vendor);  
  82.   
  83.         //最高支持的OpenCL版本,本机显示:OpenCL1.1 CUDA 4.2.1  
  84.         char *version = (char*)malloc(ext_size);  
  85.         clGetPlatformInfo(platforms[i], CL_PLATFORM_VERSION,      
  86.             ext_size, version, NULL);                 
  87.         printf("Platform %d version: %s\n", i, version);  
  88.   
  89.         //这个只有两个值:full profile 和 embeded profile  
  90.         char *profile = (char*)malloc(ext_size);  
  91.         clGetPlatformInfo(platforms[i], CL_PLATFORM_PROFILE,      
  92.             ext_size, profile, NULL);                 
  93.         printf("Platform %d full profile or embeded profile?: %s\n", i, profile);  
  94.   
  95.         /* Look for ICD extension */     
  96.         //如果支持ICD这一扩展功能的platform,输出显示,本机的Intel和Nvidia都支持这一扩展功能  
  97.         if(strstr(ext_data, icd_ext) != NULL)   
  98.             platform_index = i;  
  99.         std::cout<<"Platform_index = "<<platform_index<<std::endl;  
  100.         /* Display whether ICD extension is supported */  
  101.         if(platform_index > -1)  
  102.             printf("Platform %d supports the %s extension.\n",   
  103.             platform_index, icd_ext);  
  104.   
  105.         std::cout<<std::endl;  
  106.   
  107.         //释放空间  
  108.         free(ext_data);  
  109.         free(name);  
  110.         free(vendor);  
  111.         free(version);  
  112.         free(profile);  
  113.     }  
  114.           
  115.     if(platform_index <= -1)  
  116.         printf("No platforms support the %s extension.\n", icd_ext);  
  117.   
  118.     /* Deallocate resources */  
  119.     free(platforms);  
  120.     return 0;  
  121. }   


每个电脑的输出结果不一样的,我电脑的输出结果是:


OpenCL 查看设备信息

下面是注释程序,目的就是查看自己计算机上所有支持OpenCL的设备,并打印信息。

主函数调用run()就可以运行了。要设置请看我另一篇OpenCl设置文章。

[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4.   
  5. #ifdef MAC  
  6. #include <OpenCL/cl.h>  
  7. #else  
  8. #include <CL/cl.h>  
  9. #endif  
  10.   
  11. namespace device_ext_test  
  12. {  
  13.   
  14. int run() {  
  15.     /* Host/device data structures */  
  16.     cl_platform_id *platforms;  
  17.     cl_device_id *devices;  
  18.     cl_uint num_platforms;  
  19.     cl_uint num_devices, addr_data;  
  20.     cl_int i, err;  
  21.   
  22.     /* Extension data */  
  23.     char name_data[48], ext_data[4096];  
  24.   
  25.     err = clGetPlatformIDs(5, NULL, &num_platforms);          
  26.     if(err < 0) {          
  27.         perror("Couldn't find any platforms.");           
  28.         exit(1);                              
  29.     }  
  30.   
  31.     /* 选取所有的platforms*/  
  32.     platforms = (cl_platform_id*)                     
  33.         malloc(sizeof(cl_platform_id) * num_platforms);  
  34.     err = clGetPlatformIDs(num_platforms, platforms, NULL);           
  35.     if(err < 0) {              
  36.         perror("Couldn't find any platforms");  
  37.         exit(1);  
  38.     }  
  39.       
  40.     //循环查看所有platforms的devices信息,一般intel和AMD的都可以有两个devices:CPU和显卡  
  41.     //如果是nvidia的就一般只有一个显卡device了。  
  42.     for (int j = 0; j < (int)num_platforms; j++)  
  43.     {  
  44.         printf("\nplatform %d\n", j+1);  
  45.         /* 步骤和platforms的一样 */  
  46.         err = clGetDeviceIDs(platforms[j], CL_DEVICE_TYPE_ALL, 1, NULL, &num_devices);  
  47.         if(err < 0) {                  
  48.             perror("Couldn't find any devices");  
  49.             exit(1);  
  50.         }  
  51.   
  52.         /* Access connected devices */  
  53.         devices = (cl_device_id*)                     
  54.             malloc(sizeof(cl_device_id) * num_devices);       
  55.         clGetDeviceIDs(platforms[j], CL_DEVICE_TYPE_ALL,              
  56.             num_devices, devices, NULL);                  
  57.   
  58.         /*循环显示platform的所有device(CPU和显卡)信息。*/  
  59.         for(i=0; i<(int)num_devices; i++) {  
  60.   
  61.             err = clGetDeviceInfo(devices[i], CL_DEVICE_NAME,         
  62.                 sizeof(name_data), name_data, NULL);              
  63.             if(err < 0) {          
  64.                 perror("Couldn't read extension data");  
  65.                 exit(1);  
  66.             }  
  67.             clGetDeviceInfo(devices[i], CL_DEVICE_ADDRESS_BITS,       
  68.                 sizeof(ext_data), &addr_data, NULL);              
  69.   
  70.             clGetDeviceInfo(devices[i], CL_DEVICE_EXTENSIONS,         
  71.                 sizeof(ext_data), ext_data, NULL);            
  72.   
  73.             printf("NAME: %s\nADDRESS_WIDTH: %u\nEXTENSIONS: %s\n\n",   
  74.                 name_data, addr_data, ext_data);  
  75.         }  
  76.     }  
  77.   
  78.     free(platforms);  
  79.     free(devices);  
  80.     printf("\n");  
  81.     system("pause");  
  82.     return 0;  
  83. }  
  84.   
  85.   
  86. }  



OpenCL 操作context

本程序主要测试:

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

创建一个context

clRetainContext(context);//Context的reference +1

clReleaseContext(context);//Context的reference -1


[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4.   
  5. #ifdef MAC  
  6. #include <OpenCL/cl.h>  
  7. #else  
  8. #include <CL/cl.h>  
  9. #endif  
  10.   
  11. namespace context_count  
  12. {  
  13.   
  14. int run()   
  15. {  
  16.     cl_platform_id platform;  
  17.     cl_device_id device;  
  18.     cl_context context;  
  19.     cl_int err;  
  20.     cl_uint ref_count;  
  21.   
  22.     err = clGetPlatformIDs(1, &platform, NULL);  
  23.     if(err < 0) {  
  24.         perror("Couldn't find any platforms");  
  25.         exit(1);  
  26.     }  
  27.   
  28.     err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, NULL);  
  29.     if(err == CL_DEVICE_NOT_FOUND) {  
  30.         err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_CPU, 1, &device, NULL);  
  31.     }  
  32.     if(err < 0) {  
  33.         perror("Couldn't find any devices");  
  34.         exit(1);  
  35.     }  
  36.   
  37.     /* 创建 context */  
  38.     context = clCreateContext(NULL, 1, &device, NULL, NULL, &err);  
  39.     if(err < 0) {  
  40.         perror("Couldn't create a context");  
  41.         exit(1);     
  42.     }  
  43.   
  44.     /* 获取reference count的数量,使用ref_count返回值*/  
  45.     err = clGetContextInfo(context, CL_CONTEXT_REFERENCE_COUNT,       
  46.         sizeof(ref_count), &ref_count, NULL);             
  47.     if(err < 0) {          
  48.         perror("Couldn't read the reference count.");  
  49.         exit(1);  
  50.     }  
  51.     printf("Initial reference count: %u\n", ref_count);  
  52.   
  53.     /* 每次函数访问context的时候,调用clRetainContext,就是把context reference + 1,因为context并不是像platform和device那样delete的,而是clRetainContext的时候+1,当调用clReleaseContext的时候-1,当为零的时候,系统自动删除context。这就可以方便cl_context数据存活超过创建它的函数,可以让第三方库什么的继续访问context */  
  54.     clRetainContext(context);clRetainContext(context);                        
  55.     clGetContextInfo(context, CL_CONTEXT_REFERENCE_COUNT,         
  56.         sizeof(ref_count), &ref_count, NULL);             
  57.     printf("Reference count: %u\n", ref_count);           
  58.   
  59.     clReleaseContext(context);                        
  60.     clGetContextInfo(context, CL_CONTEXT_REFERENCE_COUNT,         
  61.         sizeof(ref_count), &ref_count, NULL);             
  62.     printf("Reference count: %u\n", ref_count);           
  63.   
  64.     clReleaseContext(context);clReleaseContext(context);      
  65.     system("pause");  
  66.     return 0;  
  67. }  
  68.   
  69. }  



OpenCL 获取Program信息

本程序生成一个OpenCL Program,然后获取Program的source,其实它的source就是一个char[],可以打印出来。

然后我们把这些内容和原来文本的内容对比,看看是否是我们想要读入的内容。

还可以测试是否编译正确,如果不正确会有输出提示的。


下面程序运行如下:



前面都是读入的函数代码。然后后面检查这些函数是否正确,可以看到第二个函数不正确,因为*r没有定义。


下面是完整代码:

[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. #define _CRT_SECURE_NO_WARNINGS  
  2.   
  3. #include <stdio.h>  
  4. #include <stdlib.h>  
  5. #include <sys/types.h>  
  6.   
  7. #ifdef MAC  
  8. #include <OpenCL/cl.h>  
  9. #else  
  10. #include <CL/cl.h>  
  11. #endif  
  12.   
  13. namespace program_build  
  14. {  
  15.   
  16. const static int NUM_FILES = 2;  
  17. const char PROGRAM_FILE_1[] = "good.cl";  
  18. const char *PROGRAM_FILE_2 = "bad.cl";  
  19.   
  20. int run()  
  21. {  
  22.     /*program可以包括多个kernel,一个kernel相当于一个功能函数,由program包含在内存中,然后就可以使用kernel的功能了。 
  23.     1 需要使用kernel,创建program,把kernel读入内存 
  24.     2 需要把program和device连接起来 
  25.      Host/device data structures */  
  26.     cl_platform_id platform;  
  27.     cl_device_id device;  
  28.     cl_context context;  
  29.     cl_int i, err;  
  30.   
  31.     /* Program data structures */  
  32.     cl_program program;  
  33.     FILE *program_handle;  
  34.     char *program_buffer[NUM_FILES];  
  35.     char *program_log;  
  36.     const char *file_name[] = {PROGRAM_FILE_1, PROGRAM_FILE_2};  
  37.     const char options[] = "-cl-finite-math-only -cl-no-signed-zeros";    
  38.     size_t program_size[NUM_FILES];  
  39.     size_t log_size;  
  40.   
  41.     /* Access the first installed platform */  
  42.     err = clGetPlatformIDs(1, &platform, NULL);  
  43.     if(err < 0) {  
  44.         perror("Couldn't find any platforms");  
  45.         exit(1);  
  46.     }  
  47.   
  48.     /* Access the first GPU/CPU */  
  49.     err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, NULL);  
  50.     if(err == CL_DEVICE_NOT_FOUND) {  
  51.         err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_CPU, 1, &device, NULL);  
  52.     }  
  53.     if(err < 0) {  
  54.         perror("Couldn't find any devices");  
  55.         exit(1);  
  56.     }  
  57.   
  58.     /* Create a context */  
  59.     context = clCreateContext(NULL, 1, &device, NULL, NULL, &err);  
  60.     if(err < 0) {  
  61.         perror("Couldn't create a context");  
  62.         exit(1);     
  63.     }  
  64.   
  65.     /* Read each program file and place content into buffer array */  
  66.     for(i=0; i<NUM_FILES; i++) {  
  67.   
  68.         program_handle = fopen(file_name[i], "r");  
  69.         if(program_handle == NULL) {  
  70.             perror("Couldn't find the program file");  
  71.             exit(1);     
  72.         }  
  73.         fseek(program_handle, 0, SEEK_END);  
  74.         program_size[i] = ftell(program_handle);  
  75.         rewind(program_handle);  
  76.         program_buffer[i] = (char*)malloc(program_size[i]+1);  
  77.         program_buffer[i][program_size[i]] = '\0';  
  78.         fread(program_buffer[i], sizeof(char), program_size[i],   
  79.             program_handle);  
  80.         fclose(program_handle);  
  81.     }  
  82.   
  83.     /* Create a program containing all program content */  
  84.     program = clCreateProgramWithSource(context, NUM_FILES,               
  85.         (const char**)program_buffer, program_size, &err);                
  86.     if(err < 0) {  
  87.         perror("Couldn't create the program");  
  88.         exit(1);     
  89.     }  
  90.   
  91.     /* Build program 
  92.     but one provision is crucial: every compiler must be accessible through clBuild-Program. This function compiles and links a cl_program for devices associated with the platform. It doesn’t return a new cl_program, but instead modifies the input data structure. 
  93.     */  
  94.   
  95.     err = clBuildProgram(program, 1, &device, options, NULL, NULL);   
  96.   
  97.     int bufSize = program_size[0] + program_size[1] + 1;  
  98.     char *programBuffer = (char *) malloc(bufSize);  
  99.     clGetProgramInfo(program, CL_PROGRAM_SOURCE, bufSize, programBuffer, NULL);  
  100.     printf("Print Program Source:\n");  
  101.     printf("\n %s \n", programBuffer);   
  102.   
  103.     printf("Check if it is correct:\n");  
  104.     for (int i = 0; i < NUM_FILES; i++)  
  105.     {  
  106.         printf("\n %s \n", program_buffer[i]);  
  107.     }  
  108.   
  109.     if(err < 0)   
  110.     {  
  111.         clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG,   
  112.             0, NULL, &log_size);  
  113.         program_log = (char*) malloc(log_size+1);  
  114.         program_log[log_size] = '\0';  
  115.         clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG,   
  116.             log_size+1, program_log, NULL);  
  117.         printf("%s\n", program_log);  
  118.         free(program_log);  
  119.         system("pause");  
  120.         exit(1);  
  121.     }  
  122.   
  123.     /* Deallocate resources */  
  124.     for(i=0; i<NUM_FILES; i++) {  
  125.         free(program_buffer[i]);  
  126.     }  
  127.     clReleaseProgram(program);  
  128.     clReleaseContext(context);  
  129.     system("pause");  
  130.   
  131.     return 0;  
  132. }  
  133.   




0 0
原创粉丝点击