Skip to content

[SYCL] Load PI plugins only once #1614

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from

Conversation

smaslov-intel
Copy link
Contributor

Stop re-loading PI plugins on every invocation of get_platforms().
Signed-off-by: Sergey V Maslov sergey.v.maslov@intel.com

Signed-off-by: Sergey V Maslov <sergey.v.maslov@intel.com>
@smaslov-intel smaslov-intel requested a review from garimagu April 30, 2020 01:06
garimagu
garimagu previously approved these changes May 1, 2020
Copy link
Contributor

@garimagu garimagu left a comment

Choose a reason for hiding this comment

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

LGTM.
@romanovvlad In case you have comments on the usage of static keyword here, please comment.

@bader bader requested a review from romanovvlad May 6, 2020 17:45
@@ -197,7 +197,12 @@ bool trace(TraceLevel Level) {

// Initializes all available Plugins.
vector_class<plugin> initialize() {
vector_class<plugin> Plugins;
static bool PluginsInitDone = false;
static vector_class<plugin> Plugins;
Copy link
Contributor

Choose a reason for hiding this comment

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

Who owns plugin? I thought it was platform_impl::MPlatform.
Related question:
What is the lifetime of Plugins? What happens if user creates a platform(to enter this function) from a global object destructor?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

plugins are system-wide, think of them as a global list of shared libraries loaded. it is currently created at the first call to pi::initialize() which I think (TODO) we should fine a better place for than in platforms_get(), and also (TODO) deallocate them at global tear-down.

Copy link
Contributor

Choose a reason for hiding this comment

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

  1. Still, who owns plugins right now? I see that platform_impl has std::shared_ptr<plugin> MPlugin; field, so I expect that platform_impl objects own plugins. When all platform_impl objects are destroyed plugin object will be deallocated as well, so Plugins vector will point to already released memory.

  2. What happens if user creates a platform(to enter this function) from a global object destructor? For example the following SYCL application can(it's UB) catch a crash with your implementation:

class Glob {
~Glob() { sycl::platform Platform(...); }
}
Glob GVar;

int main() {
  sycl::platform Platform(...);
}

Copy link
Contributor

Choose a reason for hiding this comment

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

The question about the lifetime of the Plugins vector is interesting. I looked at the SYCL spec, and I don't see any restriction that prevents a user from calling SYCL APIs from global destructors, so I think we need to assume that code like @romanovvlad shows above is legal.

This probably means that it is generally unsafe to use any static storage or namespace scope C++ objects anywhere inside the SYCL runtime. Consider the static vector_class<plugin> Plugins added by this PR. The Plugins vector will be destroyed sometime after the application's main() function returns (or when exit() is called). However, a global destructor in the application could call SYCL APIs even after that. If such a call happens after Plugins is destroyed, the application will likely crash.

One way to solve this is to define a static pointer to vector_class instead. The initialize() function can call new to allocate the vector, with no matching delete. This means the memory will never be deallocated, but this is necessary if you want to support SYCL API calls even from global destructors. Of course, the problem might be wider than that this particular PR. There might be other code that defines static storage or namespace scope objects.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I also agree there is a problem caused by undefined order of global objects destruction. The pointer solution is an interesting one (especially for its simplicity), an is probably a suitable one where destructors have no important side effects.

An alternative would be to put some order to the objects destruction (there are C++ extensions to do so, e.g. GNU attribute "destructor" with priority: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html). Vlad mentioned there is already some llvm class like GlobalGlobal (not remembering the exact name), that are guaranteed to be destroyed after other globals.

Copy link
Contributor

Choose a reason for hiding this comment

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

I would prefer that we do not use global objects.

If it's really needed I would suggest having a global pointer solution which is deallocated in "GNU attribute "destructor"".

an is probably a suitable one where destructors have no important side effects.

Are you sure "plugins" have no important side effects? Shouldn't they at least dlclose a plugin library?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would suggest having a global pointer solution which is deallocated in "GNU attribute "destructor""

Can we work on it separately from this change?
I added a TODO explaining that we need to destruct plugins last of all.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok.

Copy link
Contributor

Choose a reason for hiding this comment

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

Are you sure "plugins" have no important side effects? Shouldn't they at least dlclose a plugin library?

I don't think the dlclose is necessary. Remember, this is happening right before the process terminates. The library will get implicitly dlclosed when the process termintes.

Copy link
Contributor

Choose a reason for hiding this comment

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

User can load libsycl.so using dlopen, pugins libraries will not be properly freed by dlclose.

static vector_class<plugin> Plugins;
if (PluginsInitDone) {
return Plugins;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems it is possible for two threads to reach this point, so both accesses Plugins var. This will lead to problems.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why? Plugins are really read-only immutable objects after they are constructed in pi::initilize(). We should probably make it explicitly such, so that people aren't able to write it.

Copy link
Contributor

Choose a reason for hiding this comment

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

If two threads create platforms for the first time simultaneously they can reach this point or I missing something?

…ference to the global vector of plugins, not a temporary copy of it.

Change-Id: Ic1373059c9697b0b4d318548b79be7bcb9d4f2a9
Signed-off-by: Sergey V Maslov <sergey.v.maslov@intel.com>
@smaslov-intel
Copy link
Contributor Author

Coming in #1868

dbudanov-cmplr pushed a commit to dbudanov-cmplr/llvm that referenced this pull request Sep 19, 2022
The old mutateCallInst* functions and the new mutator doesn't quite get some of
the value names correct, which necessitated some test changes that were looking
for particular value names.

Original commit:
KhronosGroup/SPIRV-LLVM-Translator@9284a33
dbudanov-cmplr pushed a commit to dbudanov-cmplr/llvm that referenced this pull request Sep 28, 2022
The old mutateCallInst* functions and the new mutator doesn't quite get some of
the value names correct, which necessitated some test changes that were looking
for particular value names.

Original commit:
KhronosGroup/SPIRV-LLVM-Translator@9284a33
aelovikov-intel added a commit to aelovikov-intel/llvm that referenced this pull request Feb 23, 2023
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.

5 participants