四、建立命令队列(Command Queue):
命令队列是主机端向上下文中其他设备发送请求的行为机制,主机通过命令队列建立与其他内核的通信,控制其他计算单元完成相关的操作行为。在同一个上下文中可同时存在多个命令队列,每个命令队列只关联一个设备。在命令队列中,一系列命令按照主机端命令发送的先后顺序排队,并在设备端依次执行。
创建命令队列可以使用:
cl_command_queue clCreateCommandQueue( cl_comtext context,
cl_device_id device,
cl_command_queue_properties properties,
cl_int *errcode_ret)
该函数第一个参数是命令队列所处的上下文;
第二个参数是命令队列所连接的设备,该设备必须处于第一个参数所表示的上下文中;
第三个参数指定命令队列的一系列属性,包括设置命令的执行顺序等;
第四个参数返回错误码。
如果建立上下文完成,该函数返回一个非0的上下文。
查询命令队列信息可使用:
cl_int clGetCommandQueueInfo(cl_command_queue command_queue,
cl_command_queue_info qaram_name,
size_t param_vallue_size,
void *param_value,
size_t *param_value_size_ret)
该函数第一个参数为指定要查询的命令队列;
第二个参数确定要查询的信息;
第三个参数指向查询的结果;
第四个参数确定保存查询结果的内存大小,为NULL时忽略;
第五个参数为查询结果实际的大小,为NULL时忽略;
使用示例:
cl_int ret; //用于保存函数返回值
cl_context_properties context_props[] = { CL_CONTEXT_PLATFORM, (cl_context_properties)platform[1], 0 }; //用于设置命令队列属性
size_t ext_size; //用于保存命令队列信息大小
char *ext_data; //用于保存命令队列信息
cl_platform_info command_queue_info = CL_QUEUE_COMTEXT; //设置所要查询的信息
//
//建立命令队列
cl_context command_queue = clCreateContext(context, device, context_props, &ret);
//
//获取命令队列信息大小
ret = clGetCommandQueueInfo(command_queue, command_queue_info, context_props, NULL, ext_size)
//
//为ext_data分配空间大小
ext_data = new char[ext_size];
//
//获取命令队列信息
ret = clGetCommandQueueInfo(command_queue, command_queue_info, ext_size, ext_data, NULL);
std::cout << ext_data << std::endl; //输出命令队列信息
五、创建内存对象:
在异构计算中,主机无法直接使用其他设备的存储资源,而是通过内存对象来对设备的存储加以管理,包括向设备拷贝数据以及从设备拷贝数据到主机。一般对于核函数的输入及输出来说,都要建立相应的内存对象。
创建缓冲内存对象可以使用:
cl_mem clCreateBuffer(cl_context context,
cl_mem_flags flags,
size_t size,
void *host_ptr,
cl_int *errcode_ret)
该函数第一个参数为设备所在上下文;
第二个参数指定内存对象的属性,包括可读可写性以及传递方式等;
第三个参数表示缓冲内存对象的大小;
第四个参数执行分配的缓冲数据;
第五个参数返回错误码。
从主机向缓冲内存对象写入数据和从缓冲内存对向主机内存中读入数据可使用:
cl_int clEnqueueWriteBuffer(cl_command_queue command_queue,
cl_mem buffer,
cl_bool blocking_write,
void size_t offset,
size_t cb,
const void *ptr,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
cl_int cl_EnqueueReadBuffer(cl_command_queue command_queue,
cl_mem buffer,
cl_bool blocking_write,
void size_t offset,
size_t cb,
const void *ptr,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event)
该函数第一个参数为存在于缓冲内存对象所在上下文的命令队列;
第二个参数为一个有效的缓冲内存对象;
第三个参数指定读写是阻塞的还是非阻塞的;
第四个参数为读写操作在缓冲内存对象上的偏移量。
第五个参数为要读写的字节大小;
第六个参数指向要从主机内存读写的数据;
第七、八参数指定在执行此命令前必须完成的事件及其个数;
第九个参数返回标识读写命令的事件;
在程序中,这条语句会向命令队列中加入读写该缓冲内存对象的命令,可通过函数返回的事件对象来确定此命令的执行状态,这点会在之后的事件对象部分加以详述。
使用示例:
cl_int ret; //用于保存函数返回值
int input[5] = [1,2,3,4,5]; //存放向缓冲内存区域写入的数据
int *output = new int[5]; //存放从缓冲内存区域读出的数据
cl_enent enent; //存放读写命令的事件对象
//
//创建可读可写缓冲内存对象
cl_mem data = clCreateBuffer(context, CL_MEM_READ_WRITE, (size_t)(5 * sizeof(int)), NULL, &ret)
//
//向缓冲内存对象写入数据
ret = clEnqueueWriteBuffer(command_queue, data , CL_TRUE, 0, (size_t)(5 * sizeof(int)), input, NULL, NULL, &enent)
//
//从缓冲内存对象读出数据
ret = clEnqueueReadBuffer(command_queue, data , CL_TRUE, 0, (size_t)(5 * sizeof(int)), output, NULL, NULL, &enent)
for(unsigned int i = 0; i < 5; ++i)
{
std::cout << output[i] << std::endl; //输出命令队列信息
}
完成了命令队列以及核函数所需的每个内存对象的创建后,就可以开始着手构建核函数、建立程序对象并执行核函数了。(To Be Continued)