Уникальность устройства OpenCL
Есть ли способ заставить OpenCL предоставить мне список всех уникальных физических устройств, имеющих доступную реализацию OpenCL? Я знаю, как выполнять итерацию через список платформы/устройства, но, например, в моем случае у меня есть одна платформа, предоставляемая Intel, которая дает мне эффективную реализацию устройства для моего процессора и платформу APP, которая обеспечивает быструю реализацию для моего GPU, но ужасная реализация для моего процессора.
Есть ли способ выработать то, что два процессора являются фактически одним и тем же физическим устройством, поэтому я могу выбрать наиболее эффективный и работать с ним, вместо того, чтобы использовать оба и иметь их соперничать друг с другом для вычисления время на одном физическом устройстве?
Я просмотрел CL_DEVICE_VENDOR_ID
и CL_DEVICE_NAME
, но они не решают мои проблемы, CL_DEVICE_NAME
будет одинаковым для двух отдельных физических устройств той же модели (dual GPU) и CL_DEVICE_VENDOR_ID
дает мне другой идентификатор для моего процессора в зависимости от платформы.
Идеальное решение было бы своего рода уникальным идентификатором физического устройства, но я был бы доволен изменением конфигурации OpenCL вручную, чтобы самостоятельно переупорядочить устройства (если такое возможно).
Ответы
Ответ 1
Насколько я могу исследовать проблему сейчас, надежного решения нет. Если вся ваша работа выполняется в рамках одного процесса, вы можете использовать порядок записей, возвращаемых самими значениями clGetDeviceIDs
или cl_device
(по сути, они являются указателями), но все ухудшается, если вы пытаетесь использовать эти идентификаторы между процессами.
См. этот блог в блоге об этом, говоря:
Проблема в том, что если у вас два идентичных GPU, вы не можете различать их. Если вы вызываете clGetDeviceIDs
, порядок, в котором они были возвращены, на самом деле не указан, поэтому, если первый процесс выбирает первое устройство, а второе берет второе устройство, они оба могут завершить переназначение одного и того же графического процессора и оставить другого бездействующим.
Однако он отмечает, что nVidia и AMD предоставляют свои пользовательские расширения, cl_amd_device_topology
и cl_nv_device_attribute_query
. Вы можете проверить, поддерживаются ли эти расширения вашим устройством, а затем использовать их как следующие (код оригинального автора):
// This cl_ext is provided as part of the AMD APP SDK
#include <CL/cl_ext.h>
cl_device_topology_amd topology;
status = clGetDeviceInfo (devices[i], CL_DEVICE_TOPOLOGY_AMD,
sizeof(cl_device_topology_amd), &topology, NULL);
if(status != CL_SUCCESS) {
// Handle error
}
if (topology.raw.type == CL_DEVICE_TOPOLOGY_TYPE_PCIE_AMD) {
std::cout << "INFO: Topology: " << "PCI[ B#" << (int)topology.pcie.bus
<< ", D#" << (int)topology.pcie.device << ", F#"
<< (int)topology.pcie.function << " ]" << std::endl;
}
или (код мной, адаптированный из вышеуказанного связанного сообщения):
#define CL_DEVICE_PCI_BUS_ID_NV 0x4008
#define CL_DEVICE_PCI_SLOT_ID_NV 0x4009
cl_int bus_id;
cl_int slot_id;
status = clGetDeviceInfo (devices[i], CL_DEVICE_PCI_BUS_ID_NV,
sizeof(cl_int), &bus_id, NULL);
if (status != CL_SUCCESS) {
// Handle error.
}
status = clGetDeviceInfo (devices[i], CL_DEVICE_PCI_BUS_ID_NV,
sizeof(cl_int), &slot_id, NULL);
if (status != CL_SUCCESS) {
// Handle error.
}
std::cout << "Topology = [" << bus_id <<
":"<< slot_id << "]" << std::endl;
Ответ 2
-
Если у вас есть два устройства того же типа, принадлежащие платформе, вы можете разделить их с помощью связанного cl_device_ids возврата с помощью clGetDeviceID.
-
Если у вас есть устройства, которые могут использоваться двумя различными платформами, вы можете исключить записи для второй платформы, сравнив имена устройств с CL_DEVICE_NAME.
-
Если вы хотите найти предназначенную платформу для устройства, сравните строки CL_PLATFORM_VENDOR и CL_DEVICE_VENDOR с clGetPlatformInfo() и clGetDeviceInfo соответственно.
Вы можете прочитать на всех платформах и всех связанных с ними устройствах в отдельных списках конкретных платформ, а затем устранить дублирование, сравнив имена устройств в отдельных списках. Это должно гарантировать, что вы не получите одно и то же устройство для разных платформ.
Наконец, вы можете, например, аргументами командной строки или конфигурационным файлом дать аргументы вашему приложению связать устройства определенного типа (CPU, GPU, Accelerator) с определенной платформой, если существует выбор различных платформ для тип устройства. Надеюсь, это ответит на ваш вопрос.
Ответ 3
в любом случае просто предположим, что вы пытаетесь вывести уникальный идентификатор для всех устройств, на самом деле вы можете просто запросить с помощью clGetDeviceID:
cl_int clGetDeviceIDs(cl_platform_id platform,
cl_device_type device_type,
cl_uint num_entries,
cl_device_id *devices,
cl_uint *num_devices)
то ваш список устройств будет вставлен в массив * devices, а затем вы можете сделать clGetDeviceInfo(), чтобы узнать, какое устройство вы хотите использовать.
Ответ 4
Сочетая ответы выше, я решил:
long bus = 0; // leave it 0 for Intel
// update bus for NVIDIA/AMD ...
// ...
long uid = (bus << 5) | device_type;
Переменная bus
была вычислена в соответствии с конкретными информационными запросами устройства NVIDIA/AMD, как упоминалось в firegurafiku, переменная device_type
была результатом clGetDeviceInfo(clDevice, CL_DEVICE_TYPE, sizeof(cl_device_type), &device_type, nullptr)
, как предложил Стейнин.
Такой подход решил проблему одинакового уникального идентификатора для процессора Intel со встроенным графическим процессором. Теперь оба устройства имеют уникальные идентификаторы, благодаря различным CL_DEVICE_TYPE
.
Удивительно, но в случае выполнения кода на устройстве Oclgrind -emulated Oclgrind simulator
также получает уникальный идентификатор 15
, отличный от любого другого в моей системе.
Единственный случай, когда предложенный подход может дать сбой - несколько процессоров одной модели на одной материнской плате.