18 #include <shared_mutex>
19 #include <type_traits>
23 #ifdef ALPAKA_ACC_SYCL_ENABLED
25 # include <sycl/sycl.hpp>
29 template<concepts::Tag TTag>
32 template<concepts::Tag TTag>
33 class EventGenericSycl;
37 template<
typename T,
typename =
void>
38 inline constexpr
auto is_sycl_task =
false;
41 inline constexpr
auto is_sycl_task<T, std::void_t<decltype(T::is_sycl_task)>> =
true;
43 template<
typename T,
typename =
void>
44 inline constexpr
auto is_sycl_kernel =
false;
47 inline constexpr
auto is_sycl_kernel<T, std::void_t<decltype(T::is_sycl_kernel)>> =
true;
49 class QueueGenericSyclImpl
52 QueueGenericSyclImpl(sycl::context context, sycl::device device)
56 {sycl::property::queue::enable_profiling{}, sycl::property::queue::in_order{}}}
61 QueueGenericSyclImpl(QueueGenericSyclImpl
const& other) =
delete;
62 auto operator=(QueueGenericSyclImpl
const& rhs) -> QueueGenericSyclImpl& =
delete;
64 QueueGenericSyclImpl(QueueGenericSyclImpl&& other) noexcept =
delete;
65 auto operator=(QueueGenericSyclImpl&& rhs) noexcept -> QueueGenericSyclImpl& =
delete;
67 ~QueueGenericSyclImpl()
71 m_queue.wait_and_throw();
73 catch(sycl::exception
const& err)
75 std::cerr <<
"Caught SYCL exception while destructing a SYCL queue: " << err.what() <<
" ("
76 << err.code() <<
')' << std::endl;
78 catch(std::exception
const& err)
80 std::cerr <<
"The following runtime error(s) occured while destructing a SYCL queue:" << err.what()
86 auto clean_dependencies() ->
void
90 auto const old_end =
std::end(m_dependencies);
91 auto const new_end = std::remove_if(
95 return ev.get_info<sycl::info::event::command_execution_status>()
96 == sycl::info::event_command_status::complete;
99 m_dependencies.erase(new_end, old_end);
102 auto register_dependency(sycl::event event) ->
void
104 std::lock_guard<std::shared_mutex> lock{m_mutex};
106 clean_dependencies();
107 m_dependencies.push_back(event);
110 auto empty() const ->
bool
112 std::shared_lock<std::shared_mutex> lock{m_mutex};
113 return m_last_event.get_info<sycl::info::event::command_execution_status>()
114 == sycl::info::event_command_status::complete;
120 m_queue.wait_and_throw();
123 auto get_last_event() const -> sycl::event
125 std::shared_lock<std::shared_mutex> lock{m_mutex};
129 template<
bool TBlocking,
typename TTask>
130 auto enqueue(TTask
const& task) ->
void
133 std::lock_guard<std::shared_mutex> lock{m_mutex};
135 clean_dependencies();
138 if constexpr(is_sycl_task<TTask> && !is_sycl_kernel<TTask>)
140 m_last_event = task(m_queue, m_dependencies);
144 m_last_event = m_queue.submit(
145 [
this, &task](sycl::handler& cgh)
147 if(!m_dependencies.empty())
148 cgh.depends_on(m_dependencies);
150 if constexpr(is_sycl_kernel<TTask>)
157 m_dependencies.clear();
160 if constexpr(TBlocking)
169 std::vector<sycl::event> m_dependencies;
170 sycl::event m_last_event;
171 std::shared_mutex
mutable m_mutex;
177 template<concepts::Tag TTag,
bool TBlocking>
178 class QueueGenericSyclBase
179 :
public interface::Implements<ConceptCurrentThreadWaitFor, QueueGenericSyclBase<TTag, TBlocking>>
180 ,
public interface::Implements<ConceptQueue, QueueGenericSyclBase<TTag, TBlocking>>
181 ,
public interface::Implements<ConceptGetDev, QueueGenericSyclBase<TTag, TBlocking>>
184 QueueGenericSyclBase(DevGenericSycl<TTag>
const& dev)
186 , m_spQueueImpl{std::make_shared<detail::QueueGenericSyclImpl>(
190 m_dev.m_impl->register_queue(m_spQueueImpl);
193 friend auto operator==(QueueGenericSyclBase
const& lhs, QueueGenericSyclBase
const& rhs) ->
bool
195 return (lhs.m_dev == rhs.m_dev) && (lhs.m_spQueueImpl == rhs.m_spQueueImpl);
198 friend auto operator!=(QueueGenericSyclBase
const& lhs, QueueGenericSyclBase
const& rhs) ->
bool
200 return !(lhs == rhs);
205 return m_spQueueImpl->getNativeHandle();
208 DevGenericSycl<TTag> m_dev;
209 std::shared_ptr<detail::QueueGenericSyclImpl> m_spQueueImpl;
216 template<concepts::Tag TTag,
bool TBlocking>
217 struct DevType<
alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>>
219 using type = DevGenericSycl<TTag>;
223 template<concepts::Tag TTag,
bool TBlocking>
224 struct GetDev<
alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>>
226 static auto getDev(alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>
const& queue)
234 template<concepts::Tag TTag,
bool TBlocking>
235 struct EventType<
alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>>
237 using type = EventGenericSycl<TTag>;
241 template<concepts::Tag TTag,
bool TBlocking,
typename TTask>
242 struct Enqueue<
alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>, TTask>
244 static auto enqueue(alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>& queue, TTask
const& task)
248 queue.m_spQueueImpl->template enqueue<TBlocking>(task);
253 template<concepts::Tag TTag,
bool TBlocking>
254 struct Empty<
alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>>
256 static auto empty(alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>
const& queue) ->
bool
259 return queue.m_spQueueImpl->empty();
267 template<concepts::Tag TTag,
bool TBlocking>
268 struct CurrentThreadWaitFor<
alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>>
270 static auto currentThreadWaitFor(alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>
const& queue)
274 queue.m_spQueueImpl->wait();
279 template<concepts::Tag TTag,
bool TBlocking>
283 alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>
const& queue)
285 return queue.getNativeHandle();
#define ALPAKA_DEBUG_MINIMAL_LOG_SCOPE
constexpr ALPAKA_FN_HOST_ACC bool operator==(Complex< T > const &lhs, Complex< T > const &rhs)
Equality of two complex numbers.
constexpr ALPAKA_FN_HOST_ACC bool operator!=(Complex< T > const &lhs, Complex< T > const &rhs)
Inequality of two complex numbers.
ALPAKA_FN_HOST auto end(TView &view) -> Iterator< TView >
ALPAKA_FN_HOST auto begin(TView &view) -> Iterator< TView >
The alpaka accelerator library.
decltype(getNativeHandle(std::declval< TImpl >())) NativeHandle
Alias to the type of the native handle.
ALPAKA_FN_HOST auto getDev(T const &t)
ALPAKA_FN_HOST auto getNativeHandle(TImpl const &impl)
Get the native handle of the alpaka object. It will return the alpaka object handle if there is any,...
ALPAKA_FN_HOST auto empty(TQueue const &queue) -> bool
Tests if the queue is empty (all ops in the given queue have been completed).
ALPAKA_FN_HOST auto enqueue(TQueue &queue, TTask &&task) -> void
Queues the given task in the given queue.
ALPAKA_FN_HOST auto wait(TAwaited const &awaited) -> void
Waits the thread for the completion of the given awaited action to complete.