【问题标题】:why it's so slow in data exchanging between CPU and GPU memory?为什么CPU和GPU内存之间的数据交换如此缓慢?
【发布时间】:2015-05-24 15:45:42
【问题描述】:

这是我第一次在 ARM 上使用 openCL(CPU:Qualcomm Snapdragon MSM8930,GPU:Adreno(TM)305)。

我发现使用 openCL 确实非常有效,但是 CPU 和 GPU 之间的数据交换需要太多时间,我无法成像。

这是一个例子:

cv::Mat mat(640,480,CV_8UC3,cv::Scalar(0,0,0));
cv::ocl::oclMat mat_ocl;

//cpu->gpu
mat_ocl.upload(mat);
//gpu->cpu
mat = (cv::Mat)mat_ocl;

就这样一张小图,上传选项需要10ms,下载选项需要20ms!这需要的时间太长了。

谁能告诉我这种情况正常吗?或者这里出了什么问题?

提前谢谢你!

添加:

我的打法是

clock_t start,end;
start=clock();
mat_ocl.upload(mat);
end = clock();
__android_log_print(ANDROID_LOG_INFO,"tag","upload time = %f s",(double)(end-start)/CLOCKS_PER_SEC);

实际上,我并没有完全使用 openCL,而是 openCV 中的 ocl 模块(尽管它说它们是相等的)。在阅读openCV文档时,我发现它只是告诉我们将cv::Mat转换为cv::ocl::oclMat(即从CPU上传到GPU的数据)来进行GPU计算,但我没有找到内存映射方法ocl 模块文档。

【问题讨论】:

  • 您如何衡量上传/下载时间?
  • 您的传输硬件带宽是多少?
  • 我还没有找到硬件带宽参数,只能说处理器是高通骁龙MSM8930,GPU是Adreno(TM)305。
  • rossi_lhf,你的操作系统是什么? clock() 通常是最不精确的(在某些配置为将所有报告时间四舍五入为 10 毫秒的内核上),尝试使用 gettimeofday()clock_gettime() 测量时间 - 检查 stackoverflow.com/questions/8594277/clock-precision-in-time-h。您还可以测量多个复制操作的时间(循环 10 次上传,或 50 次上传)
  • 我的操作系统是 android 4.2.2。实际上,我确实测量了几次复制操作的时间,所以时间 10ms 和 20ms 是平均时间。

标签: opencv arm opencl gpu


【解决方案1】:

好吧,我在 openCV doc 中找到了一些有用的介绍:

在异构设备环境中,可能存在与数据传输相关的成本。例如,当数据需要从主机内存(CPU 可访问)移动到设备内存(离散 GPU 可访问)时,就会出现这种情况。在集成图形芯片的情况下,可能存在性能问题,这与从集成设备的 GPU“部分”或 CPU“部分”进行访问之间的内存一致性有关。为获得最佳性能,无论哪种情况,都建议您不要在 CPU 和离散 GPU 之间引入数据传输,算法管道的开头和结尾除外。

所以,这似乎解释了 CPU 和 GPU 之间的数据传输速度如此缓慢的原因。但我仍然不知道如何解决这个问题。

【讨论】:

  • 这应该是对 OP 的评论或编辑
【解决方案2】:

提供准确的测量方法和结果。

根据 ARM 平台(不是 Qcom)下的 OpenCL 开发经验,我可以说你不应该期望太多的读写操作。内存总线通常是 64 位的,加上 DDR3 不是那么快。

使用共享内存以获得优势 - 使用映射/取消映射而不是读取/写入。

P。 S. 实际运行时间测量,使用cl_event profiling:

cl_ulong getTimeNanoSeconds(cl_event event)
{
    cl_ulong start = 0, end = 0;

    cl_int ret = clWaitForEvents(1, &event);
    if (ret != CL_SUCCESS)
        throw(ret);

    ret = clGetEventProfilingInfo(
              event,
              CL_PROFILING_COMMAND_START,
              sizeof(cl_ulong),
              &start,
              NULL);
    if (ret != CL_SUCCESS)
        throw(ret);

    ret = clGetEventProfilingInfo(
              event,
              CL_PROFILING_COMMAND_END,
              sizeof(cl_ulong),
              &end,
              NULL);
    if (ret != CL_SUCCESS)
        throw(ret);

    return (end - start);
}

【讨论】:

  • 我的测量方法是:'clock_t start, end;' 'start = clock();' 'mat_ocl.upload(mat);' '结束 = 时钟();' '__android_log_print(ANDROID_LOG_INFO,"tag","上传时间 = %f s",(double)(end-start)/CLOCKS_PER_SEC);'
  • 4张640x480xCV_8UC3的图片,上传时间0.0569s,下载时间0.1137s
  • 您正在测量 OpenCV 函数的整个执行时间,该函数包裹在 OpenCL clEnqueueReadBuffer (clEnqueueReadImage) 函数中。实际 IO 时间可以通过前面提到的函数生成 cl_event 并获取配置文件信息来测量
  • 我的时间测量方法确实不准确,但是根据opencv doc介绍(我粘贴在answer2中),我认为主要问题可能是集成芯片的读/写速度。所以我应该尝试共享内存方法。谢谢你的建议!
  • 如果你有足够的时间,我强烈建议你深入研究 OpenCV 类并实现内存映射的能力 - 取消映射而不是读取 - 写入,这将为移动设备的 OpenCL 开发带来意义.
猜你喜欢
  • 2019-09-23
  • 1970-01-01
  • 1970-01-01
  • 2013-02-07
  • 1970-01-01
  • 2021-12-29
  • 2012-08-17
  • 1970-01-01
  • 2017-07-15
相关资源
最近更新 更多