首页 > 解决方案 > 为什么在每个 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;
    }
}

该 MWE 在几秒钟内生成以下配置文件。请注意,99% 的时间都花在了 clGetPlatformInfo 中。 MWE 配置文件结果

标签: performanceprofilingopencl

解决方案


我们发现了问题: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


推荐阅读