`clCreateBuffer` с` CL_MEM_HOST_WRITE_ONLY` на macOS не может выделить буферы размером более 128 МБ на графических процессорах - PullRequest
0 голосов
/ 30 сентября 2018

clCreateBuffer с флагом CL_MEM_HOST_WRITE_ONLY в macOS не может выделить буферы размером более 128 МБ для графических процессоров, даже если размер меньше, чем CL_DEVICE_MAX_MEM_ALLOC_SIZE.-6 (CL_OUT_OF_HOST_MEMORY) будет возвращено в таких случаях.

На моем MacBook Pro (Retina, 15 дюймов, конец 2013 г.), macOS 10.13.6, оба GT 750M (максимальное распределение: 512MiB) и Iris Pro 5200 (максимальное выделение: 384 МиБ) дает сбой на CL_MEM_HOST_WRITE_ONLY буферах 129 МиБ.В то время как для моего рабочего стола Ubuntu, на GTX 760 (максимальное выделение: 512 МБ) такое распределение возможно.Предыдущие или будущие версии macOS, возможно, не имеют этой проблемы.

Следующий пример сценария (test.cpp) может продемонстрировать проблему.Вызов программы с аргументом -1 печатает все устройства OpenCL и их устройства OpenCL #;вызов программы с помощью 1 запустит программу на устройстве # 1:

#include <cstdio>
#ifdef __APPLE__
#include <OpenCL/cl.h>
#else
#include <CL/cl.h>
#endif  

using namespace std;

cl_device_id OpenCLGetGPU(int idev, int *gpu_count)
{
    cl_device_id dev_id;
    cl_uint num_plat;
    clGetPlatformIDs(0, NULL, &num_plat);
    cl_platform_id *plats = new cl_platform_id[num_plat];
    clGetPlatformIDs(num_plat, plats, NULL);

    cl_uint num_dev = 0, idev_gb = 0;
    char plat_name[128], device_name[128], vend_name[128];
    int count = 0;

    if (idev == -1)
        printf("OpenCL devices:\n");

    for (cl_uint i = 0 ; i < num_plat ; i++, num_dev = 0) {
        clGetPlatformInfo(plats[i], CL_PLATFORM_NAME,
                sizeof(plat_name), plat_name, NULL);
        clGetDeviceIDs(plats[i], CL_DEVICE_TYPE_ALL, 0, NULL, &num_dev);
        count += num_dev;

        cl_device_id* devices = new cl_device_id[num_dev];
        clGetDeviceIDs(plats[i], CL_DEVICE_TYPE_ALL, num_dev, devices, NULL);

        for (cl_uint j = 0 ; j < num_dev ; j++, idev_gb++) {
            clGetDeviceInfo(devices[j], CL_DEVICE_NAME,
                    sizeof(device_name), device_name, NULL);
            clGetDeviceInfo(devices[j], CL_DEVICE_VENDOR,
                    sizeof(vend_name), vend_name, NULL);
            if (idev == -1)
                printf("  %i. %s, Vendor: %s, Platform: %s.\n",
                        idev_gb, device_name, vend_name, plat_name);
            if (idev == (int) idev_gb) dev_id = devices[j];
        }

        delete[] devices, devices = NULL;
    }

    delete[] plats, plats = NULL;

    if (idev == -1)
        exit(0);
    else if (idev == -2) {
        *gpu_count = count;
        return 0;
    }

    cl_platform_id plat;
    clGetDeviceInfo(dev_id, CL_DEVICE_NAME, sizeof(device_name), device_name, NULL);
    clGetDeviceInfo(dev_id, CL_DEVICE_VENDOR, sizeof(vend_name), vend_name, NULL);
    clGetDeviceInfo(dev_id, CL_DEVICE_PLATFORM, sizeof(plat), &plat, NULL);
    clGetPlatformInfo(plat, CL_PLATFORM_NAME, sizeof(plat_name), plat_name, NULL);
    printf("  Device: %d. %s, Vendor: %s, Platform/Driver: %s. \n",
            idev, device_name, vend_name, plat_name);

    return dev_id;
}

int main(int argc, char *argv[])
{
    size_t MiB = 1024 * 1024, max_alloc;
    int gid = 0;
    cl_int err;

    if (argc > 1)
        gid = strtol(argv[1], NULL, 10);

    cl_device_id dev_id = OpenCLGetGPU(gid, NULL);
    cl_platform_id plat;
    clGetDeviceInfo(dev_id, CL_DEVICE_PLATFORM, sizeof(plat), &plat, NULL);
    clGetDeviceInfo(dev_id, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(max_alloc), &max_alloc, NULL);
    printf("CL_DEVICE_MAX_MEM_ALLOC_SIZE: %g MiB\n", 1.0 * max_alloc / MiB);

    cl_context_properties props[3] = { CL_CONTEXT_PLATFORM, 0, 0 };
    props[1] = (cl_context_properties) plat;
    cl_context ctx = clCreateContext(props, 1, &dev_id, NULL, NULL, &err);
    cl_command_queue q = clCreateCommandQueue(ctx, dev_id, 0, &err);

    /* Allocate memory on device */
    int sz = 128;   
    cl_mem a = clCreateBuffer(ctx, CL_MEM_READ_WRITE | CL_MEM_HOST_WRITE_ONLY, sz * MiB, NULL, &err);
    printf("clCreateBuffer with CL_MEM_HOST_WRITE_ONLY, \t%d \tMiB, err = %d\n", sz, err);
    sz = 129;
    cl_mem b = clCreateBuffer(ctx, CL_MEM_READ_WRITE | CL_MEM_HOST_WRITE_ONLY, sz * MiB, NULL, &err);
    printf("clCreateBuffer with CL_MEM_HOST_WRITE_ONLY, \t%d \tMiB, err = %d\n", sz, err);
    sz = 129;
    cl_mem c = clCreateBuffer(ctx, CL_MEM_READ_WRITE, sz * MiB, NULL, &err);
    printf("clCreateBuffer without CL_MEM_HOST_WRITE_ONLY, \t%d \tMiB, err = %d\n", sz, err);

    return EXIT_SUCCESS;
}

Выход для вызова программы на GT 750M в macOS:

  Device: 2. GeForce GT 750M, Vendor: NVIDIA, Platform/Driver: Apple. 
CL_DEVICE_MAX_MEM_ALLOC_SIZE: 512 MiB
clCreateBuffer with CL_MEM_HOST_WRITE_ONLY,     128     MiB, err = 0
clCreateBuffer with CL_MEM_HOST_WRITE_ONLY,     129     MiB, err = -6
clCreateBuffer without CL_MEM_HOST_WRITE_ONLY,  129     MiB, err = 0

This "Вопрос «может быть больше похож на отчет о поведении - поскольку эта функция, похоже, не нарушает стандарты OpenCL (по крайней мере для 1.2), а macOS не поддерживает OpenCL.Но это просто неожиданно, поскольку такие платформы, как Windows или Linux, не имеют этой проблемы.Это может быть вызвано неполной поддержкой OpenCL 1.2, так как предупреждение clinfo:

NOTE:   your OpenCL library only supports OpenCL 1.0,
    but some installed platforms support OpenCL 1.2.
    Programs using 1.2 features may crash
    or behave unexpectedly

Также сообщается об аналогичной ошибке в clEnqueueFillBuffer, API-интерфейсе OpenCL 1.2 (1 , 2 ) и пришло мне в голову, только на macOS.

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