OpenCL Hello World

时间:2022-04-27 14:38:07

▶ OpenCL 的环境配置与第一个程序

● CUDA 中自带 OpenCL 需要的头文件和库,直接拉近项目里边去就行;AMD 需要下载 AMD APP SDK(https://community.amd.com/message/2739800 和 http://hc.csdn.net/resources/resource_detail?id=13,感谢大神们提供的方便渠道)

▶ CUDA - OpenCL 在Visual Studio 2015 中的配置。注意 32 位项目和 64 位项目的属性选项不共享,添加的文件也不相同,应该先选定项目的位数,再进行配置。

● VS项目属性右键,属性,C/C++ 目录,包含目录,添加 CUDA 的头文件目录,我的是 "D:\Program\CUDA9.0\include" ,一般代码中使用  #inlcude <CL/cl.h>  来包含子目录中的头文件,也可将其 CL 子目录直接写在这里, "D:\Program\CUDA9.0\include\CL"

● VS项目属性右键,属性,C/C++ 目录,库目录,添加 CUDA 的库目录,注意 32 位和64位是不同的,32位 "D:\Program\CUDA9.0\lib\Win32",64位 "D:\Program\CUDA9.0\lib\x64",使用错误的库文件在编译时会显示类似 “错误 LNK2019 无法解析的外部符号 clGetPlatformInfo,该符号在函数 main 中被引用” 的错误。

  OpenCL Hello World

● VS项目属性右键,属性,链接器,输入,附加依赖项,添加 OpenCL.lib

  OpenCL Hello World

▶ AMD APP SDK - OpenCL 在Visual Studio 2015 中的配置。跟上面 CUDA - OpenCL 的差不多,也需要添加头文件位置,库位置和链接器输入,注意区分 32 位项目和 64 位项目。

● 在办公室的垃圾电脑上完成了配置,相关目录如下:"C:\Program Files %28x86%29\AMD APP SDK\3.0\include","C:\Program Files %28x86%29\AMD APP SDK\3.0\include\CL","C:\Program Files (x86)\AMD APP SDK\3.0\lib\x86_64"

● 我直接按照上面的配置运行时,遇到函数 clGetPlatformIDs() 时报内存错误(0x0FD9F73C (XXX.dll)处(位于 OpenCL.exe 中)引发的异常: 0xC0000005: 读取位置 0x00000001 时发生访问冲突。),与动态库有关。这时需要在 "C:\Windows\SysWOW64" 或 "C:\Windows\System32" 下更新 igdrcl32.dll igdrcl64.dll 才行(随便找了一个较新的版本替换掉它)。

▶ 第一个程序,访问计算平台,输出相关信息

● 代码

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cl.h> // OpenCL 的头文件 int main()
{
cl_platform_id *pPlatform; // 平台数据结构数组,每个结构表示一个在主机上的 OpenCL 执行平台(执行设备)
cl_uint nPlatform;
cl_int i, err;
char* extraInformation; // 额外信息缓冲区
size_t extraSize; // 额外信息缓冲区大小
bool supportICD = false; // 记录主机是否支持 OpenCL Installable Client Driver (ICD) // platform工作的步骤:0、询问主机上有多少计算平台;1、为平台数据结构分配内存空间;2、初始化这些数据结构
if (err = clGetPlatformIDs(, NULL, &nPlatform) < )// 查询平台数,返回值非零说明调用错误,参数:1、需要的平台数上限;2、NULL 表查询平台总数;3、输出平台数的变量指针
{
perror("Couldn't find any pPlatform."); // 输出错误信息用的函数
exit();
}
printf("Platform count: %d\n", nPlatform); pPlatform = (cl_platform_id*)malloc(sizeof(cl_platform_id) * nPlatform);// 创建主机数据结构
clGetPlatformIDs(nPlatform, pPlatform, NULL); // 初始化结构 for (i = ; i < nPlatform; i++) // 循环获取平台信息
{
if (err = clGetPlatformInfo(pPlatform[i], CL_PLATFORM_EXTENSIONS, , NULL, &extraSize) < ) // 获取额外信息,第五个参数为信息长度
{
perror("Couldn't read extension data.");
exit();
}
printf("\nExtension data size: %d\n", extraSize); extraInformation = (char*)malloc(extraSize); // 输出信息缓存
clGetPlatformInfo(pPlatform[i], CL_PLATFORM_EXTENSIONS, extraSize, extraInformation, NULL); // 获取相关信息,第二参数为信息内容,这里是OpenCL支持的扩展功能信息
printf("Platform %d supports extensions: %s\n", i, extraInformation);
if (strstr(extraInformation, "cl_khr_icd") != NULL) // 检查是否支持 ICD,支持则输出平台编号
{
printf("\nPlatform %d supports ICD extension.\n", i);
supportICD = true;
}
clGetPlatformInfo(pPlatform[i], CL_PLATFORM_NAME, extraSize, extraInformation, NULL); // 产商名
printf("Platform %d name: %s\n", i, extraInformation);
clGetPlatformInfo(pPlatform[i], CL_PLATFORM_VENDOR, extraSize, extraInformation, NULL); // 供应商名
printf("Platform %d vendor: %s\n", i, extraInformation);
clGetPlatformInfo(pPlatform[i], CL_PLATFORM_VERSION, extraSize, extraInformation, NULL); // OpenCL版本
printf("Platform %d version: %s\n", i, extraInformation);
clGetPlatformInfo(pPlatform[i], CL_PLATFORM_PROFILE, extraSize, extraInformation, NULL); // 完整模式 / 嵌入式
printf("Profile: %s\n", extraInformation);
free(extraInformation);
}
if (!supportICD)
printf("\nNo platform support ICD extension.\n");
free(pPlatform);
getchar();
return ;
}

● 输出结果,我的电脑。核显被物理屏蔽,仅检测到独立显卡,仅支持到 OpenCL1.2

Platform count: 

Extension data size:
Platform supports extensions: cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_fp64 cl_khr_byte_addressable_store cl_khr_icd cl_khr_gl_sharing cl_nv_compiler_options cl_nv_device_attribute_query cl_nv_pragma_unroll cl_nv_d3d10_sharing cl_khr_d3d10_sharing cl_nv_d3d11_sharing cl_nv_copy_opts cl_nv_create_buffer Platform supports ICD extension.
Platform name: NVIDIA CUDA
Platform vendor: NVIDIA Corporation
Platform version: OpenCL 1.2 CUDA 9.1.
Profile: FULL_PROFILE

● 输出结果,办公室的电脑。检测到独立显卡(支持到 OpenCL2.0)和核显(支持到OpenCL1.2)

Platform count: 

Extension data size:
Platform supports extensions: cl_khr_icd cl_khr_d3d10_sharing cl_khr_d3d11_sharing cl_khr_dx9_media_sharing cl_amd_event_callback cl_amd_offline_devices Platform supports ICD extension.
Platform name: AMD Accelerated Parallel Processing
Platform vendor: Advanced Micro Devices, Inc.
Platform version: OpenCL 2.0 AMD-APP (1800.11)
Profile: FULL_PROFILE Extension data size:
Platform supports extensions: cl_khr_icd cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_byte_addressable_store cl_khr_depth_images cl_khr_3d_image_writes cl_intel_exec_by_local_thread cl_khr_spir cl_khr_dx9_media_sharing cl_intel_dx9_media_sharing cl_khr_d3d11_sharing cl_khr_gl_sharing cl_khr_fp64 Platform supports ICD extension.
Platform name: Intel(R) OpenCL
Platform vendor: Intel(R) Corporation
Platform version: OpenCL 1.2
Profile: FULL_PROFILE

● 用到的函数和定义

 // cl_platform.h
// 标量类型
typedef signed __int8 cl_char;
typedef unsigned __int8 cl_uchar;
typedef signed __int16 cl_short;
typedef unsigned __int16 cl_ushort;
typedef signed __int32 cl_int;
typedef unsigned __int32 cl_uint;
typedef signed __int64 cl_long;
typedef unsigned __int64 cl_ulong;
typedef unsigned __int16 cl_half;
typedef float cl_float;
typedef double cl_double; // 平台数据结构函数
extern CL_API_ENTRY cl_int CL_API_CALL clGetPlatformIDs(// 查询平台数和初始化平台数据结构
cl_uint, // 需要的平台数上限
cl_platform_id *, // 传入指针,NULL 表查询平台总数,非 NULL 表初始化平台数据结构
cl_uint * // 输出指针,指向保存了平台数量的变量
) CL_API_SUFFIX__VERSION_1_0; // 版本号?只是一个宏 extern CL_API_ENTRY cl_int CL_API_CALL clGetPlatformInfo(// 获取平台信息
cl_platform_id, // 平台数据结构
cl_platform_info, // 需要查询的信息名
size_t, // 输出缓冲区大小(Byte),首次调用时采用 0
void *, // 输出信息的缓冲区指针,首次调用时采用 NULL
size_t * // 输出信息需要的缓冲区大小(Byte),首次调用使用该变量来获得所需缓冲区的大小
) CL_API_SUFFIX__VERSION_1_0; // 各种可以查询的信息名,含义见代码中
#define CL_PLATFORM_PROFILE 0x0900
#define CL_PLATFORM_VERSION 0x0901
#define CL_PLATFORM_NAME 0x0902
#define CL_PLATFORM_VENDOR 0x0903
#define CL_PLATFORM_EXTENSIONS 0x0904 // stdio.h
_ACRTIMP void __cdecl perror(_In_opt_z_ char const* _ErrorMessage);// 输出错误信息 // vcruntime.h
typedef unsigned __int64 size_t;// size_t 的定义