18#include <shared_mutex>
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
89 auto const start = std::begin(m_dependencies);
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};
132 template<
bool TBlocking,
typename TTask>
133 auto enqueue(TTask&& task) ->
void
136 using TaskType = std::decay_t<TTask>;
137 std::lock_guard<std::shared_mutex> lock{m_mutex};
139 clean_dependencies();
142 if constexpr(is_sycl_task<TaskType> && !is_sycl_kernel<TaskType>)
144 m_last_event = task(m_queue, m_dependencies);
148 m_last_event = m_queue.submit(
149 [
this, captured_task = std::forward<TTask>(task)](sycl::handler& cgh)
mutable
151 if(!m_dependencies.empty())
152 cgh.depends_on(m_dependencies);
154 if constexpr(is_sycl_kernel<TaskType>)
157 cgh.host_task(std::move(captured_task));
161 m_dependencies.clear();
164 if constexpr(TBlocking)
173 std::vector<sycl::event> m_dependencies;
174 sycl::event m_last_event;
175 std::shared_mutex
mutable m_mutex;
181 template<concepts::Tag TTag,
bool TBlocking>
182 class QueueGenericSyclBase
183 :
public interface::Implements<ConceptCurrentThreadWaitFor, QueueGenericSyclBase<TTag, TBlocking>>
184 ,
public interface::Implements<ConceptQueue, QueueGenericSyclBase<TTag, TBlocking>>
185 ,
public interface::Implements<ConceptGetDev, QueueGenericSyclBase<TTag, TBlocking>>
188 QueueGenericSyclBase(DevGenericSycl<TTag>
const& dev)
190 , m_spQueueImpl{
std::make_shared<detail::QueueGenericSyclImpl>(
194 m_dev.m_impl->register_queue(m_spQueueImpl);
197 friend auto operator==(QueueGenericSyclBase
const& lhs, QueueGenericSyclBase
const& rhs) ->
bool
199 return (lhs.m_dev == rhs.m_dev) && (lhs.m_spQueueImpl == rhs.m_spQueueImpl);
202 friend auto operator!=(QueueGenericSyclBase
const& lhs, QueueGenericSyclBase
const& rhs) ->
bool
204 return !(lhs == rhs);
209 return m_spQueueImpl->getNativeHandle();
212 DevGenericSycl<TTag> m_dev;
213 std::shared_ptr<detail::QueueGenericSyclImpl> m_spQueueImpl;
220 template<concepts::Tag TTag,
bool TBlocking>
221 struct DevType<
alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>>
223 using type = DevGenericSycl<TTag>;
227 template<concepts::Tag TTag,
bool TBlocking>
228 struct GetDev<
alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>>
230 static auto getDev(alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>
const& queue)
238 template<concepts::Tag TTag,
bool TBlocking>
239 struct EventType<
alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>>
241 using type = EventGenericSycl<TTag>;
245 template<concepts::Tag TTag,
bool TBlocking,
typename TTask>
246 struct Enqueue<
alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>, TTask>
248 template<
typename UTask>
249 static auto enqueue(alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>& queue, UTask&& task) ->
void
252 queue.m_spQueueImpl->template enqueue<TBlocking>(std::forward<UTask>(task));
257 template<concepts::Tag TTag,
bool TBlocking>
258 struct Empty<
alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>>
260 static auto empty(alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>
const& queue) ->
bool
263 return queue.m_spQueueImpl->empty();
271 template<concepts::Tag TTag,
bool TBlocking>
272 struct CurrentThreadWaitFor<
alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>>
274 static auto currentThreadWaitFor(alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>
const& queue)
278 queue.m_spQueueImpl->wait();
283 template<concepts::Tag TTag,
bool TBlocking>
287 alpaka::detail::QueueGenericSyclBase<TTag, TBlocking>
const& queue)
289 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.
The alpaka accelerator library.
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.
decltype(getNativeHandle(std::declval< TImpl >())) NativeHandle
Alias to the type of the native handle.