OpenCL CL_INVALID_COMMAND_QUEUE при запуске ядра на графических процессорах NVIDIA и Intel - PullRequest
0 голосов
/ 14 сентября 2018

Возможно, это не самая узкая проблема, но ..

Программа реализует обертку вокруг всего, что связано с OpenCL. Оболочка обнаруживает все устройства OpenCL, а затем оборачивает их в еще одну обертку. Оболочки устройства содержат все связанные с ним объекты, такие как выделенный буфер cl_mem, связанный контекст и т. Д.

Я несколько раз проверял, если нет ошибок, если указатели не используются повторно, как если бы из-за какой-либо ошибки оболочки устройств с разных платформ имели бы один и тот же указатель платформы. но нет.

Проблема: Когда я делю работу между всеми вычислительными устройствами на моем ноутбуке (CPU + Intel GPU + Nvidia GPU), выполнение ядра, выдаваемое графическому процессору NVIDIA, с CL_INVALID_COMMAND_QUEUE.

Я все проверил.

Я пробовал следующие сценарии:

  • Intel GPU и CPU одновременно => все отлично работает
  • два процессора одновременно (сервер) => все отлично работает
  • , если я смешиваю устройства с двух платформ на ноутбуке => он вылетает с CL_INVALID_COMMAND_QUEUE. сбой ТОЛЬКО на графическом процессоре Nvidia.

большая часть кода инициализации приведена ниже.

std::cout << "Initializing the OpenCL engine..\n";
cl_int ret;
unsigned int nrOfActiveContexts = 0;
ret = clGetPlatformIDs(0, NULL, &mRetNumPlatforms);
if (mRetNumPlatforms > 0)
{

    this->mPlatforms.resize(mRetNumPlatforms);
}
else
{
    fprintf(stderr, "No OpenCL platform available.\n");
    exit(1);
}

ret = clGetPlatformIDs(mRetNumPlatforms, mPlatforms.data(), NULL);

std::vector<cl_device_id> devices;
cl_context context;
cl_uint numberOfDevices;
//query for available compute platforms
for (int i = 0; i < mPlatforms.size() ; i++)
{
    bool error = false;
    numberOfDevices = 0;
    devices.clear();
    context = NULL;
    cl_device_type deviceTypes = CL_DEVICE_TYPE_ALL;
    if (useCPU &&useGPU)
        deviceTypes = CL_DEVICE_TYPE_ALL;
    else if (useCPU)
        deviceTypes = CL_DEVICE_TYPE_CPU;
    else if (useGPU)
        deviceTypes = CL_DEVICE_TYPE_GPU;

    ret = clGetDeviceIDs(mPlatforms[i], deviceTypes, 0, NULL, &numberOfDevices);
    if (numberOfDevices > 0)
    {
        devices.resize( numberOfDevices);
        ret = clGetDeviceIDs(mPlatforms[i], deviceTypes,
            numberOfDevices, devices.data(), NULL);
    }
    else continue;

    context = clCreateContext(NULL, numberOfDevices, devices.data(), NULL, NULL, &ret);
    if (ret != CL_SUCCESS)
        throw(std::abort);
    mContexts.push_back(context);
    if (ret != CL_SUCCESS)
    {
        error = true;
    }
    //query device properties create Workers
    size_t ret_size;
    cl_uint compute_units;
    cl_ulong max_alloc;
    size_t max_work_size;
    std::string name;
    std::vector<char> c_name;
    for (int y = 0; y < devices.size(); y++)
    {
        ret_size = compute_units = max_alloc = max_work_size = 0;
        c_name.clear();

        ret = clGetDeviceInfo(devices[y], CL_DEVICE_NAME, NULL, NULL, &ret_size);
        if (ret != CL_SUCCESS)
        {
            error = true; goto errored;
        }
        c_name.resize(ret_size);
        ret = clGetDeviceInfo(devices[y], CL_DEVICE_NAME, c_name.size(), c_name.data(), &ret_size);
        if (ret != CL_SUCCESS)
        {
            error = true; goto errored;
        }
        name = std::string(c_name.begin(), c_name.end());
        name = std::regex_replace(name, std::regex("[' ']{2,}"), " ");

        cl_device_type   devType;
        ret = clGetDeviceInfo(devices[y], CL_DEVICE_TYPE, sizeof(cl_device_type), (void *)&devType, NULL);
        if (ret != CL_SUCCESS)
        {
            error = true; goto errored;
        }



        ret = clGetDeviceInfo(devices[y], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(cl_uint), (void *)&compute_units, NULL);
        if (ret != CL_SUCCESS)
        {
            error = true; goto errored;
        }
        ret = clGetDeviceInfo(devices[y], CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(size_t), (void *)&max_work_size, NULL);
        if (ret != CL_SUCCESS)
        {
            error = true; goto errored;
        }
        CWorker::eWorkerType type;
        if (devType & CL_DEVICE_TYPE_GPU)
            type = CWorker::eWorkerType::GPU;
        else
            if (devType & CL_DEVICE_TYPE_CPU)
                type = CWorker::eWorkerType::CPU;


        if (type == CWorker::eWorkerType::CPU)
        {
            if (compute_units > 8)
                max_work_size = compute_units / 4;
            else if (compute_units == 8)
                max_work_size = 2;
            else
                max_work_size = 1;

        }
        ret = clGetDeviceInfo(devices[y], CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), (void *)&max_alloc, NULL);
        if (ret != CL_SUCCESS)
        {
            error = true;
            goto errored;
        }
    errored:
        if (error != true)
        {
            CWorker  * w = new CWorker();

            w->setDevice(devices[y]);
            w->setMaxComputeUnits(compute_units);
            w->setMaxMemAlloc(max_alloc);
            w->setMaxWorkGroupSize(max_work_size);
            w->setName(name);
            std::cmatch cm;
            if (std::regex_search(name.data(), cm, std::regex("\\w\+")))
                w->setShortName(std::string(cm[0]) +"-"+ std::to_string(mWorkers.size()+1));
            w->setContext(context);
            w->setType(type);

            mWorkers.push_back(w);
        }
    }

    nrOfActiveContexts++;
}

if (mWorkers.size() > 0)
    mInitialised = true;
if (mWorkers.size() > 0)
    return true;
else return false;

1 Ответ

0 голосов
/ 15 сентября 2018

Вполне вероятно, проблема в том, как создается контекст:

context = clCreateContext ( NULL , numberOfDevices, devices.data (), NULL, NULL и & ret);

Первый передаваемый параметр - NULL, что согласно руководству OpenCL означает, что выбранная платформа определяется реализацией:

Задает список имен свойств контекста и их соответствующих значений. За каждым именем свойства сразу же следует соответствующее требуемое значение. Список заканчивается 0. Свойства могут иметь значение NULL, и в этом случае выбранная платформа определяется реализацией.

Попробуйте передать что-то вроде этого:

cl_context_properties properties[] = { CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[i])(), 0};
context = clCreateContext(properties, numberOfDevices, devices.data(), NULL, NULL, &ret);

Если это не поможет, возможно, сначала попытайтесь инициализировать Nvidia (если это уже не так). Может случиться так, что Intel инициализируется в первую очередь, и его драйвер версии OpenCL новее, чем Nvidia (например, Intel OpenCL 2.0 против Nvidia 1.2), и часть этого используется для Nvidia, следовательно, ошибка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...