Skip to content

[UR] Static OpenCL adapter - #21983

Merged
kswiecicki merged 17 commits into
intel:syclfrom
mateuszpn:ocl-static-link
Jul 3, 2026
Merged

[UR] Static OpenCL adapter#21983
kswiecicki merged 17 commits into
intel:syclfrom
mateuszpn:ocl-static-link

Conversation

@mateuszpn

@mateuszpn mateuszpn commented May 11, 2026

Copy link
Copy Markdown
Contributor

Builds the OpenCL adapter as a static library embedded in the UR loader instead of a separate runtime-loaded .so/.dll. Controlled by UR_STATIC_ADAPTER_OPENCL (default ON for SYCL builds). The OpenCL ICD itself is still resolved dynamically at runtime, so there's no OpenCL link-time dependency.

Key changes

  • Dynamic ICD loading — new ocl_dynamic_lib.{cpp,hpp} loads the ICD at init: LoadLibraryExA("OpenCL.dll", LOAD_LIBRARY_SEARCH_SYSTEM32) on Windows, dlopen("libOpenCL.so.1") (→ libOpenCL.so) on Linux, resolving entry points through function pointers (core_functions.def, new ocl_functions.def).

  • Namespace isolation — all adapter entry points moved into namespace ur::opencl to avoid symbol collisions; the loader wires DDI tables directly via ur::opencl::urGet*ProcAddrTable.

  • Loader integration — under UR_STATIC_ADAPTER_OPENCL the adapter is probed/registered in-process (no adapter dlopen), and discarded cleanly when no platforms are present (ur_loader.cpp, ur_adapter_registry.hpp, loader/CMakeLists.txt).

  • Build/linking control — opencl/CMakeLists.txt builds the static lib, drops the OpenCL link, and zeroes UR_APIEXPORT/UR_APICALL/UR_DLLEXPORT so definitions carry no __declspec(dllimport/dllexport). BuildUnifiedRuntime.cmake forces the option on, propagates it into the Windows ExternalProject, and suppresses the now-nonexistent ur_adapter_opencl.dll in the copy/install logic.

  • SYCL runtime — os_util.hpp: with the adapter static, __SYCL_OCL_CALL probes libOpenCL.so.1/libOpenCL.so for clRetain*/clRelease* directly (the libur_adapter_opencl.so it used to look them up in no longer exists);

@mateuszpn
mateuszpn force-pushed the ocl-static-link branch 5 times, most recently from 61e281d to 2857569 Compare May 12, 2026 12:08
@mateuszpn
mateuszpn requested a review from kswiecicki May 12, 2026 13:12
}
#endif
#ifdef UR_STATIC_ADAPTER_OPENCL
if (!adapter_registry.adaptersForceLoaded()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't duplicate this if.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ups, fixed

@@ -0,0 +1,120 @@
// OpenCL function definitions for dynamic loading
// Format: OCL_FUNC(name, required)
// where 'required' is 1 for OpenCL 1.0 functions that must be present, 0 for optional

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how did you determine which functions are required, and which are not?
some of these don't look right to me.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The split was based on "OpenCL 1.0 spec membership = required, anything later = optional". However, not all the functions are used by adapter, and those which are used - are required. Now the file is reduced to functions actually used by adapter.

@mateuszpn
mateuszpn marked this pull request as ready for review May 25, 2026 13:44
@mateuszpn
mateuszpn requested review from a team as code owners May 25, 2026 13:44
Comment thread buildbot/configure.py Outdated
Comment on lines +445 to +449
parser.add_argument(
"--static-opencl-adapter",
action="store_true",
help="Build OpenCL adapter as static library with dynamic OpenCL loading (no OpenCL dependency at link time).",
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to add this option. We didn't add any other backend. I think this would be a very rarely used function. And we want to enable static adapters by default anyway.

Comment on lines 115 to 121

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
*pNumAdapters = liveAdapter != nullptr ? 1 : 0;

?
what is the purpose of checking ocl::loadOCLLibrary() result here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied the suggestion

Comment on lines 87 to 89

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does the namespace have to be ifdefed?

In general, I suggest limiting the number of ifdefs to the minimum required, preferring to share implementations wherever possible.

Comment on lines 49 to 54

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please follow the same pattern used in level-zero adapter, with these symbols defined in ur_interface_loader.hpp. You should be able to reuse the exact same templates, just with different namespace name.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines 99 to 104

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn't it be simpler to rename the struct fields?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines 117 to 121

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

namespace it in both modes, and remove the ifdef.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you modify this file manually?

please use the existing ur_interface_loader template. It shouldn't require modifications.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that hand-edit is gone. generate_code.py now drives the existing ur_interface_loader.{cpp,hpp}.mako templates for opencl too. Only template change was parameterizing two L0-hardcoded strings (Level Zero →
${adapter}, UR_STATIC_ADAPTER_LEVEL_ZERO → UR_STATIC_ADAPTER_${Adapter});

Comment thread unified-runtime/source/ur/ur.hpp Outdated
Comment on lines 217 to 233

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why? is there a symbol conflict?

This should get resolved by creating a common library for the adapter. #21845 already does that here:
https://github.com/intel/llvm/pull/21845/changes#diff-e83af30e7502eb85108ac495d4a4d50775e6b0eba4e27e8b682c797f8b8a168fR26

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted for now, should be fixed after #21845 merge

Comment thread unified-runtime/source/adapters/opencl/ocl_dynamic_lib.cpp Outdated
@mateuszpn
mateuszpn requested review from a team as code owners May 27, 2026 13:47
@mateuszpn
mateuszpn requested a review from mmichel11 May 27, 2026 13:47
@mateuszpn
mateuszpn requested review from kswiecicki and pbalcer May 27, 2026 14:38
@mateuszpn
mateuszpn force-pushed the ocl-static-link branch 7 times, most recently from a3e5bbe to cb907b8 Compare June 1, 2026 14:11
@mateuszpn
mateuszpn requested a review from a team as a code owner June 1, 2026 14:11
@mateuszpn
mateuszpn force-pushed the ocl-static-link branch 2 times, most recently from 7170f4b to 1e647d8 Compare June 23, 2026 14:30
@mateuszpn
mateuszpn requested a review from pbalcer June 26, 2026 08:23
Comment thread unified-runtime/source/adapters/opencl/adapter.cpp Outdated
Comment thread sycl/source/detail/queue_impl.hpp Outdated
Comment on lines +1045 to +1051
// The device above is a raw reference into the platform's device list, which
// is owned by the platform. Hold a shared_ptr to the owning platform so that
// `MDevice` (and the per-device queue list it is registered in) is guaranteed
// to outlive this queue. Without this, a queue_impl kept alive by a deferred
// scheduler command can outlive its device_impl and crash in ~queue_impl when
// unregistering from the (already freed) device's queue list.
const std::shared_ptr<platform_impl> MPlatform;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how is this related?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix in queue_impl is not directly related to the PR's core purpose, still the issue (pre-existing, but static linking probably changed timing and the problem surfaced) prevented Windows tests to pass - "Queue not found" assert was fired on destructor of queue_impl.
You are probably right to move the fix to separate PR. I did #22481 for this.

Comment on lines +99 to +112
ur_result_t mock_urAdapterGetInfo(void *pParams) {
const auto &params = *static_cast<ur_adapter_get_info_params_t *>(pParams);
if (*params.ppropName == UR_ADAPTER_INFO_BACKEND) {
if (*params.ppPropValue) {
*reinterpret_cast<ur_backend_t *>(*params.ppPropValue) =
UR_BACKEND_OPENCL;
}
if (*params.ppPropSizeRet) {
**params.ppPropSizeRet = sizeof(ur_backend_t);
}
}
return UR_RESULT_SUCCESS;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bump

Comment on lines +47 to +62
{
// Probe the adapter before registering: urAdapterGet triggers
// loadOCLLibrary(). If the OpenCL library is absent the global
// ocl::*_ptr function pointers stay null, and any later call through
// the DDI table (e.g. urPlatformGetInfo) would segfault.
ur_dditable_t ocl_ddi = {};
ur::opencl::urAdapterGetDdiTables(&ocl_ddi);
ur_adapter_handle_t hAdapter = nullptr;
if (ocl_ddi.Adapter.pfnGet &&
ocl_ddi.Adapter.pfnGet(1, &hAdapter, nullptr) == UR_RESULT_SUCCESS) {
ocl_ddi.Adapter.pfnRelease(hAdapter);
auto &opencl = platforms.emplace_back(nullptr);
opencl.dditable = ocl_ddi;
staticOCLRegistered = true;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How was this handled in the normal dynamic case? I don't think statically linking changes anything here. The OpenCL adapter should return 0 platforms, and users wouldn't call any functions on it.

@mateuszpn
mateuszpn requested a review from pbalcer June 30, 2026 12:06

@pbalcer pbalcer left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, just one nit.


void enableMock() {
adaptersLoadPaths.clear();
forceLoaded = true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment why this is added here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@kswiecicki

Copy link
Copy Markdown
Contributor

@intel/dpcpp-devops-reviewers, @intel/bindless-images-reviewers, @intel/sycl-graphs-reviewers could you take a look please.

@slawekptak slawekptak left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SYCL changes LGTM

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this changed?

@mmichel11 mmichel11 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Command buffer changes LGTM

@sarnex sarnex left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cmake lgtm minus a nit

ur_adapter_is_static(${adapter} adapter_is_static)
if(adapter_is_static)
# No DLL for statically linked adapter
else()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can just do
if(NOT adapter_is_static) instead of having an empty branch

@dyniols dyniols left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bindless images changes LGTM

@mateuszpn

Copy link
Copy Markdown
Contributor Author

@intel/llvm-gatekeepers Please consider merge. MacOS workflow failure appears unrelated to the changes in this PR and looks like a workflow configuration issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants