Особенности следования стандартам

Недавно возникла необходимость сравнить производительность работы кернела (kernel) на CPU и GPU под Linux. Однако, выяснилось, что устройства типа CPU не оказалось в списке доступных устройств для платформы, в связи с чем было произведено обновление драйверов nVidia под Linux со старых версий до последних. Результат был неожиданным: получилась неработающая программа. Почему и как побороть - далее.

Выбор платформы не происходил, следующий фрагмент кода приводил к возврату CL_INVALID_PLATFORM.

cl_int result = CL_SUCCESS;
cl_context context = clCreateContextFromType(NULL, CL_DEVICE_TYPE_DEFAULT, NULL, NULL, &result);

Та же ситуация с бета-версиями драйверов, доступными по программе early-access, независимо от типа CL_DEVICE_TYPE_ALL, CL_DEVICE_TYPE_GPU и т.п.
 

Надо сказать, до этого код был рабочим на Linux, более того, он продолжает оставаться рабочим на MacOS X. Стандарт по этому поводу говорит: "properties can be NULL in which case the platform that is selected is implementation-defined" (где properties - это первый параметр clCreateContextFromType()). Трактовать выделенный фрагмент можно по разному, но очевидно, что какая-то платформа должна быть выбрана. Исключением является ситуация, описанная в кодах ошибок: CL_INVALID_PLATFORM возвращается  "if properties is NULL and no platform could be selected or if platform value specified in properties is not a valid platform". Опрос платформ показывает следующее:

0x0x1e240e90: platform NVIDIA CUDA, version OpenCL 1.1 CUDA 3.2.1, vendor: NVIDIA Corporation    
Devices:    
0: GeForce GTX 285 ver. OpenCL 1.0 CUDA, NVIDIA Corporation

Что как бы намекает на то, что выбрать платформу автоматически можно, собственно и выбирать-то не из чего.

Ситуация стала весьма неясной. В связи с этим, был создан баг-репорт в nVidia. В результате которого было получено следующее объяснение (приведена выдержка):

In order to allow co-existence of multiple vendor libraries on OSes like Windows and Linux we have proposed and adopted the cl_khr_icd extension. This makes it a difficult decision to be able to pick up a particular vendor's implementation over another when the application passes NULL as the platform identifier.

A portable OpenCL program should never pass a platform pointer without first obtaining an ID from the driver through the relevant queries.

Расширение cl_khr_icd позволяет мирно сосуществовать драйверам (ICD = installable client drivers) от нескольких вендоров. Это удобный механизм, скрытый в общем и целом от прикладного программиста и позволяющий выбирать любую платформу от любого вендора без каких-либо ухищрений и привязки к конкретным библиотекам. Однако, есть у этого удобства и обратная сторона - выбрать автоматически платформу становится сложно, посему (см. issue 3 по ссылке выше) было решено, что:

3. How will the ICD handle a NULL cl_platform_id?
RESOLVED: The NULL platform is not supported by the ICD.

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

Таким образом, для корректной инициализации необходимо сначала выбрать платформу, опросив все существующие (вызвав clGetPlatformIDs()), а затем указать идентификатор конкретной платформы при создании контекста. Иначе есть возможность в один прекрасный день получить неработающее приложение.