Как собирать двоичные ядра для распространения собственного кода


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

Как охватить большинство пользователей (AMD и Intel, поскольку Nvidia может использовать код CUDA) минимумом двоичных файлов и минимумом машин, на которых я должен запускать свой автономный компилятор? Существуют ли семейства графических процессоров, которые могут использовать одни и те же двоичные файлы? Компилятор CUDA может компилировать для разные архитектуры, как насчет OpenCL? Данные о бинарной совместимости не кажутся хорошо документированными, но, возможно, кто-то собрал эти данные для себя.

Я знаю, что есть SPIR, но старое оборудование его не поддерживает.

Вот подробности моей реализации, если кто-то нашел этот вопрос и сделал меньше, чем я. Я сделал инструмент, который компилирует ядро в файл, а затем собрал все эти двоичные файлы в массив C, который будет включен в main применение:

const char* binaries[] = { //kernels/HD Graphics 4000 "\x62\x70\x6c\x69\x73\x74\x30\x30\xd4\x01\x02\x03" "\x04\x05\x06\x07\x08\x5f\x10\x0f\x63\x6c\x42\x69" "\x6e\x61\x72\x79\x56\x65\x72\x73\x69\x6f\x6e\x5c" ... "\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x47\xe0" , //here more kernels }; size_t binaries_sizes[] = { 204998, 205907, ... };

А затем я использую следующий код, который повторяет все ядра (я не придумал ничего более умного, чем метод проб и ошибок, выбирая первое ядро, которое успешно строится, вероятно, есть лучшее решение):

int e3 = -1; int i = 0; while (e3 != CL_SUCCESS) { if (i == lenof(binaries)) { throw Error(); } program = clCreateProgramWithBinary(context, 1, &deviceIds[devIdx], &binaries_sizes[i], (const unsigned char**)&binaries[i], nullptr, &e3); if (e3 != CL_SUCCESS) { ++i; continue; } int e4 = clBuildProgram(program, 1, &deviceIds[devIdx], "", nullptr, nullptr); e3 = e4; ++i; }

1   2   2016-12-14 21:34:20

1 ответ:

К сожалению, нет стандартного решения для вашей проблемы. OpenCL не зависит от платформы, и нет никакого стандартного способа (кроме SPIR) решить эту проблему. Каждый поставщик самостоятельно определяет набор инструментов компилятора, и даже это может изменяться в разных версиях одного и того же драйвера или для разных устройств.

Вы можете добавить некоторые метаданные в ядро, чтобы определить, для какой платформы вы его скомпилировали, что избавит вас от части проб и ошибок (т. е., вместо того, чтобы просто хранить двоичные файлы и binaries_size, вы можете также хранить binary_platform и binary_device, а затем перебирать эти массивы, чтобы увидеть, какой двоичный файл вы должны загрузить).

Лучшим решением для вас будет SPIR (или новый SPIRV), которые являются промежуточными представлениями, которые затем могут быть "перекомпилированы" драйвером OpenCL в фактический набор инструкций архитектуры. Если вы храните свои двоичные файлы в SPIRV и имеете доступ к / знанию некоторой магии компилятора, вы можете использовать переводчик инструмент, чтобы получить обратно с помощью LLVM-IR и затем скомпилировать вниз для других платформ, таких как AMD или видеорегистратор PTX, с использованием инфраструктуры LLVM инфраструктуры (см. https://github.com/KhronosGroup/SPIRV-LLVM)