第二十九章 使用OpenCL工作

OpenCL 程序用来执行支持OpenCL 1.1或更高版本的视频卡上的计算。 现代视频卡包含数百个小型专用处理器,可以同时与输入数据流进行简单的数学运算。 OpenCL语言组织了并行计算并且为一类特定任务提供了更快的速度。

在一些图形卡中默认禁止处理 双精度(double)类型数字。这可能会导致编译错误5105。若要启用支持 双精度(double)类型数字,请添加以下指令到您的OpenCL程序:

#pragma OPENCL EXTENSION cl_khr_fp64 : enable

更多详情请参考以下链接

https://www.khronos.org/registry/OpenCL/sdk/1.0/docs/man/xhtml/cl_khr_fp64.html

但是,如果图形卡不支持 双精度(double)型,启用该指令则不会有帮助。

建议以单独的CL文件编写OpenCL源代码,稍后将其包含进使用资源变量MQL5程序。

运行OpenCL程序中的函数:

函数 功能
CLHandleType 返回OpenCL句柄的类型,作为ENUM_OPENCL_HANDLE_TYPE枚举值
CLGetInfoInteger 为OpenCL对象 或 设备返回一个整数属性值
CLContextCreate 创建OpenCL上下文(容器)
CLContextFree 移除OpenCL上下文(容器)
CLGetDeviceInfo 从OpenCL驱动程序接收设备属性
CLProgramCreate 从源代码创建OpenCL程序
CLProgramFree 移除OpenCL程序
CLKernelCreate 创建OpenCL开始函数
CLKernelFree 移除OpenCL开始函数
CLSetKernelArg 为OpenCL函数设置一个参数
CLSetKernelArgMem 设置OpenCL缓冲作为OpenCL函数的参数
CLSetKernelArgMemLocal 设置本地缓冲区作为内核函数参数
CLBufferCreate 创建OpenCL缓冲
CLBufferFree 删除OpenCL缓冲
CLBufferWrite 写入数组到OpenCL缓冲
CLBufferRead 读取OpenCL缓冲到数组
CLExecute 运行OpenCL程序
CLExecutionStatus 返回OpenCL程序执行状态。

相关参考

OpenCL, 资源

# 29.1 CLHandleType

返回OpenCL句柄的类型,作为ENUM_OPENCL_HANDLE_TYPE枚举的值。

ENUM_OPENCL_HANDLE_TYPE  CLHandleType( 
   int  handle     // OpenCL对象处理 
   );
1
2
3

参数

handle

[in] OpenCL对象的句柄:上下文,内核或OpenCL程序。

返回值

OpenCL句柄的类型,作为ENUM_OPENCL_HANDLE_TYPE枚举的值。

ENUM_OPENCL_HANDLE_TYPE

标识符 描述
OPENCL_INVALID 不正确处理
OPENCL_CONTEXT OpenCL上下文的句柄
OPENCL_PROGRAM OpenCL程序的句柄
OPENCL_KERNEL OpenCL内核的句柄
OPENCL_BUFFER OpenCL缓冲的句柄

# 29.2 CLGetInfoInteger

返回OpenCL对象 或 设备的整数属性的值。

long  CLGetInfoInteger( 
   int  handle,                           // OpenCL对象处理或OpenCL设备编号 
   ENUM_OPENCL_PROPERTY_INTEGER  prop     // 被请求属性 
   );
1
2
3
4

参数

handle

[in] OpenCL对象的句柄或OpenCL设备的编号。 OpenCL设备的编号从零开始。

prop

[in] 从ENUM_OPENCL_PROPERTY_INTEGER枚举中请求的属性的类型,您要获取的值。

返回值

如果成功则返回 属性的值,或 一旦错误则返回 -1。想要获取有关错误的详细信息,请调用 GetLastError() 函数.

ENUM_OPENCL_PROPERTY_INTEGER

标识符 描述 类型
CL_DEVICE_COUNT OpenCL支持的设备编号. 此属性不要求第一个参数规范,即你可以处理参数通过一个为零的值 int
CL_DEVICE_TYPE 设备类型 ENUM_CL_DEVICE_TYPE
CL_DEVICE_VENDOR_ID 唯一的供应商识别 uint
CL_DEVICE_MAX_COMPUTE_UNITS OpenCL设备中的并行计算任务编号. 一个工作组解决了一个计算任务.最低值为1 uint
CL_DEVICE_MAX_CLOCK_FREQUENCY 设备最高的固定频率兆赫. uint
CL_DEVICE_GLOBAL_MEM_SIZE 设备的全局内存字节大小 ulong
CL_DEVICE_LOCAL_MEM_SIZE 处理数据(事件)本地内存的字节大小 uint
CL_BUFFER_SIZE OpenCL字节缓冲区的实际大小 ulong
CL_DEVICE_MAX_WORK_GROUP_SIZE 可用于OpenCL设备的本地工作组总数。 ulong
CL_KERNEL_WORK_GROUP_SIZE 可用于OpenCL程序的本地工作组总数。 ulong
CL_KERNEL_LOCAL_MEM_SIZE 由OpenCL程序用于解决一组全部并行任务的本地存储器大小(字节)。 使用CL_DEVICE_LOCAL_MEM_SIZE 接收最大可用值 ulong
CL_KERNEL_PRIVATE_MEM_SIZE OpenCL程序内核中,每个任务使用的最小专有存储器大小(字节)。 ulong

ENUM_CL_DEVICE_TYPE枚举包含了可能支持OpenCL的设备类型。您可以通过调用CLGetInfoInteger(handle_or_deviceN,CL_DEVICE_TYPE),通过其编号或OpenCL对象的句柄来接收设备类型。

ENUM_CL_DEVICE_TYPE

标识符 描述
CL_DEVICE_ACCELERATOR OpenCL专用加速器 (比如, IBM CELL Blade). 这些设备使用外设互连如PCIe与主处理器进行通信.
CL_DEVICE_CPU 一个OpenCL主机处理器设备. 主机处理器运行OpenCL运转且为一个单核或多核CPU.
CL_DEVICE_GPU 一个OpenCL设备是GPU.
CL_DEVICE_DEFAULT 系统默认的OpenCL设备. 默认设备不能为
CL_DEVICE_CUSTOM 专用的加速器不支持OpenCL C编写的程序.

示例:

void OnStart() 
  { 
   int cl_ctx; 
//--- 初始化 OpenCL 上下文 
   if((cl_ctx=CLContextCreate(CL_USE_GPU_ONLY))==INVALID_HANDLE) 
     { 
      Print("OpenCL not found"); 
      return; 
     } 
//--- 显示有关OpenCL设备的常规信息 
   Print("OpenCL type: ",EnumToString((ENUM_CL_DEVICE_TYPE)CLGetInfoInteger(cl_ctx,CL_DEVICE_TYPE))); 
   Print("OpenCL vendor ID: ",CLGetInfoInteger(cl_ctx,CL_DEVICE_VENDOR_ID)); 
   Print("OpenCL units: ",CLGetInfoInteger(cl_ctx,CL_DEVICE_MAX_COMPUTE_UNITS)); 
   Print("OpenCL freq: ",CLGetInfoInteger(cl_ctx,CL_DEVICE_MAX_CLOCK_FREQUENCY)," MHz"); 
   Print("OpenCL global mem: ",CLGetInfoInteger(cl_ctx,CL_DEVICE_GLOBAL_MEM_SIZE)," bytes"); 
   Print("OpenCL local mem: ",CLGetInfoInteger(cl_ctx,CL_DEVICE_LOCAL_MEM_SIZE)," bytes"); 
//---  
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 29.3 CLGetInfoString

返回OpenCL对象 或 设备的属性的字符串值。

bool  CLGetInfoString( 
   int  handle,                           // OpenCL对象处理或者OpenCL设备号码 
   ENUM_OPENCL_PROPERTY_STRING  prop,     // 被请求的属性 
   string&  value                         // 引用字符串 
   );
1
2
3
4
5

参数

handle

[in] OpenCL对象句柄或OpenCL设备号。 OpenCL设备的编号从零开始。 prop

[in] 从 ENUM_OPENCL_PROPERTY_STRING 枚举中请求的属性的类型,您要获取的值

value

[out] 接收属性值的字符串.

返回值

成功则返回true, 否则返回 false. 想要获取有关错误的详细信息,请调用 GetLastError() 函数.

ENUM_OPENCL_PROPERTY_STRING

标识符 描述
CL_PLATFORM_PROFILE OpenCL简介. 简介名称可以是以下值中的某一个:
FULL_PROFILE - 实现支持OpenCL(功能定义为核心规范的一部分而无需为OpenCL支持额外的扩展) ;
EMBEDDED_PROFILE - 实现支持OpenCL作为增补. 修订简介被定义为每个OpenCL版本的子集.
CL_PLATFORM_VERSION OpenCL版本
CL_PLATFORM_VENDOR 平台供应商名称
CL_PLATFORM_EXTENSIONS 由平台支持的扩展名列表。扩展名应该能被所有与这个平台相
CL_DEVICE_NAME 设备名称
CL_DEVICE_VENDOR 供应商名称
CL_DRIVER_VERSION major_number.minor_number格式OpenCL设备版本
CL_DEVICE_PROFILE OpenCL设备简介. 简介名称可以是以下值的某一个:
FULL_PROFILE - 实现支持OpenCL(功能定义为核心规范的一部分而无需为OpenCL支持额外的扩展);
EMBEDDED_PROFILE -实现支持OpenCL作为增补. 修订简介被定义为每个OpenCL版本的子集.
CL_DEVICE_VERSION OpenCL<space><major_version.minor_version><space><vendor-specific information>格式OpenCL版本
CL_DEVICE_EXTENSIONS 设备所支持的扩展名列表。列表可以包含由供应商支持的扩展,以及一个或多个批准名称:
cl_khr_int64_base_atomics
cl_khr_int64_extended_atomics
cl_khr_fp16
cl_khr_gl_sharing
cl_khr_gl_event
cl_khr_d3d10_sharing
cl_khr_dx9_media_sharing
cl_khr_d3d11_sharing
CL_DEVICE_BUILT_IN_KERNELS 可支持的内核列表用 ";"分割.
CL_DEVICE_OPENCL_C_VERSION 这个设备的编译器所支持的最大版本。版本格式:
OpenCL<space>C<space><major_version.minor_version><space><vendor-specific information>

例如:

void OnStart() 
  { 
   int cl_ctx; 
   string str; 
//--- 初始化 OpenCL 上下文 
   if((cl_ctx=CLContextCreate(CL_USE_GPU_ONLY))==INVALID_HANDLE) 
     { 
      Print("OpenCL not found"); 
      return; 
     } 
//--- 显示平台信息 
   if(CLGetInfoString(cl_ctx,CL_PLATFORM_NAME,str)) 
      Print("OpenCL platform name: ",str); 
   if(CLGetInfoString(cl_ctx,CL_PLATFORM_VENDOR,str)) 
      Print("OpenCL platform vendor: ",str); 
   if(CLGetInfoString(cl_ctx,CL_PLATFORM_VERSION,str)) 
      Print("OpenCL platform ver: ",str); 
   if(CLGetInfoString(cl_ctx,CL_PLATFORM_PROFILE,str)) 
      Print("OpenCL platform profile: ",str); 
   if(CLGetInfoString(cl_ctx,CL_PLATFORM_EXTENSIONS,str)) 
      Print("OpenCL platform ext: ",str); 
//--- 显示设备信息 
   if(CLGetInfoString(cl_ctx,CL_DEVICE_NAME,str)) 
      Print("OpenCL device name: ",str); 
   if(CLGetInfoString(cl_ctx,CL_DEVICE_PROFILE,str)) 
      Print("OpenCL device profile: ",str); 
   if(CLGetInfoString(cl_ctx,CL_DEVICE_BUILT_IN_KERNELS,str)) 
      Print("OpenCL device kernels: ",str); 
   if(CLGetInfoString(cl_ctx,CL_DEVICE_EXTENSIONS,str)) 
      Print("OpenCL device ext: ",str); 
   if(CLGetInfoString(cl_ctx,CL_DEVICE_VENDOR,str)) 
      Print("OpenCL device vendor: ",str); 
   if(CLGetInfoString(cl_ctx,CL_DEVICE_VERSION,str)) 
      Print("OpenCL device ver: ",str); 
   if(CLGetInfoString(cl_ctx,CL_DEVICE_OPENCL_C_VERSION,str)) 
      Print("OpenCL open c ver: ",str); 
//--- 显示OpenCL设备的常规信息 
   Print("OpenCL type: ",EnumToString((ENUM_CL_DEVICE_TYPE)CLGetInfoInteger(cl_ctx,CL_DEVICE_TYPE))); 
   Print("OpenCL vendor ID: ",CLGetInfoInteger(cl_ctx,CL_DEVICE_VENDOR_ID)); 
   Print("OpenCL units: ",CLGetInfoInteger(cl_ctx,CL_DEVICE_MAX_COMPUTE_UNITS)); 
   Print("OpenCL freq: ",CLGetInfoInteger(cl_ctx,CL_DEVICE_MAX_CLOCK_FREQUENCY)); 
   Print("OpenCL global mem: ",CLGetInfoInteger(cl_ctx,CL_DEVICE_GLOBAL_MEM_SIZE)); 
   Print("OpenCL local mem: ",CLGetInfoInteger(cl_ctx,CL_DEVICE_LOCAL_MEM_SIZE)); 
//---  
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 29.4 CLContextCreate

创建一个OpenCL上下文并返回其句柄。

int  CLContextCreate( 
   int  device     // OpenCL设备或宏的序列号 
   );
1
2
3

参数

device

[in] 系统中的OpenCL设备序号. 你可以指定下列值之一,而不是一个具体的数字:

• CL_USE_ANY —— 任何支持OpenCL的有效设备均被允许;
• CL_USE_CPU_ONLY —— 仅CPU中的OpenCL仿真被允许;
• CL_USE_GPU_ONLY —— OpenCL仿真被禁止并且仅有OpenCL支持的专业设备 (视频卡) 可以被使用.

返回值

如果成功创建OpenCL上下文对象将返回句柄。一旦出错 则返回 -1 . 想要获取有关错误的详细信息,请调用 GetLastError() 函数.

# 29.5 CLContextFree

删除一个OpenCL上下文并返回其句柄。

void  CLContextFree( 
   int  context     // 一个OpenCL上下文的句柄 
   );
1
2
3

参数

context

[in] OpenCL 上下文的句柄。

返回值

无。 在内部错误情况下 _LastError 的值会改变。想要获取有关错误的详细信息,请调用 GetLastError() 函数.

# 29.6 CLGetDeviceInfo

此函数从OpenCL驱动中接收设备的属性信息。

bool  CLGetDeviceInfo( 
   int     handle,          // OpenCL设备处理 
   int     property_id,     // 被请求的属性 ID  
   uchar&  data[],          // 数据接收数组 
   uint&   size             // 数组中的元素转换,默认为0 
   );
1
2
3
4
5
6

参数

handle

[in] 由CLContextCreate()函数创建的OpenCL设备索引 或 OpenCL句柄。

property_id

[in] 应接收的OpenCL设备属性的ID。这些值可能是下表中列出的枚举值之一。

data[]

[out] 用于接收所请求属性的数据的数组。

size

[out] 接收数据的数组 data[] 的大小.

返回值

如果成功则为true ,否则为 false. 想要获取有关错误的详细信息,请调用 GetLastError() 函数.

注意

对于一维数组,考虑AS_SERIES标帜计算从中读取OpenCL缓冲区的数据的元素的数量。

OpenCL设备属性的可用ID列表

可以在OpenCL官方网站(https://www.khronos.org/opencl/)上找到该属性及其功能的确切描述。

标识符

CL_DEVICE_TYPE

0x1000

CL_DEVICE_VENDOR_ID

0x1001

CL_DEVICE_MAX_COMPUTE_UNITS

0x1002

CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS

0x1003

CL_DEVICE_MAX_WORK_GROUP_SIZE

0x1004

CL_DEVICE_MAX_WORK_ITEM_SIZES

0x1005

CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR

0x1006

CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT

0x1007

CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT

0x1008

CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG

0x1009

CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT

0x100A

CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE

0x100B

CL_DEVICE_MAX_CLOCK_FREQUENCY

0x100C

CL_DEVICE_ADDRESS_BITS

0x100D

CL_DEVICE_MAX_READ_IMAGE_ARGS

0x100E

CL_DEVICE_MAX_WRITE_IMAGE_ARGS

0x100F

CL_DEVICE_MAX_MEM_ALLOC_SIZE

0x1010

CL_DEVICE_IMAGE2D_MAX_WIDTH

0x1011

CL_DEVICE_IMAGE2D_MAX_HEIGHT

0x1012

CL_DEVICE_IMAGE3D_MAX_WIDTH

0x1013

CL_DEVICE_IMAGE3D_MAX_HEIGHT

0x1014

CL_DEVICE_IMAGE3D_MAX_DEPTH

0x1015

CL_DEVICE_IMAGE_SUPPORT

0x1016

CL_DEVICE_MAX_PARAMETER_SIZE

0x1017

CL_DEVICE_MAX_SAMPLERS

0x1018

CL_DEVICE_MEM_BASE_ADDR_ALIGN

0x1019

CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE

0x101A

CL_DEVICE_SINGLE_FP_CONFIG

0x101B

CL_DEVICE_GLOBAL_MEM_CACHE_TYPE

0x101C

CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE

0x101D

CL_DEVICE_GLOBAL_MEM_CACHE_SIZE

0x101E

CL_DEVICE_GLOBAL_MEM_SIZE

0x101F

CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE

0x1020

CL_DEVICE_MAX_CONSTANT_ARGS

0x1021

CL_DEVICE_LOCAL_MEM_TYPE

0x1022

CL_DEVICE_LOCAL_MEM_SIZE

0x1023

CL_DEVICE_ERROR_CORRECTION_SUPPORT

0x1024

CL_DEVICE_PROFILING_TIMER_RESOLUTION

0x1025

CL_DEVICE_ENDIAN_LITTLE

0x1026

CL_DEVICE_AVAILABLE

0x1027

CL_DEVICE_COMPILER_AVAILABLE

0x1028

CL_DEVICE_EXECUTION_CAPABILITIES

0x1029

CL_DEVICE_QUEUE_PROPERTIES

0x102A

CL_DEVICE_NAME

0x102B

CL_DEVICE_VENDOR

0x102C

CL_DRIVER_VERSION

0x102D

CL_DEVICE_PROFILE

0x102E

CL_DEVICE_VERSION

0x102F

CL_DEVICE_EXTENSIONS

0x1030

CL_DEVICE_PLATFORM

0x1031

CL_DEVICE_DOUBLE_FP_CONFIG

0x1032

CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF

0x1034

CL_DEVICE_HOST_UNIFIED_MEMORY

0x1035

CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR

0x1036

CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT

0x1037

CL_DEVICE_NATIVE_VECTOR_WIDTH_INT

0x1038

CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG

0x1039

CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT

0x103A

CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE

0x103B

CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF

0x103C

CL_DEVICE_OPENCL_C_VERSION

0x103D

CL_DEVICE_LINKER_AVAILABLE

0x103E

CL_DEVICE_BUILT_IN_KERNELS

0x103F

CL_DEVICE_IMAGE_MAX_BUFFER_SIZE

0x1040

CL_DEVICE_IMAGE_MAX_ARRAY_SIZE

0x1041

CL_DEVICE_PARENT_DEVICE

0x1042

CL_DEVICE_PARTITION_MAX_SUB_DEVICES

0x1043

CL_DEVICE_PARTITION_PROPERTIES

0x1044

CL_DEVICE_PARTITION_AFFINITY_DOMAIN

0x1045

CL_DEVICE_PARTITION_TYPE

0x1046

CL_DEVICE_REFERENCE_COUNT

0x1047

CL_DEVICE_PREFERRED_INTEROP_USER_SYNC

0x1048

CL_DEVICE_PRINTF_BUFFER_SIZE

0x1049

CL_DEVICE_IMAGE_PITCH_ALIGNMENT

0x104A

CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT

0x104B

示例:
void OnStart() 
  { 
//---  
   int dCount= CLGetInfoInteger(0,CL_DEVICE_COUNT); 
   for(int i = 0; i<dCount; i++) 
     { 
      int clCtx=CLContextCreate(i); 
      if(clCtx == -1) 
         Print("ERROR in CLContextCreate"); 
      string device; 
      CLGetInfoString(clCtx,CL_DEVICE_NAME,device); 
      Print(i,": ",device); 
      uchar data[1024]; 
      uint size; 
      CLGetDeviceInfo(clCtx,CL_DEVICE_VENDOR,data,size); 
      Print("size = ",size); 
      string str=CharArrayToString(data); 
      Print(str); 
     } 
  } 
//--- example of entries in Experts journal 
//  2013.07.24 10:50:48     opencl (EURUSD,H1)      2: Advanced Micro Devices, Inc. 
//  2013.07.24 10:50:48     opencl (EURUSD,H1)      size = 32 
//  2013.07.24 10:50:48     opencl (EURUSD,H1)      Tahiti 
//  2013.07.24 10:50:48     opencl (EURUSD,H1)      Intel(R) Corporation 
//  2013.07.24 10:50:48     opencl (EURUSD,H1)      size = 21 
//  2013.07.24 10:50:48     opencl (EURUSD,H1)      1:        Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz 
//  2013.07.24 10:50:48     opencl (EURUSD,H1)      NVIDIA Corporation 
//  2013.07.24 10:50:48     opencl (EURUSD,H1)      size = 19 
//  2013.07.24 10:50:48     opencl (EURUSD,H1)      0: GeForce GTX 580

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 29.7 CLProgramCreate

从源代码创建一个OpenCL程序.

int  CLProgramCreate( 
   int           context,     // 一个OpenCL上下文的句柄 
   const string  source       // 源代码 
   );
1
2
3
4

重载函数版本创建OpenCL程序并将编译器消息写入传递的字符串。

int  CLProgramCreate( 
   int           context,     // Handle to an OpenCL context 
   const string  source,      // Source code 
   string       &build_log    // A string for receiving the compilation log 
   );
1
2
3
4
5

参数

context

[in] 一个OpenCL上下文的句柄。

source

[in] OpenCL程序源代码字符串。

&build_log

[in] 用于接收OpenCL编译器消息的字符串。

返回值

如果成功,则为OpenCL对象的句柄。想要获取有关错误的详细信息,请调用 GetLastError() 函数.

注意

目前,以下错误代码正在使用:
• ERR_OPENCL_INVALID_HANDLE —— OpenCL上下文的句柄无效。
• ERR_INVALID_PARAMETER —— 无效的字符串参数。
• ERR_NOT_ENOUGH_MEMORY —— 内存不足无法完成操作。
• ERR_OPENCL_PROGRAM_CREATE —— OpenCL 内部错误或编译错误。

在一些图形卡中默认禁止处理 双精度(double)类型数字。这可能会导致编译错误5105。若要启用支持 双精度(double)类型数字,请添加以下指令到您的OpenCL程序:

#pragma OPENCL EXTENSION cl_khr_fp64 : enable 更多详情请参考以下链接 https://www.khronos.org/registry/OpenCL/sdk/1.0/docs/man/xhtml/cl_khr_fp64.html

但是,如果图形卡不支持 双精度(double)型,启用该指令则不会有帮助。

示例:

//+------------------------------------------------------------------+ 
//| OpenCL kernel                                                    | 
//+------------------------------------------------------------------+ 
const string 
cl_src= 
       //--- 默认一些 GPU 不支持双精度类型 
       //--- cl_khr_fp64 指令用于启用处理双精度类型 
       "#pragma OPENCL EXTENSION cl_khr_fp64 : enable      \r\n" 
       //--- OpenCL 核函数 
       "__kernel void Test_GPU(__global double *data,      \r\n" 
       "                       const    int N,             \r\n" 
       "                       const    int total_arrays)  \r\n" 
       "  {                                                \r\n" 
       "   uint kernel_index=get_global_id(0);             \r\n" 
       "   if (kernel_index>total_arrays) return;          \r\n" 
       "   uint local_start_offset=kernel_index*N;         \r\n" 
       "   for(int i=0; i<N; i++)                          \r\n" 
       "     {                                             \r\n" 
       "       data[i+local_start_offset] *= 2.0;          \r\n" 
       "     }                                             \r\n" 
       "  }                                                \r\n"; 
//+------------------------------------------------------------------+ 
//| Test_CPU                                                         | 
//+------------------------------------------------------------------+ 
bool Test_CPU(double &data[],const int N,const int id,const int total_arrays) 
  { 
//--- 检查数组大小 
   if(ArraySize(data)==0) return(false); 
//--- 检查数组索引 
   if(id>total_arrays) return(false); 
//--- 通过索引id计算数组局部偏移 
   int local_start_offset=id*N; 
//--- 元素乘以2 
   for(int i=0; i<N; i++) 
     { 
      data[i+local_start_offset]*=2.0; 
     } 
   return true; 
  } 
//--- 
#define ARRAY_SIZE   100  // size of the array 
#define TOTAL_ARRAYS 5    // total arrays 
//--- OpenCL 处理程序 
int cl_ctx;  // OpenCL 内容处理 
int cl_prg;  // OpenCL 程序处理 
int cl_krn;  // OpenCL 核处理 
int cl_mem;  // OpenCL 缓冲处理 
//--- 
double DataArray1[]; // 用于CPU计算的数据数组 
double DataArray2[]; // 用于GPU计算的数据数组 
//+------------------------------------------------------------------+ 
//| 脚本程序起始函数                                   | 
//+------------------------------------------------------------------+ 
int OnStart() 
  { 
//--- 初始化OpenCL对象 
//--- 创建OpenCL 环境 
   if((cl_ctx=CLContextCreate())==INVALID_HANDLE) 
     { 
      Print("OpenCL not found. Error=",GetLastError()); 
      return(1); 
     } 
//--- 创建 OpenCL 程序 
   if((cl_prg=CLProgramCreate(cl_ctx,cl_src))==INVALID_HANDLE) 
     { 
      CLContextFree(cl_ctx); 
      Print("OpenCL program create failed. Error=",GetLastError()); 
      return(1); 
     } 
//--- 创建OpenCL 内核 
   if((cl_krn=CLKernelCreate(cl_prg,"Test_GPU"))==INVALID_HANDLE) 
     { 
      CLProgramFree(cl_prg); 
      CLContextFree(cl_ctx); 
      Print("OpenCL kernel create failed. Error=",GetLastError()); 
      return(1); 
     } 
//--- 创建 OpenCL 缓冲 
   if((cl_mem=CLBufferCreate(cl_ctx,ARRAY_SIZE*TOTAL_ARRAYS*sizeof(double),CL_MEM_READ_WRITE))==INVALID_HANDLE) 
     { 
      CLKernelFree(cl_krn); 
      CLProgramFree(cl_prg); 
      CLContextFree(cl_ctx); 
      Print("OpenCL buffer create failed. Error=",GetLastError()); 
      return(1); 
     } 
//--- 设置OpenCL 内核常量参数 
   CLSetKernelArgMem(cl_krn,0,cl_mem); 
   CLSetKernelArg(cl_krn,1,ARRAY_SIZE); 
   CLSetKernelArg(cl_krn,2,TOTAL_ARRAYS); 
//--- 准备数据数组 
   ArrayResize(DataArray1,ARRAY_SIZE*TOTAL_ARRAYS); 
   ArrayResize(DataArray2,ARRAY_SIZE*TOTAL_ARRAYS); 
//--- 用数据填写数组 
   for(int j=0; j<TOTAL_ARRAYS; j++) 
     { 
      //--- 计算 jth 数组局部开始偏移 
      uint local_offset=j*ARRAY_SIZE; 
      //--- 准备 j 索引数组 
      for(int i=0; i<ARRAY_SIZE; i++) 
        { 
         //--- 用MathCos(i+j)函数填写数组; 
         DataArray1[i+local_offset]=MathCos(i+j); 
         DataArray2[i+local_offset]=MathCos(i+j); 
        } 
     }; 
//--- 测试CPU 计算 
   for(int j=0; j<TOTAL_ARRAYS; j++) 
     { 
      //--- 计算 j 索引数组  
      Test_CPU(DataArray1,ARRAY_SIZE,j,TOTAL_ARRAYS); 
     } 
//--- 准备 CLExecute 参数 
   uint  offset[]={0}; 
//--- 全局工作大小 
   uint  work[]={TOTAL_ARRAYS}; 
//--- 编写数据到 OpenCL 缓冲 
   CLBufferWrite(cl_mem,DataArray2); 
//--- 执行OpenCL 内核 
   CLExecute(cl_krn,1,offset,work); 
//--- 从OpenCL缓冲阅读数据 
   CLBufferRead(cl_mem,DataArray2); 
//--- 总误差 
   double total_error=0; 
//--- 比较结果和计算误差 
   for(int j=0; j<TOTAL_ARRAYS; j++) 
     { 
      //--- 计算 jth 数组局部偏移 
      uint local_offset=j*ARRAY_SIZE; 
      //--- 比较结果 
      for(int i=0; i<ARRAY_SIZE; i++) 
        { 
         double v1=DataArray1[i+local_offset]; 
         double v2=DataArray2[i+local_offset]; 
         double delta=MathAbs(v2-v1); 
         total_error+=delta; 
         //--- 显示初始和最后的数组 
         if((j==0) || (j==TOTAL_ARRAYS-1)) 
            PrintFormat("array %d of %d, element [%d]:  %f, %f, [error]=%f",j+1,TOTAL_ARRAYS,i,v1,v2,delta); 
        } 
     } 
   PrintFormat("Total error: %f",total_error); 
//--- 删除OpenCL 对象 
//--- 释放 OpenCL 缓冲 
   CLBufferFree(cl_mem); 
//--- 释放 OpenCL 内核 
   CLKernelFree(cl_krn); 
//--- 释放 OpenCL 程序 
   CLProgramFree(cl_prg); 
//--- 释放 OpenCL 环境 
   CLContextFree(cl_ctx); 
//--- 
   return(0); 
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

# 29.8 CLProgramFree

删除一个OpenCL程序.

void  CLProgramFree( 
   int  program     // 一个OpenCL句柄 
   );
1
2
3

参数

program

[in] OpenCL句柄。

返回值

无。 在内部错误情况下 _LastError 的值会改变。想要获取有关错误的详细信息,请调用 GetLastError() 函数。

# 29.9 CLKernelCreate

创建OpenCL程序内核并返回其句柄。

int  CLKernelCreate( 
   int           program,        // 一个OpenCL句柄 
   const string  kernel_name     // 内核名称 
   );
1
2
3
4

参数

program

[in] 一个OpenCL句柄。

kernel_name

[in] 适当的OpenCL程序中的内核函数的名称,执行开始。

返回值

如果成功将创建一个OpenCL句柄。一旦出错 返回-1。 想要获取有关错误的详细信息,请调用 GetLastError() 函数.

注意

目前,以下错误代码正在使用:
• ERR_OPENCL_INVALID_HANDLE —— 无效的 OpenCL的句柄。
• ERR_INVALID_PARAMETER —— 无效的字符串参数。
• ERR_OPENCL_TOO_LONG_KERNEL_NAME —— 内核名称超过127个字符。
• ERR_OPENCL_KERNEL_CREATE —— 创建OpenCL对象时发生的内部错误。

# 29.10 CLKernelFree

删除一个OpenCL启动函数.

void  CLKernelFree( 
   int  kernel     // 处理OpenCL程序的内核 
   );
1
2
3

参数

kernel_name

[in] 处理OpenCL程序的内核。

返回值

无。 在内部错误情况下 _LastError 的值会改变。想要获取有关错误的详细信息,请调用 GetLastError() 函数。

# 29.11 CLSetKernelArg

为OpenCL函数设置一个参数。

bool  CLSetKernelArg( 
   int   kernel,        // 处理一个OpenCL程序内核 
   uint  arg_index,     // OpenCL函数幅角的数量 
   void  arg_value      // 源代码 
   );
1
2
3
4
5

参数

kernel

[in] 处理一个OpenCL程序内核.

arg_index

[in] 函数参数的编号,编号从零开始。

arg_value

[in] 函数参数的值.

返回值

如果成功则返回true, 否则返回false。想要获取有关错误的详细信息,请调用 GetLastError() 函数.

注意

目前,以下错误代码正在使用:
• ERR_INVALID_PARAMETER —— 无效的参数
• ERR_OPENCL_INVALID_HANDLE —— OpenCL内核的句柄无效
• ERR_OPENCL_SET_KERNEL_PARAMETER —— OpenCL内部错误

# 29.12 CLSetKernelArgMem

设置一个OpenCL缓冲作为OpenCL函数的参数。

bool  CLSetKernelArgMem( 
   int   kernel,           // 处理一个OpenCL程序的内核 
   uint  arg_index,        // OpenCL函数参数的数量 
   int   cl_mem_handle     // 处理一个OpenCL缓冲 
   );
1
2
3
4
5

参数

kernel

[in] 处理一个OpenCL程序的内核。

arg_index

[in] 函数参数的编号,编号从零开始。

cl_mem_handle

[in] 一个OpenCL缓冲处理句柄。

返回值

如果成功则返回true, 否则返回false。想要获取有关错误的详细信息,请调用 GetLastError() 函数.

# 29.13 CLSetKernelArgMemLocal

设置本地缓冲区作为内核函数参数。

bool  CLSetKernelArgMemLocal( 
   int    kernel,           // 处理OpenCL程序的内核 
   uint   arg_index,        // OpenCL函数参数的数值 
   ulong  local_mem_size    // 缓冲区大小 
   );
1
2
3
4
5

参数

kernel

[in] 处理OpenCL程序的内核。

arg_index

[in] 函数参数的编号,编号从零开始。

local_mem_size

[in] 缓冲区的字节大小。

返回值

如果成功返回true,否则返回false。想要获取有关错误的详细信息,请调用 GetLastError() 函数.

# 29.14 CLBufferCreate

创建一个OpenCL缓冲并返回其句柄。

int  CLBufferCreate( 
   int   context,     // 一个OpenCL 上下文句柄 
   uint  size,        // 缓冲大小 
   uint  flags        // 指定OpenCL缓冲性能的标志组合  
   );
1
2
3
4
5

参数

context

[in] 一个OpenCL 上下文句柄。

size

[in] 缓冲字节大小。

flags

[in] 使用组合标帜的缓冲性能: CL_MEM_READ_WRITE, CL_MEM_WRITE_ONLY, CL_MEM_READ_ONLY, CL_MEM_ALLOC_HOST_PTR。

返回值

如果成功,则返回OpenCL缓冲的句柄。 一旦出错 返回-1。想要获取有关错误的详细信息,请调用 GetLastError() 函数.

注意

目前,以下错误代码正在使用:
• ERR_OPENCL_INVALID_HANDLE —— 无效的OpenCL上下文句柄。
• ERR_NOT_ENOUGH_MEMORY —— 内存不足。
• ERR_OPENCL_BUFFER_CREATE —— 创建缓冲区时发生内部错误。

# 29.15 CLBufferFree

删除OpenCL缓冲。

void  CLBufferFree( 
   int   buffer     // 一个OpenCL缓冲句柄 
   );
1
2
3

参数

buffer

[in] 一个OpenCL缓冲句柄。

返回值

无。 在内部错误情况下 _LastError 的值会改变。想要获取有关错误的详细信息,请调用 GetLastError() 函数。

# 28.16 CLBufferWrite

写入OpenCL缓冲区并返回写入元素的数量。

uint  CLBufferWrite( 
   int          buffer,                    // 一个OpenCL缓冲句柄 
   const void&  data[],                    // 值的数组 
   uint         buffer_offset=0,           // 字节区偏移的OpenCL缓冲,默认为0 
   uint         data_offset=0,             // 元素中数组的偏移,默认为0 
   uint         data_count=WHOLE_ARRAY     // 从阵列写入的值的数量,默认整个阵列 
   );
1
2
3
4
5
6
7

参数

buffer

[in] 一个OpenCL缓冲句柄。

data[]

[in] 应该在OpenCL缓冲区中写入的值数组。 通过引用传递。

buffer_offset

[in] OpenCL缓冲区中的偏移量,以字节为单位,从中开始写入。默认情况下,从缓冲区的开头开始写入。

data_offset

[in] 第一个数组元素的索引,从数组中的值开始写入OpenCL缓冲区。默认情况下,从数组的最开始处获取值。

data_count

[in] 应写入的值的数量。 默认情况下,为该数组的所有值。

返回值

写入元素的数量. 错误情况下返回0。想要获取有关错误的详细信息,请调用 GetLastError() 函数。

注意

对于一维数组,在读取数据用于写入OpenCL缓冲区的元素时,计算的数量,是在考虑了AS_SERIES标帜的情况下得出的。

一个二维或多维的数组被表示为一维时。在这种情况下,data_offset是表示中应该跳过的元素数量,而不是第一个维度中的元素数量。

# 29.17 CLBufferRead

读取OpenCL缓冲区并返回写入元素的数量。

uint  CLBufferRead( 
   int          buffer,                    // 处理一个OpenCL缓冲 
   const void&  data[],                    // 一个值的数组 
   uint         buffer_offset=0,           // 在字节缓冲区偏移的OpenCL,默认为0 
   uint         data_offset=0,             // 在元素的数组的偏移量,默认为0 
   uint         data_count=WHOLE_ARRAY     // 用于读取的缓冲值的个数,默认为整个缓冲区 
   );
1
2
3
4
5
6
7

参数

buffer

[in] 一个OpenCL缓冲句柄。

data[]

[in] 用于从OpenCL缓冲区接收值的数组。 通过引用传递。

buffer_offset

[in] OpenCL缓冲区中的偏移量,以字节为单位,从中开始写入。默认情况下,从缓冲区的开头开始写入。

data_offset

[in] 第一个数组元素的索引,从数组中的值开始写入OpenCL缓冲区。默认情况下,从数组的最开始处获取值。

data_count

[in] 应读取的值的数量。默认情况下,为该数组的所有值。

返回值

读取元素的数量. 错误情况下返回0。想要获取有关错误的详细信息,请调用 GetLastError() 函数。

注意

对于一维数组,在读取数据用于写入OpenCL缓冲区的元素时,计算的数量,是在考虑了AS_SERIES标帜的情况下得出的。

一个二维或多维的数组被表示为一维时。在这种情况下,data_offset是表示中应该跳过的元素数量,而不是第一个维度中的元素数量。

# 29.18 CLExecute

此函数运行一个 OpenCL程序。有三个版本的变体:

  1. 用一个内核启动内核函数
bool  CLExecute( 
   int          kernel                    // 处理一个OpenCL程序的内核 
   );
1
2
3
  1. 启动几个内核副本 (OpenCL函数) 与任务空间描述
bool  CLExecute( 
   int          kernel,                   // 处理一个OpenCL程序的内核 
   uint         work_dim,                 // 任务空间维度 
   const uint&  global_work_offset[],     // 在任务空间初始偏移 
   const uint&  global_work_size[]        // 任务总数 
   );
1
2
3
4
5
6
  1. 启动几个内核副本 (OpenCL函数) 与任务空间描述以及集合本地任务子集大小规范
bool  CLExecute( 
   int          kernel,                   // 处理一个OpenCL程序的内核 
   uint         work_dim,                 // 任务空间维度 
   const uint&  global_work_offset[],     // 在任务空间初始偏移 
   const uint&  global_work_size[],       // 任务总数 
   const uint&  local_work_size[]         // 在本地集合中的任务数 
   );
1
2
3
4
5
6
7

参数

kernel

[in] 处理OpenCL内核。

work_dim

[in] 任务空间维度。

global_work_offset[]

[in] 在任务空间初始偏移。

global_work_size[]

[in] 任务子集大小。

local_work_size[]

[in] 集合本地任务子集大小。

返回值

如果成功则返回true, 否则返回false。 想要获取有关错误的详细信息,请调用 GetLastError() 函数。

注意

以下例子中要考虑参数的使用:
• work_dim 指定 work_items[] 描述任务的阵列维度. 如果work_dim=3,三维阵列work_items[N1, N2, N3] 将被使用。
• global_work_size[] 包含设定 work_items[]阵列大小的值. 如果 work_dim=3, global_work_size[3] 阵列将是 {40, 100, 320}。 然后我们将得到 work_items[40, 100, 320]。 所以,任务总数是 is 40 x 100 x 320 = 1 280 000。
• local_work_size[] 设定任务的子集将由OpenCL程序的指定内核来执行。 其维度等于 work_items[] 维度并允许共同任务子集精确分割成更小的子集。 事实上,应当选择 local_work_size[] 从而使全局任务设定分割成更小的子集。

local_work_size[3]={10, 10, 10} 将适合当前的例子, 比如work_items[40, 100, 320] 能被 local_items[10, 10, 10] 阵列毫无剩余的收集起来。

# 29.19 CLExecutionStatus

返回OpenCL程序执行状态。

bool  CLExecutionStatus( 
   int   kernel            // 处理OpenCL程序的内核 
   );
1
2
3

参数

kernel

[in] 处理OpenCL程序的内核。

返回值

返回OpenCL程序状态。该值可以是以下值的其中一个:
• CL_COMPLETE=0 —— 程序完成,
• CL_RUNNING=1 —— 运行,
• CL_SUBMITTED=2 —— 提交执行,
• CL_QUEUED=3 —— 排队,
• -1 (负1) —— 执行CLExecutionStatus()时出现错误。