performance - 为什么在每个 clEnqueue 函数中都会调用 clGetPlatformInfo?
问题描述
我们正在分析在主机和设备上的 NVidia GPU 上运行的 OpenCL 应用程序。我们惊讶地发现(基于 gperftools)主机将 44% 的时间花在clGetPlatformInfo
了 . 它由clEnqueueCopyBuffer_hid
, clEnqueueWriteBuffer_hid
, and调用clEnqueueNDRangeKernel_hid
(可能还有所有其他clEnqueue
方法,但它们在我们的代码中很少被调用)。由于这占用了我们的主机时间,而且我们现在似乎受到主机速度的限制,我需要知道是否有办法消除这些额外的调用。
为什么每个 OpenCL 调用都会调用它?(大概是可以存储在上下文中的静态信息?)我们是否可能错误地初始化了上下文?
编辑:我被要求提供 MWE:
#include <CL/opencl.h>
#include <vector>
using namespace std;
int main ()
{
cl_uint numPlatforms;
clGetPlatformIDs (0, nullptr, &numPlatforms);
vector<cl_platform_id> platformIdArray (numPlatforms);
clGetPlatformIDs (numPlatforms, platformIdArray.data (), nullptr);
// Assume the NVidia GPU is the first platform
cl_platform_id platformId = platformIdArray[0];
cl_uint numDevices;
clGetDeviceIDs (platformId, CL_DEVICE_TYPE_GPU, 0, nullptr, &numDevices);
vector<cl_device_id> deviceArray (numDevices);
clGetDeviceIDs (platformId, CL_DEVICE_TYPE_GPU, numDevices, deviceArray.data (), nullptr);
// Assume the NVidia GPU is the first device
cl_device_id deviceId = deviceArray[0];
cl_context context = clCreateContext (
nullptr,
1,
&deviceId,
nullptr,
nullptr,
nullptr);
cl_command_queue commandQueue = clCreateCommandQueue (context, deviceId, {}, nullptr);
cl_mem mem = clCreateBuffer (context, CL_MEM_READ_WRITE, sizeof(cl_int),
nullptr, nullptr);
cl_int i = 0;
while (true)
{
clEnqueueWriteBuffer (
commandQueue,
mem,
CL_TRUE,
0,
sizeof (i),
&i,
0,
nullptr,
nullptr);
++i;
}
}
解决方案
我们发现了问题:gproftools 很难给出正确的回溯。该代码实际上并没有clGetPlatformInfo
像 gperftools 所说的那样调用数千次。根据在 Khronos 论坛上与 bashbaug 的对话:
当我使用我们的 GPU 驱动程序使用 gperftools 运行测试时,我发现大部分时间都归因于 GTPin_Init,正如您所提到的。我认为这是因为 OpenCL ICD 必须导出很少的符号,因为对大多数 OpenCL API 的调用都是通过 ICD 调度表进行的。
我们使用他建议的分析工具(OpenCL 拦截层,可在https://github.com/intel/opencl-intercept-layer找到)让我们更好地了解内核的运行时特性并帮助我们找到一些内存泄漏. 实际上导致速度变慢的是内存泄漏 --- 如果内核以高引用计数作为参数传递内存,它们似乎需要很长时间才能启动。
您可以在此处的 Khronos 论坛上找到完整的对话:https ://community.khronos.org/t/why-does-clgetplatforminfo-get-called-in-every-clenqueue-function/105756/5
推荐阅读
- c++ - 我输入了 g++ -o main.cpp main 并且我丢失了我的程序
- android - 安卓30后杀死Activity
- scala - spark rdd级别中具有groupby的条件运算符 - scala
- ios - 快速在地图上的uitextview中使电话号码可点击
- javascript - 数组不更新
- java - Java ResultSet 提前关闭
- javascript - 如何使用 Spectron 访问客户端窗口 javascript 全局变量
- django - API url 路由 - Django/Postman
- python - 为什么我的 for 循环覆盖而不是附加 CSV?
- angular - Angular html选择问题