Files
TheRock/compiler/amd-llvm/libsycl/include/sycl/__impl/queue.hpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

441 lines
19 KiB
C++

//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file contains the declaration of the SYCL queue class, which
/// schedules kernels on a device.
///
//===----------------------------------------------------------------------===//
#ifndef _LIBSYCL___IMPL_QUEUE_HPP
#define _LIBSYCL___IMPL_QUEUE_HPP
#include <sycl/__impl/async_handler.hpp>
#include <sycl/__impl/device.hpp>
#include <sycl/__impl/event.hpp>
#include <sycl/__impl/property_list.hpp>
#include <sycl/__impl/detail/config.hpp>
#include <sycl/__impl/detail/default_async_handler.hpp>
#include <sycl/__impl/detail/get_device_kernel_info.hpp>
#include <sycl/__impl/detail/kernel_arg_helpers.hpp>
#include <sycl/__impl/detail/obj_utils.hpp>
#include <sycl/__impl/detail/unified_range_view.hpp>
_LIBSYCL_BEGIN_NAMESPACE_SYCL
class context;
namespace detail {
class QueueImpl;
template <typename, typename T> struct CheckFunctionCallOperator {
static_assert(std::integral_constant<T, false>::value,
"Second template parameter is required to be of function type");
};
template <typename F, typename RetT, typename... Args>
struct CheckFunctionCallOperator<F, RetT(Args...)> {
private:
template <typename T>
static constexpr auto check(T *) ->
typename std::is_same<decltype(std::declval<std::add_const_t<T>>()
.operator()(std::declval<Args>()...)),
RetT>::type;
template <typename> static constexpr std::false_type check(...);
using type = decltype(check<F>(0));
public:
static constexpr bool value = type::value;
};
} // namespace detail
// SYCL 2020 4.6.5. Queue class.
class _LIBSYCL_EXPORT queue {
public:
queue(const queue &rhs) = default;
queue(queue &&rhs) = default;
queue &operator=(const queue &rhs) = default;
queue &operator=(queue &&rhs) = default;
~queue() = default;
friend bool operator==(const queue &lhs, const queue &rhs) {
return lhs.impl == rhs.impl;
}
friend bool operator!=(const queue &lhs, const queue &rhs) {
return !(lhs == rhs);
}
/// Constructs a SYCL queue instance using the device returned by an instance
/// of default_selector.
///
/// \param propList is a list of properties for queue construction.
explicit queue(const property_list &propList = {})
: queue(detail::SelectDevice(default_selector_v),
detail::defaultAsyncHandler, propList) {}
/// Constructs a SYCL queue instance with an async_handler using the device
/// returned by an instance of default_selector.
///
/// \param asyncHandler is a SYCL asynchronous exception handler.
/// \param propList is a list of properties for queue construction.
explicit queue(const async_handler &asyncHandler,
const property_list &propList = {})
: queue(detail::SelectDevice(default_selector_v), asyncHandler,
propList) {}
/// Constructs a SYCL queue instance using the device identified by the
/// device selector provided.
/// \param deviceSelector is a SYCL 2020 Device Selector, a simple callable
/// that takes a device and returns an int
/// \param propList is a list of properties for queue construction.
template <
typename DeviceSelector,
typename = detail::EnableIfDeviceSelectorIsInvocable<DeviceSelector>>
explicit queue(const DeviceSelector &deviceSelector,
const property_list &propList = {})
: queue(detail::SelectDevice(deviceSelector), detail::defaultAsyncHandler,
propList) {}
/// Constructs a SYCL queue instance using the device identified by the
/// device selector provided.
/// \param deviceSelector is a SYCL 2020 Device Selector, a simple callable
/// that takes a device and returns an int
/// \param asyncHandler is a SYCL asynchronous exception handler.
/// \param propList is a list of properties for queue construction.
template <
typename DeviceSelector,
typename = detail::EnableIfDeviceSelectorIsInvocable<DeviceSelector>>
explicit queue(const DeviceSelector &deviceSelector,
const async_handler &asyncHandler,
const property_list &propList = {})
: queue(detail::SelectDevice(deviceSelector), asyncHandler, propList) {}
/// Constructs a SYCL queue instance using the device provided.
///
/// \param syclDevice is an instance of SYCL device.
/// \param propList is a list of properties for queue construction.
explicit queue(const device &syclDevice, const property_list &propList = {})
: queue(syclDevice, detail::defaultAsyncHandler, propList) {}
/// Constructs a SYCL queue instance with an async_handler using the device
/// provided.
///
/// \param syclDevice is an instance of SYCL device.
/// \param asyncHandler is a SYCL asynchronous exception handler.
/// \param propList is a list of properties for queue construction.
explicit queue(const device &syclDevice, const async_handler &asyncHandler,
const property_list &propList = {});
/// \return the SYCL backend associated with this queue.
backend get_backend() const noexcept;
/// \return the associated SYCL context.
context get_context() const;
/// \return the SYCL device this queue was constructed with.
device get_device() const;
/// Equivalent to has_property<property::queue::in_order>().
///
/// \return true if and only if the queue is in order.
bool is_in_order() const;
/// Queries the queue for information.
///
/// The return type depends on information being queried.
template <typename Param> typename Param::return_type get_info() const;
/// Queries the queue for SYCL backend-specific information.
///
/// The return type depends on the information being queried.
template <typename Param>
typename Param::return_type get_backend_info() const;
/// Blocks the calling thread until all commands previously submitted to this
/// queue have completed. Synchronous errors are reported through SYCL
/// exceptions.
void wait();
/// Defines and invokes a SYCL kernel function as a lambda expression or a
/// named function object type.
///
/// \param kernelFunc is the kernel functor or lambda.
/// \return an event that represents the status of the submitted kernel.
template <typename KernelName = detail::AutoName, typename KernelType>
event single_task(const KernelType &kernelFunc) {
return single_task<KernelName, KernelType>({}, kernelFunc);
}
/// Defines and invokes a SYCL kernel function as a lambda expression or a
/// named function object type.
///
/// \param depEvent is an event that specifies the kernel dependency.
/// \param kernelFunc is the kernel functor or lambda.
/// \return an event that represents the status of the submitted kernel.
template <typename KernelName = detail::AutoName, typename KernelType>
event single_task(event depEvent, const KernelType &kernelFunc) {
return single_task<KernelName, KernelType>({depEvent}, kernelFunc);
}
/// Defines and invokes a SYCL kernel function as a lambda expression or a
/// named function object type.
///
/// \param depEvents is a collection of events that specify the kernel
/// dependencies.
/// \param kernelFunc is the kernel functor or lambda.
/// \return an event that represents the status of the submitted kernel.
template <typename KernelName = detail::AutoName, typename KernelType>
event single_task(const std::vector<event> &depEvents,
const KernelType &kernelFunc) {
static_assert(
detail::CheckFunctionCallOperator<std::remove_reference_t<KernelType>,
void()>::value,
"Invalid kernel function signature.");
setKernelParameters(depEvents);
using NameT =
typename detail::get_kernel_name_t<KernelName, KernelType>::name;
submitSingleTask<NameT, KernelType>(kernelFunc);
return getLastEvent();
}
/// Defines and invokes a SYCL kernel function as a lambda expression or a
/// named function object type, for the specified range.
///
/// \param numWorkItems specifies the global work space of the kernel.
/// \param rest acts as if it was "const KernelType &KernelFunc".
// TODO: Rest will represent reduction types once it is supported.
template <typename KernelName = detail::AutoName, typename... Rest>
event parallel_for(range<1> numWorkItems, Rest &&...rest) {
return parallel_for<KernelName>(numWorkItems, {},
std::forward<Rest>(rest)...);
}
/// Defines and invokes a SYCL kernel function as a lambda expression or a
/// named function object type, for the specified range.
///
/// \param numWorkItems specifies the global work space of the kernel.
/// \param rest acts as if it was "const KernelType &KernelFunc".
// TODO: Rest will represent reduction types once it is supported.
template <typename KernelName = detail::AutoName, typename... Rest>
event parallel_for(range<2> numWorkItems, Rest &&...rest) {
return parallel_for<KernelName>(numWorkItems, {},
std::forward<Rest>(rest)...);
}
/// Defines and invokes a SYCL kernel function as a lambda expression or a
/// named function object type, for the specified range.
///
/// \param numWorkItems specifies the global work space of the kernel.
/// \param rest acts as if it was "const KernelType &KernelFunc".
// TODO: Rest will represent reduction types once it is supported.
template <typename KernelName = detail::AutoName, typename... Rest>
event parallel_for(range<3> numWorkItems, Rest &&...rest) {
return parallel_for<KernelName>(numWorkItems, {},
std::forward<Rest>(rest)...);
}
/// Defines and invokes a SYCL kernel function as a lambda expression or a
/// named function object type, for the specified range.
///
/// \param numWorkItems specifies the global work space of the kernel.
/// \param depEvent adds a requirement that the action represented by depEvent
/// must complete before executing this kernel.
/// \param rest acts as if it was "const KernelType &KernelFunc".
// TODO: Rest will represent reduction types once it is supported.
template <typename KernelName = detail::AutoName, typename... Rest>
event parallel_for(range<1> numWorkItems, event depEvent, Rest &&...rest) {
return parallel_for<KernelName>(numWorkItems, {depEvent},
std::forward<Rest>(rest)...);
}
/// Defines and invokes a SYCL kernel function as a lambda expression or a
/// named function object type, for the specified range.
///
/// \param numWorkItems specifies the global work space of the kernel.
/// \param depEvent adds a requirement that the action represented by depEvent
/// must complete before executing this kernel.
/// \param rest acts as if it was "const KernelType &KernelFunc".
// TODO: Rest will represent reduction types once it is supported.
template <typename KernelName = detail::AutoName, typename... Rest>
event parallel_for(range<2> numWorkItems, event depEvent, Rest &&...rest) {
return parallel_for<KernelName>(numWorkItems, {depEvent},
std::forward<Rest>(rest)...);
}
/// Defines and invokes a SYCL kernel function as a lambda expression or a
/// named function object type, for the specified range.
///
/// \param numWorkItems specifies the global work space of the kernel.
/// \param depEvent adds a requirement that the action represented by depEvent
/// must complete before executing this kernel.
/// \param rest acts as if it was "const KernelType &KernelFunc".
// TODO: Rest will represent reduction types once it is supported.
template <typename KernelName = detail::AutoName, typename... Rest>
event parallel_for(range<3> numWorkItems, event depEvent, Rest &&...rest) {
return parallel_for<KernelName>(numWorkItems, {depEvent},
std::forward<Rest>(rest)...);
}
/// Defines and invokes a SYCL kernel function as a lambda expression or a
/// named function object type, for the specified range.
///
/// \param numWorkItems specifies the global work space of the kernel
/// \param depEvents is a vector of events that specifies the kernel
/// dependencies.
/// \param rest acts as if it was "const KernelType &KernelFunc".
// TODO: Rest will represent reduction types once it is supported.
template <typename KernelName = detail::AutoName, typename... Rest>
event parallel_for(range<1> numWorkItems, const std::vector<event> &depEvents,
Rest &&...rest) {
return parallelForImpl<KernelName>(numWorkItems, depEvents,
std::forward<Rest>(rest)...);
}
/// Defines and invokes a SYCL kernel function as a lambda expression or a
/// named function object type, for the specified range.
///
/// \param numWorkItems specifies the global work space of the kernel
/// \param depEvents is a vector of events that specifies the kernel
/// dependencies.
/// \param rest acts as if it was "const KernelType &KernelFunc".
// TODO: Rest will represent reduction types once it is supported.
template <typename KernelName = detail::AutoName, typename... Rest>
event parallel_for(range<2> numWorkItems, const std::vector<event> &depEvents,
Rest &&...rest) {
return parallelForImpl<KernelName>(numWorkItems, depEvents,
std::forward<Rest>(rest)...);
}
/// Defines and invokes a SYCL kernel function as a lambda expression or a
/// named function object type, for the specified range.
///
/// \param numWorkItems specifies the global work space of the kernel
/// \param depEvents is a vector of events that specifies the kernel
/// dependencies.
/// \param rest acts as if it was "const KernelType &KernelFunc".
// TODO: Rest will represent reduction types once it is supported.
template <typename KernelName = detail::AutoName, typename... Rest>
event parallel_for(range<3> numWorkItems, const std::vector<event> &depEvents,
Rest &&...rest) {
return parallelForImpl<KernelName>(numWorkItems, depEvents,
std::forward<Rest>(rest)...);
}
private:
template <typename KernelName, int Dims, typename... Rest>
event parallelForImpl(range<Dims> numWorkItems,
const std::vector<event> &depEvents, Rest &&...rest) {
if constexpr (sizeof...(Rest) != 1)
throw sycl::exception(errc::feature_not_supported,
"Reductions are not supported");
setKernelParameters(depEvents, numWorkItems);
using KernelType =
std::decay_t<detail::nth_type_t<sizeof...(Rest) - 1, Rest...>>;
using LambdaArgType = sycl::detail::lambda_arg_type<KernelType, item<Dims>>;
static_assert(
std::is_convertible_v<sycl::item<Dims>, LambdaArgType> ||
std::is_convertible_v<sycl::item<Dims, false>, LambdaArgType>,
"Kernel argument of a sycl::parallel_for with sycl::range "
"must be either sycl::item or be convertible from sycl::item");
using TranformedLambdaArgType = std::conditional_t<
std::is_convertible_v<item<Dims>, LambdaArgType>, item<Dims>,
std::conditional_t<
std::is_convertible_v<item<Dims, false>, LambdaArgType>,
item<Dims, false>, LambdaArgType>>;
using NameT =
typename detail::get_kernel_name_t<KernelName, KernelType>::name;
submitParallelFor<NameT, TranformedLambdaArgType, KernelType>(rest...);
return getLastEvent();
}
/// Name of this function is defined by compiler. It generates a call to this
/// function in the host implementation of KernelFunc in submitSingleTask or
/// submitParallelFor.
/// \param KernelName the name of the kernel being invoked.
/// \param args the kernel arguments for the kernel invocation.
template <typename KN, typename... Args>
void sycl_kernel_launch(const char *KernelName, Args &&...args) {
static_assert(
sizeof...(args) == 1,
"sycl_kernel_launch expects only 2 arguments now: name of kernel and "
"callable object passed to kernel invocation by the user.");
auto FirstArg = std::get<0>(std::tie(args...));
submitKernelImpl(detail::getDeviceKernelInfo<KN>(KernelName), &FirstArg,
sizeof(FirstArg));
}
/// The sycl_kernel_entry_point attribute facilitates the generation of an
/// offload kernel entry point function with parameters corresponding to the
/// (potentially decomposed) kernel arguments and a body that executes the
/// kernel (after reconstructing the arguments if required).
#ifdef SYCL_LANGUAGE_VERSION
# define _LIBSYCL_ENTRY_POINT_ATTR__(KernelName) \
[[clang::sycl_kernel_entry_point(KernelName)]]
#else
# define _LIBSYCL_ENTRY_POINT_ATTR__(KernelName)
#endif // SYCL_LANGUAGE_VERSION
/// Specifies the parameters and body of the generated offload kernel entry
/// point for single_task invocations. On host, the compiler generates a call
/// to sycl_kernel_launch instead of the KernelFunc invocation.
template <typename KernelName, typename KernelType>
_LIBSYCL_ENTRY_POINT_ATTR__(KernelName)
void submitSingleTask(const KernelType &KernelFunc) {
KernelFunc();
}
/// Specifies the parameters and body of the generated offload kernel entry
/// point for parallel_for invocations. On host, the compiler generates a call
/// to sycl_kernel_launch instead of the KernelFunc invocation.
template <typename KernelName, typename ElementType, typename KernelType>
_LIBSYCL_ENTRY_POINT_ATTR__(KernelName)
void submitParallelFor(const KernelType &KernelFunc) {
KernelFunc(detail::Builder::getElement(detail::declptr<ElementType>()));
}
#undef _LIBSYCL_ENTRY_POINT_ATTR__
/// Passes kernel parameters to the runtime.
/// \param Events a collection of events representing dependencies of the
/// kernel to submit.
/// \param Range a unified view of the kernel execution range.
void setKernelParameters(const std::vector<event> &Events,
const detail::UnifiedRangeView &Range = {});
/// Passes kernel arguments to runtime.
/// If all the dependencies can be handled by the backend, the kernel is
/// submitted to it directly in this call.
/// \param KernelInfo the information for the kernel being invoked.
/// \param ArgData a pointer to the kernel argument.
/// \param ArgSize the size of the kernel argument.
void submitKernelImpl(detail::DeviceKernelInfo &KernelInfo, void *ArgData,
size_t ArgSize);
/// \return an event representing last kernel invocation.
event getLastEvent();
queue(const std::shared_ptr<detail::QueueImpl> &Impl) : impl(Impl) {}
std::shared_ptr<detail::QueueImpl> impl;
friend sycl::detail::ImplUtils;
}; // class queue
_LIBSYCL_END_NAMESPACE_SYCL
template <>
struct std::hash<sycl::queue> : public sycl::detail::HashBase<sycl::queue> {};
#endif // _LIBSYCL___IMPL_QUEUE_HPP