Уникальность устройства OpenCL

Есть ли способ заставить OpenCL выдать мне список всех уникальных физических устройств, для которых доступна реализация OpenCL? Я знаю, как перебирать список платформ / устройств, но, например, в моем случае у меня есть одна платформа, предоставленная Intel, которая дает мне эффективную реализацию устройства для моего процессора, и платформу APP, которая обеспечивает быструю реализацию для моего графического процессора, но ужасная реализация для моего процессора.

Есть ли способ выяснить, что два устройства ЦП на самом деле являются одним и тем же физическим устройством, чтобы я мог выбрать наиболее эффективное и работать с ним, вместо того, чтобы использовать оба и заставлять их бороться друг с другом за время вычислений на одно физическое устройство?

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

Идеальным решением был бы какой-то уникальный идентификатор физического устройства, но я был бы счастлив вручную изменить конфигурацию OpenCL, чтобы самостоятельно переставить устройства (если такое возможно).


person Thomas    schedule 01.06.2012    source источник
comment
я не понял вопроса .. так вы хотите выбирать между двумя процессорами с одинаковыми характеристиками?   -  person ardiyu07    schedule 02.06.2012
comment
Я хочу использовать все доступные физические устройства (для решения проблемы, которую легко распараллелить) - и я хочу использовать только одно логическое устройство для физического устройства, иначе я получу разногласия.   -  person Thomas    schedule 02.06.2012


Ответы (4)


Насколько я мог сейчас исследовать проблему, надежного решения не существует. Если вся ваша работа выполняется в рамках одного процесса, вы можете использовать порядок записей, возвращаемый самими значениями clGetDeviceIDs или cl_device (по сути, это указатели), но ситуация ухудшится, если вы попытаетесь разделить эти идентификаторы между процессами.

См. сообщение в блоге этого парня об этом, где говорится:

Проблема в том, что если у вас два одинаковых графических процессора, вы не сможете их различить. Если вы вызываете 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;
person firegurafiku    schedule 15.03.2016
comment
порядок, в котором они возвращаются, на самом деле не указан. Вау! это даже хуже, чем я ожидал. В любом случае мой вопрос был не столько о нескольких процессах, сколько о разных платформах, представляющих одно и то же физическое устройство (например, Intel SDK и AMD SDK оба выставляют один и тот же основной ЦП в качестве логического устройства на каждой из своих соответствующих платформ), но это расширение топологии решает и это. Спасибо за ответ! - person Thomas; 16.03.2016
comment
@Thomas: Добро пожаловать! Кстати, программа clinfo должна отображать идентификаторы топологии как для устройств nVidia, так и для устройств AMD. Вам обязательно стоит посмотреть, как они справляются с их код кажется лучше моего. - person firegurafiku; 16.03.2016

  • Если у вас есть два устройства одного и того же типа, принадлежащие платформе, вы можете отличить их друг от друга по связанному cl_device_ids, возвращаемому clGetDeviceIDs.

  • Если у вас есть устройства, которые могут использоваться двумя разными платформами, вы можете удалить записи для второй платформы, сравнив имена устройств из CL_DEVICE_NAME.

  • Если вы хотите найти предполагаемую платформу для устройства, сравните строки CL_PLATFORM_VENDOR и CL_DEVICE_VENDOR из clGetPlatformInfo () и clGetDeviceInfo соответственно.

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

Наконец, вы можете с помощью аргументов командной строки или файла конфигурации, например, передать аргументы вашему приложению для связывания устройств определенного типа (CPU, GPU, Accelerator) с определенной платформой, если существует выбор различных платформ для типа устройства. Надеюсь, это ответит на ваш вопрос.

person Steinin    schedule 07.11.2013

в любом случае давайте просто предположим, что вы пытаетесь получить уникальный идентификатор для всех устройств, на самом деле вы можете просто запросить с помощью clGetDeviceIDs:

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 (), чтобы узнать, какое устройство вы хотите использовать.

person ardiyu07    schedule 02.06.2012
comment
Я хочу использовать их все, но не хочу, чтобы к какому-либо физическому устройству было доступно несколько логических устройств. - person Thomas; 02.06.2012
comment
Если я не ошибаюсь, вы хотите использовать многопоточность со всеми устройствами, работающими одновременно? если да, то вы можете взглянуть на CUDA Computing SDK for OpenCL, исходный код oclMultiThreads, где вы можете разделить работу вручную, а затем запустить их асинхронно с доступными устройствами. - person ardiyu07; 02.06.2012
comment
Нет, мой вопрос более тонкий. Я знаю, что могу перечислить все устройства и распечатать их. Но проблема в том, что одно физическое устройство (скажем, мой уникальный ЦП) выступает как два логических устройства (по одному на каждой платформе OpenCL) - многопоточность по двум логическим устройствам вызовет конфликт ресурсов из-за уникального физического ЦП (это даже больше верно для графических процессоров), поэтому я хочу обнаружить, что два логических устройства указывают на одно и то же физическое устройство и используют только одно из них. - person Thomas; 02.06.2012
comment
Ах, я вижу, наконец, у меня есть ваш вопрос. Я не знаю, как вы разбили свое устройство на разделы и сказали им запустить ту же программу opencl, но есть также способ разделить устройство на подустройства с расширением OpenCL, и вы можете взглянуть на описание здесь: khronos.org/registry/cl/extensions/ext/ . Я думаю, что он поддерживает как Intel, так и AMD, но я не гарантирую, что он совместим с вашей средой. - person ardiyu07; 02.06.2012

Объединив ответы выше, мое решение было:

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) вызова API , как предложил Стейнин.

Такой подход решил проблему одинакового уникального идентификатора для процессора Intel со встроенным графическим процессором. Теперь у обоих устройств есть уникальные идентификаторы, благодаря разным CL_DEVICE_TYPE.

Удивительно, но в случае запуска кода на устройстве, эмулированном Oclgrind, Oclgrind simulator устройство также получает уникальный идентификатор 15, disctinct от любого другого в моей системе.

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

person Mykyta Kozlov    schedule 30.04.2019