KhronosGroup / SYCL-Docs

SYCL Open Source Specification
Other
110 stars 67 forks source link

Clarify `get_kernel_ids()` behaviours in the case of dynamic linking of separate SYCL applications #209

Open keryell opened 2 years ago

keryell commented 2 years ago

There is a global free function to get the ids of all the known kernels but it is not clear how to return all the kernels when for example a SYCL application use some other libraries which might be loaded lazily later which also use SYCL internally in a hidden way. While the concept of dynamic library is not defined in the ISO C++ standard, concrete SYCL programs have to deal with it.

std::vector<kernel_id> get_kernel_ids();

Returns: A vector with the identifiers for all kernels defined in the SYCL application. This does not include identifiers for any device built-in kernels.

Can we say that this should return at least all the kernels usable at some point in the life of a program? So the kernels from not yet loaded library might not be there, but they should be once the library is loaded. Once the library is unloaded, the kernels might be still returned by get_kernel_ids(), if it is difficult to figure out which are no longer usable. On the other hand, a conformant SYCL implementation might not be required to implement kernels in dynamic libraries.

keryell commented 2 years ago

I was thinking to this while reviewing https://github.com/KhronosGroup/SYCL-CTS/pull/222

Michoumichmich commented 2 years ago

I encountered that issue yesterday, I was using templates to query information from various kernels which were compiled into a shared library and well, it wasn't working. (Instantiating these queries in the backend first fixed it.) Making get_kernel_ids work with not loaded shared libraries wouldn't that require to load all of the libraries used by the application? (even those who don't contain SYCL programs)

keryell commented 2 years ago

I was just thinking to a minimal solution similar to normal C++ behavior: you cannot know the unknown. So get_kernel_ids() could be populated with the kernels of a library only once the library is loaded, by running a C++ static constructor of the SYCL runtime. We could also remove the kernels from the static destructor.

keryell commented 2 years ago

At least this is good feedback for the committee to know that someone has actually this problem and this is not just some fantasy of mine. :-)

Michoumichmich commented 2 years ago

I was just thinking to a minimal solution similar to normal C++ behavior: you cannot know the unknown.

Okay I see, thanks!

So get_kernel_ids() could be populated with the kernels of a library only once the library is loaded, by running a C++ static constructor of the SYCL runtime. We could also remove the kernels from the static destructor.

That would prevent some "proprietary SYCL library vendor" from hiding its implementation from the end user (which is good or bad, depending on your team ahah). I guess having some attribute to limit kernel visibility (ie not register to get_kernel_ids() would help, maybe)

(I was using that to manually compute the GPU occupancy before launching the SYCL kernel and so the shared library was never loaded before, thus my remark on loading everything before)

keryell commented 2 years ago

It is not exposing a library detail more than you would have with a pure C++ library where you know the entry points, you know the library will use some resources by tracing the program or just sampling the system with a tool like perf. In the case of a library using SYCL, you will see the kernel invocations and data transfers, but an explicit kernel typename can be used in the library to hide the automatic kernel naming that might leak some implementation details like class hierarchy and lambda naming. Perhaps a company like Codeplay or https://quarkslab.com/ @aguinet could add an obfuscation option for SYCL and the paranoids. :-)

gmlueck commented 2 years ago

As you say, ISO C++ does not define the behavior of programs with dynamic libraries. For example, dynamic libraries impact the order of global constructors / destructors, but this is not mentioned in ISO C++. If we are using ISO C++ as a model for the SYCL specification, it's not clear to me that the SYCL spec should address the behavior of dynamic libraries either.

I do think your proposed behavior is reasonable, though, @keryell. Most likely get_kernel_ids() would only return the kernel IDs for kernels that reside in libraries that have been already loaded. Clearly, the implementation cannot look into the future and determine which kernels might be contained by some other library that will be loaded via dlopen().

Note that there is a related issue with get_kernel_id<KernelName>(). Is it legal to request an ID for a kernel that is defined in a shared library? My expectation is that this would be legal only if the shared library is currently loaded. In fact, my expectation is that the template specialization would be defined in the shared library that defines the kernel. Therefore, calling get_kernel_id<KernelName>() would result in a link error if the shared library does not export that symbol. It would also result in a link error if the shared library was loaded via dlopen() (since these libraries do not export any symbols into the global name space.)

fraggamuffin commented 2 years ago

statically linked vs dlopen, so we may address through OS, Draft non-normative note to inform people also impl dependent

keryell commented 2 years ago

@keryell to add a non normative note about the issue.