Memory management clEnqueueMap需要很长时间,几乎相当于ClenqueueWriteBuffer

Memory management clEnqueueMap需要很长时间,几乎相当于ClenqueueWriteBuffer,memory-management,opencl,gpu,mali,Memory Management,Opencl,Gpu,Mali,根据适用于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函数与clEnqueue

根据适用于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创建了一个缓冲区。然后我使用OpenCLAPI映射了这个缓冲区。这返回一个指针,我用数据填充了指针指向的内存。这种情况下的映射机制需要时间。映射时间几乎等于clENqueuewritebuffer。因此,在这个例子中,我使用CL_MEM_ALLOC_HOST_PTR并没有得到任何显著的改进

我的问题是,当我使用CL\u MEM\u ALLOC\u HOST\u PTR时,为什么映射时间这么长?

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

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

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

CL_MEM_ALLOC_HOST_PTR—使用memcpy Time将数据从malloc指针复制到主机ALLOC指针 映射时间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);
start=getTime();
a_st=getTime();
bufferA=clCreateBuffer(上下文、CL_MEM_ALLOC_HOST_PTR、sizeof(CL_float)*ELE_NUM、NULL和err);
cl_float*src_a=(cl_float*)clenqueueemapbuffer(commandQueue,bufferA,cl_TRUE,cl_MAP_WRITE,0,sizeof(cl_float)*ELE NUM,0,NULL,NULL,err);
bufferB=clCreateBuffer(上下文、CL_MEM_ALLOC_HOST_PTR、sizeof(CL_float)*ELE_NUM、NULL和err);
cl_float*src_b=(cl_float*)clenqueueemapbuffer(commandQueue,bufferB,cl_TRUE,cl_MAP_WRITE,0,sizeof(cl_float)*ELE NUM,0,NULL,NULL,err);
clFinish(命令队列);
a_en=getTime();
a_时间=a_时间+(a_en-a_st);
pfill_s=getTime();
for(int i=0;i
根据您的源代码,您正在测量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);
}
静态无效检查错误(cl_int ret_code,int line)
{
如果(返回代码!=成功返回){
fprintf(stderr,“第%d行发生错误。\n”,返回代码,第行);
}
}
静态长getRunTime(cl_事件evt){
克莱乌隆
开始=0,
结束=0;
cl_int ret=cl_成功;
ret=clWaitForEvents(1,事件);
检查错误(ret、线);
ret=clGetEventProfilingInfo(*事件,CL_PROFILING_命令\u启动,
sizeof(cl_ulong),&start,NULL);
检查错误(ret、线);
ret=clGetEventProfilingInfo(*事件,CL_PROFILING_命令,sizeof(CL_ulong),
&结束,空);
检查错误(ret、线);
返回结束-开始;
}
int
KB=1024,
兆字节=千字节*1024;
cl_int ret=cl_成功;
用于(整数大小=64*KB;大小<10*MB;大小*=2){
cl_mem buff1=clCreateBuffer(一些上下文、cl_mem_ALLOC_主机、大小和ret);
检查错误(ret、线);
cl\u mem buff2=clCreateBuffer(一些上下文、cl\u mem\u读写、大小和ret);
检查错误(ret、线);
void*host\u buffer=malloc(大小);
cl_事件evt;
//检查clEnqueueMapBuffer时间
void*mapped=clEnqueueMapBuffer(…,buff1,…,evt,&ret);
检查错误(ret、线);
长时间=getRunTime(evt);
fprintf(标准输出,“clenqueemapbuffer:大小:%d字节时间:%l纳秒。\n”);
clEnqueueUnmapMemObject(…,buff1,…);
//正在从CL_MEM_ALLOC_HOST_PTR检查clEnqueueReadBuffer
ret=CLENQUEUREADBUFFER(…,buff1,…,主机缓冲区,…,大小,&evt);
检查错误(ret、线);
时间=getRunTime(evt);
fprintf(标准输出,“CL_MEM_ALLOC_HOST的clEnqueueReadBuffer:大小:%d字节时间:%l纳秒。\n”);
//从CL_MEM_READ_WRITE检查clEnqueueReadBuffer
ret=CLENQUEUREADBUFFER(…,buff2,…,主机缓冲区,…,大小,&evt);
检查错误(ret、线);
时间=getRunTime(evt);
fprintf(标准输出,“CL_MEM_读写的clEnqueueReadBuffer:大小:%d字节时间:%l纳秒。\n”);
clreleasemobject(buff1);
clreleasemobject(buff2);
空闲(主机缓冲区);
}

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

谢谢您的回复。我会在得到数据后进行更新。实际上,我也使用了相同的时间测量方法来计算clENqueueWriteBuffer的时间。因此,在这两种情况下,我都在测量主机端时间,并基于该clE