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.