-
Notifications
You must be signed in to change notification settings - Fork 114
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
Lazy initialization of queue inside dpcpp_default policy #1154
Changes from all commits
3c95aca
a3aea24
5699334
8b6bd6d
888e0cb
2c3096d
9d6b47a
fee82e0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,8 @@ | |
|
||
#include "sycl_defs.h" | ||
|
||
#include <mutex> | ||
#include <optional> | ||
#include <type_traits> | ||
|
||
namespace oneapi | ||
|
@@ -42,21 +44,66 @@ struct DefaultKernelName; | |
template <typename KernelName = DefaultKernelName> | ||
class device_policy | ||
{ | ||
// Needed for the copy constructor that rebinds the kernel name | ||
template <typename> | ||
friend class device_policy; | ||
|
||
template <typename T> | ||
static auto | ||
lock_and_forward(T&& t, std::mutex& mtx) | ||
adamfidel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
::std::scoped_lock lock{mtx}; | ||
return std::forward<T>(t); | ||
} | ||
|
||
public: | ||
using kernel_name = KernelName; | ||
|
||
device_policy() = default; | ||
explicit device_policy(sycl::queue q_) : q(q_) {} | ||
explicit device_policy(sycl::device d_) { q.emplace(d_); } | ||
|
||
template <typename OtherName> | ||
device_policy(const device_policy<OtherName>& other) : q(other.queue()) | ||
device_policy(const device_policy<OtherName>& other) : q(device_policy::lock_and_forward(other.q, other.mtx)) | ||
{ | ||
} | ||
explicit device_policy(sycl::queue q_) : q(q_) {} | ||
explicit device_policy(sycl::device d_) : q(d_) {} | ||
operator sycl::queue() const { return q; } | ||
|
||
device_policy(const device_policy& other) : q(device_policy::lock_and_forward(other.q, other.mtx)) {} | ||
|
||
device_policy(device_policy&& other) : q(device_policy::lock_and_forward(::std::move(other.q), other.mtx)) {} | ||
|
||
device_policy& | ||
operator=(const device_policy& other) | ||
SergeyKopienko marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
if (this != &other) | ||
{ | ||
::std::scoped_lock lock{mtx, other.mtx}; | ||
q = other.q; | ||
} | ||
return *this; | ||
} | ||
|
||
device_policy& | ||
operator=(device_policy&& other) | ||
{ | ||
if (this != &other) | ||
{ | ||
::std::scoped_lock lock{mtx, other.mtx}; | ||
q = ::std::move(other.q); | ||
} | ||
return *this; | ||
} | ||
|
||
operator sycl::queue() const { return queue(); } | ||
sycl::queue | ||
queue() const | ||
{ | ||
return q; | ||
::std::scoped_lock lock{mtx}; | ||
if (!q) | ||
SergeyKopienko marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
q.emplace(); | ||
} | ||
return *q; | ||
} | ||
|
||
// For internal use only | ||
|
@@ -77,8 +124,9 @@ class device_policy | |
return ::std::true_type{}; | ||
} | ||
|
||
private: | ||
sycl::queue q; | ||
protected: | ||
mutable ::std::mutex mtx; | ||
SergeyKopienko marked this conversation as resolved.
Show resolved
Hide resolved
|
||
mutable ::std::optional<sycl::queue> q; | ||
mmichel11 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}; | ||
|
||
#if _ONEDPL_FPGA_DEVICE | ||
|
@@ -91,21 +139,31 @@ class fpga_policy : public device_policy<KernelName> | |
public: | ||
static constexpr unsigned int unroll_factor = factor; | ||
|
||
fpga_policy() | ||
: base(sycl::queue( | ||
# if _ONEDPL_FPGA_EMU | ||
__dpl_sycl::__fpga_emulator_selector() | ||
# else | ||
__dpl_sycl::__fpga_selector() | ||
# endif // _ONEDPL_FPGA_EMU | ||
)) | ||
fpga_policy() = default; | ||
template <unsigned int other_factor, typename OtherName> | ||
fpga_policy(const fpga_policy<other_factor, OtherName>& other) : base(other.queue()) | ||
{ | ||
} | ||
|
||
template <unsigned int other_factor, typename OtherName> | ||
fpga_policy(const fpga_policy<other_factor, OtherName>& other) : base(other.queue()){}; | ||
explicit fpga_policy(sycl::queue q) : base(q) {} | ||
explicit fpga_policy(sycl::device d) : base(d) {} | ||
|
||
operator sycl::queue() const { return queue(); } | ||
sycl::queue | ||
queue() const | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Am I correct that this function
fpga_policy policy;
auto& d_policy = static_cast<device_policy&>(policy);
fpga_policy policy;
auto& d_policy = static_cast<device_policy&>(policy);
auto q = d_policy.queue(); // call device_policy::queue() !? Looks like we will call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or we need some another approach to resolve this issue: may be we are able to pack May be able to apply something like #1158 template <unsigned int other_factor, typename OtherName>
fpga_policy(const fpga_policy<other_factor, OtherName>& other) : base(other.queue()){}; See my comment https://github.com/oneapi-src/oneDPL/pull/1154/files#r1318324154 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel like that:
|
||
{ | ||
::std::scoped_lock lock{this->mtx}; | ||
if (!this->q) | ||
{ | ||
this->q.emplace( | ||
# if _ONEDPL_FPGA_EMU | ||
__dpl_sycl::__fpga_emulator_selector() | ||
# else | ||
__dpl_sycl::__fpga_selector() | ||
# endif // _ONEDPL_FPGA_EMU | ||
); | ||
} | ||
return *this->q; | ||
} | ||
}; | ||
|
||
#endif // _ONEDPL_FPGA_DEVICE | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we also add a test that fails before this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might be able to add a test that just includes oneDPL but doesn't call anything, and then invoke it with a device filter that disables all devices (e.g.,
ONEAPI_DEVICE_SELECTOR='!*:*'
). In this case, the old code should throw an exception whereas this PR should not.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have manually confirmed that this test works in principle. I created the following test:
Running it as
ONEAPI_DEVICE_SELECTOR='!*:*' ./build/test/header_inclusion_only.pass
crashes on main but does not crash with this branch.I feel that there is benefit in adding this test, but it will require some special changes to the CMake to modify the environment specifically for this test. It is further complicated by the fact that the CMake files currently already do something similar with the variable
$ONEAPI_DEVICE_SELECTOR
, which is either set toONEAPI_DEVICE_SELECTOR=gpu/acc/fpga
orSYCL_DEVICE_FILTER=gpu/acc/fpga
depending on the compiler version and device type.The dynamic selection branch also makes changes to this variable. In all, I believe that there is value for adding this test but the risks are high to unintentionally break something with this being so close to the code freeze.