0

基于 Mali 600 gpu 的 OpenCL 指南,应使用 CL_MEM_ALLOC_HOST_PTR 删除任何数据副本并提高性能。

今天,我在具有 Mali 604 gpu 的 Arndale 板上使用 CL_MEM_ALLOC_HOST_PTR 测试内存复制时间。我用 CL_MEM_ALLOC_HOST_PTR 和 clEnqueueWriteBuffer 进行了测试。我发现,如果我使用 CL_MEM_ALLOC_HOST_PTR,总体上我并没有得到太多的性能提升。因为 clEnqueueMap 函数花费的时间几乎与 clEnqueueWriteBuffer 相同。这个测试是在向量加法上完成的。

我是如何测试的:我没有使用 malloc 创建指针并将数据传输到设备,而是首先使用 CL_MEM_ALLOC_HOST_PTR 创建了一个缓冲区。然后我使用 OpenCL API 映射了这个缓冲区。这返回一个指针,我用数据填充了这个指针指向的内存。这种情况下的映射机制需要时间。映射时间几乎等于 clENqueuewritebuffer。因此,从这个示例中,我没有使用 CL_MEM_ALLOC_HOST_PTR 获得任何显着改进。

我的问题是,当我使用 CL_MEM_ALLOC_HOST_PTR 时,为什么映射时间这么长?

这是性能测量:元素大小:10000000,内核:向量加法,所有时间都以微秒为单位

正常读写缓冲时间 缓冲区创建时间 20 入队写入缓冲时间 108019

CL_MEM_ALLOC_HOST_PTR - 在分配的缓冲区时间内直接复制数据 用数据填充 clEnqueueMap 返回的指针 208009 映射时间 81346 取消映射时间 269

CL_MEM_ALLOC_HOST_PTR - 使用 memcpy 将数据从 malloc 指针复制到主机分配指针 时间映射时间 64134 取消映射时间 190 memcpy 时间(将数据从已创建的 malloc 指针复制到主机分配的固定指针)
56987

这是我用于 Host_alloc_ptr 的代码片段:

start = getTime();
    a_st=getTime();
    bufferA = clCreateBuffer(context,  CL_MEM_ALLOC_HOST_PTR, sizeof(cl_float) * ELE_NUM, NULL, &err);
    cl_float* src_a=(cl_float*)clEnqueueMapBuffer(commandQueue, bufferA,CL_TRUE,CL_MAP_WRITE, 0, sizeof(cl_float) * ELE_NUM, 0, NULL, NULL, &err);

    bufferB = clCreateBuffer(context, CL_MEM_ALLOC_HOST_PTR, sizeof(cl_float) * ELE_NUM, NULL, &err);
    cl_float* src_b=(cl_float*)clEnqueueMapBuffer(commandQueue, bufferB,CL_TRUE,CL_MAP_WRITE, 0, sizeof(cl_float) * ELE_NUM, 0, NULL, NULL, &err);
    clFinish(commandQueue);
    a_en=getTime();
    a_time=a_time+(a_en-a_st);

    pfill_s=getTime();
    for (int i = 0; i < ELE_NUM; i++){
        src_a[i] = 100.0;
        src_b[i] = 11.1;

    }
    pfill_e=getTime();
    pfill_time=pfill_time+(pfill_e-pfill_s);

    b_st=getTime();
    clEnqueueUnmapMemObject(commandQueue, bufferB, src_b, 0, NULL, NULL);
    clEnqueueUnmapMemObject(commandQueue, bufferA, src_a, 0, NULL, NULL);
    clFinish(commandQueue);
    b_en=getTime();
    b_time=b_time+(b_en-b_st);


    end = getTime();
    creat_buffer += (end-start);
    bufferC = clCreateBuffer(context, CL_MEM_ALLOC_HOST_PTR, sizeof(cl_float) * ELE_NUM, NULL, &err);
4

1 回答 1

0

根据您的源代码,您正在测量 OpenCL 主机端的操作时间。通常,它给出的结果很差,因为您获得的时间由 OpenCL 设备端操作时间(需要)+ 各种开销组成。OpenCL 事件是性能测量和任务同步的强大工具,可用于获取准确的操作时间。要查看内存映射在速度方面的工作原理,我建议您运行以下代码:

static void checkError(cl_int ret_code, int line)
{
    if(ret_code != CL_SUCCESS){
        fprintf(stderr, "Error %d happened at line %d.\n", ret_code, line);
    }
}

static long getRunTime(cl_event evt){
    cl_ulong 
        start = 0, 
        end   = 0;

    cl_int ret = CL_SUCCESS;

    ret = clWaitForEvents(1, event);
    checkError(ret, __LINE__);

    ret = clGetEventProfilingInfo(*event, CL_PROFILING_COMMAND_START,
            sizeof(cl_ulong), &start, NULL);
    checkError(ret, __LINE__);

    ret = clGetEventProfilingInfo(*event, CL_PROFILING_COMMAND_END, sizeof(cl_ulong),
            &end, NULL);
    checkError(ret, __LINE__);

    return end - start;
}

int 
    kilobyte = 1024,
    megabyte = kilobyte * 1024;

cl_int ret = CL_SUCCESS;

for(int size = 64 * kilobyte; size < 10 * megabyte; size *= 2){
    cl_mem buff1 = clCreateBuffer(some_cl_context, CL_MEM_ALLOC_HOST_PTR, size, &ret);
    checkError(ret, __LINE__);

    cl_mem buff2 = clCreateBuffer(some_cl_context, CL_MEM_READ_WRITE, size, &ret);
    checkError(ret, __LINE__);

    void *host_buffer = malloc(size);
    cl_event evt;

    // Checking clEnqueueMapBuffer time
    void *mapped = clEnqueueMapBuffer(..., buff1, ..., &evt, &ret);
    checkError(ret, __LINE__);

    long time = getRunTime(evt);
    fprintf(stdout, "clEnqueueMapBuffer: size: %d bytes time: %l nanoseconds.\n");

    clEnqueueUnmapMemObject(..., buff1, ...);

    // Checking clEnqueueReadBuffer from CL_MEM_ALLOC_HOST_PTR
    ret  = clEnqueueReadBuffer(..., buff1, ..., host_buffer, ..., size, ..., &evt);
    checkError(ret, __LINE__);

    time = getRunTime(evt);
    fprintf(stdout, "clEnqueueReadBuffer from CL_MEM_ALLOC_HOST_PTR: size: %d bytes time: %l nanoseconds.\n");

    // Checking clEnqueueReadBuffer from CL_MEM_READ_WRITE
    ret  = clEnqueueReadBuffer(..., buff2, ..., host_buffer, ..., size, ..., &evt);
    checkError(ret, __LINE__);

    time = getRunTime(evt);
    fprintf(stdout, "clEnqueueReadBuffer from CL_MEM_READ_WRITE: size: %d bytes time: %l nanoseconds.\n");

    clReleaseMemObject(buff1);
    clReleaseMemObject(buff2);
    free(host_buffer);
}

请提供您将获得的时间结果。

于 2014-07-06T13:31:41.567 回答