Уникальность устройства 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, отличный от любого другого в моей системе.

Единственный случай, когда предложенный подход может дать сбой - несколько процессоров одной модели на одной материнской плате.