Skip to content

Commit

Permalink
Made vecmem::sycl::queue_wrapper use PIMPL.
Browse files Browse the repository at this point in the history
Also added additional functions to it as
quality-of-life improvements.
  • Loading branch information
krasznaa committed Jan 10, 2025
1 parent a7dc568 commit 6b3ddd6
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 112 deletions.
3 changes: 1 addition & 2 deletions sycl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ vecmem_add_library( vecmem_sycl sycl
"include/vecmem/utils/sycl/queue_wrapper.hpp"
"src/utils/sycl/queue_wrapper.sycl"
"src/utils/sycl/get_queue.hpp"
"src/utils/sycl/get_queue.sycl"
"src/utils/sycl/opaque_queue.hpp" )
"src/utils/sycl/get_queue.sycl" )
target_link_libraries( vecmem_sycl PUBLIC vecmem::core )

# Hide the library's symbols by default.
Expand Down
48 changes: 30 additions & 18 deletions sycl/include/vecmem/utils/sycl/queue_wrapper.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* VecMem project, part of the ACTS project (R&D line)
*
* (c) 2021-2024 CERN for the benefit of the ACTS project
* (c) 2021-2025 CERN for the benefit of the ACTS project
*
* Mozilla Public License Version 2.0
*/
Expand All @@ -11,14 +11,10 @@

// System include(s).
#include <memory>
#include <string>

namespace vecmem::sycl {

// Forward declaration(s).
namespace details {
class opaque_queue;
}

/// Wrapper class for @c ::sycl::queue
///
/// It is necessary for passing around SYCL queue objects in code that should
Expand All @@ -45,13 +41,6 @@ class queue_wrapper {
queue_wrapper(queue_wrapper&& parent);

/// Destructor
///
/// The destructor is declared and implemented explicitly as an empty
/// function to make sure that client code would not try to generate it
/// itself. Leading to problems about the symbols of
/// @c vecmem::sycl::details::opaque_queue not being available in
/// client code.
///
VECMEM_SYCL_EXPORT
~queue_wrapper();

Expand All @@ -69,12 +58,35 @@ class queue_wrapper {
VECMEM_SYCL_EXPORT
const void* queue() const;

private:
/// Bare pointer to the wrapped @c ::sycl::queue object
void* m_queue;
/// Wait for all tasks in the queue to complete
VECMEM_SYCL_EXPORT
void synchronize();

/// Smart pointer to the managed @c ::sycl::queue object
std::unique_ptr<details::opaque_queue> m_managedQueue;
/// Get the name of the device that the queue operates on
VECMEM_SYCL_EXPORT
std::string device_name() const;

/// Check if it's a CPU queue
bool is_cpu() const;
/// Check if it's a GPU queue
bool is_gpu() const;
/// Check if it's an accelerator (FPGA) queue
bool is_accelerator() const;

/// Check if it's an OpenCL queue
bool is_opencl() const;
/// Check if it's a Level-0 queue
bool is_level0() const;
/// Check if it's a CUDA queue
bool is_cuda() const;
/// Check if it's a HIP queue
bool is_hip() const;

private:
/// Structure holding the internals of the class
struct impl;
/// Pointer to the internal structure
std::unique_ptr<impl> m_impl;

}; // class queue_wrapper

Expand Down
6 changes: 3 additions & 3 deletions sycl/src/utils/sycl/get_queue.sycl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* VecMem project, part of the ACTS project (R&D line)
*
* (c) 2021-2024 CERN for the benefit of the ACTS project
* (c) 2021-2025 CERN for the benefit of the ACTS project
*
* Mozilla Public License Version 2.0
*/
Expand All @@ -16,13 +16,13 @@ namespace vecmem::sycl::details {
::sycl::queue& get_queue(vecmem::sycl::queue_wrapper& queue) {

assert(queue.queue() != nullptr);
return *(reinterpret_cast<::sycl::queue*>(queue.queue()));
return *(static_cast<::sycl::queue*>(queue.queue()));
}

const ::sycl::queue& get_queue(const vecmem::sycl::queue_wrapper& queue) {

assert(queue.queue() != nullptr);
return *(reinterpret_cast<const ::sycl::queue*>(queue.queue()));
return *(static_cast<const ::sycl::queue*>(queue.queue()));
}

} // namespace vecmem::sycl::details
20 changes: 0 additions & 20 deletions sycl/src/utils/sycl/opaque_queue.hpp

This file was deleted.

166 changes: 97 additions & 69 deletions sycl/src/utils/sycl/queue_wrapper.sycl
Original file line number Diff line number Diff line change
@@ -1,127 +1,155 @@
/* VecMem project, part of the ACTS project (R&D line)
*
* (c) 2021-2024 CERN for the benefit of the ACTS project
* (c) 2021-2025 CERN for the benefit of the ACTS project
*
* Mozilla Public License Version 2.0
*/

// Local include(s).
#include "get_queue.hpp"
#include "opaque_queue.hpp"
#include "vecmem/utils/debug.hpp"
#include "vecmem/utils/sycl/queue_wrapper.hpp"

// SYCL include(s).
#include <sycl/sycl.hpp>

// System include(s).
#include <cassert>

namespace vecmem::sycl {

queue_wrapper::queue_wrapper()
: m_queue(nullptr),
m_managedQueue(std::make_unique<details::opaque_queue>()) {
struct queue_wrapper::impl {
/// Bare pointer to the wrapped @c ::sycl::queue object
::sycl::queue* m_queue = nullptr;
/// Smart pointer to the managed @c ::sycl::queue object
std::shared_ptr<::sycl::queue> m_managedQueue;
};

queue_wrapper::queue_wrapper() : m_impl{std::make_unique<impl>()} {

m_queue = m_managedQueue.get();
m_impl->m_managedQueue = std::make_shared<::sycl::queue>();
m_impl->m_queue = m_impl->m_managedQueue.get();
VECMEM_DEBUG_MSG(1,
"Created an \"owning wrapper\" around a queue on "
"device: %s",
details::get_queue(*this)
.get_device()
m_impl->m_queue.get_device()
.get_info<::sycl::info::device::name>()
.c_str());
}

queue_wrapper::queue_wrapper(void* queue) : m_queue(queue), m_managedQueue() {
queue_wrapper::queue_wrapper(void* queue) : m_impl{std::make_unique<impl>()} {

assert(queue != nullptr);
m_impl->m_queue = static_cast<::sycl::queue*>(queue);
VECMEM_DEBUG_MSG(3,
"Created a \"view wrapper\" around a queue on "
"device: %s",
details::get_queue(*this)
.get_device()
m_impl->m_queue.get_device()
.get_info<::sycl::info::device::name>()
.c_str());
}

queue_wrapper::queue_wrapper(const queue_wrapper& parent)
: m_queue(nullptr), m_managedQueue() {

// Check whether the parent owns its own queue or not.
if (parent.m_managedQueue) {
// If so, make a copy of it, and own that copy in this object as well.
m_managedQueue =
std::make_unique<details::opaque_queue>(*(parent.m_managedQueue));
m_queue = m_managedQueue.get();
} else {
// If not, then let's just point at the same queue that somebody else
// owns.
m_queue = parent.m_queue;
}
}

queue_wrapper::queue_wrapper(queue_wrapper&& parent)
: m_queue(nullptr), m_managedQueue(std::move(parent.m_managedQueue)) {
: m_impl{std::make_unique<impl>()} {

// Set the bare pointer.
if (m_managedQueue) {
m_queue = m_managedQueue.get();
} else {
m_queue = parent.m_queue;
}
*m_impl = *(parent.m_impl);
}

queue_wrapper::~queue_wrapper() {}
queue_wrapper::queue_wrapper(queue_wrapper&& parent) = default;

queue_wrapper::~queue_wrapper() = default;

queue_wrapper& queue_wrapper::operator=(const queue_wrapper& rhs) {

// Avoid self-assignment.
if (this == &rhs) {
return *this;
}

// Check whether the copied object owns its own queue or not.
if (rhs.m_managedQueue) {
// If so, make a copy of it, and own that copy in this object as well.
m_managedQueue =
std::make_unique<details::opaque_queue>(*(rhs.m_managedQueue));
m_queue = m_managedQueue.get();
} else {
// If not, then let's just point at the same queue that somebody else
// owns.
m_queue = rhs.m_queue;
if (this != &rhs) {
*m_impl = *(rhs.m_impl);
}

// Return this object.
return *this;
}

queue_wrapper& queue_wrapper::operator=(queue_wrapper&& rhs) {
queue_wrapper& queue_wrapper::operator=(queue_wrapper&& rhs) = default;

// Avoid self-assignment.
if (this == &rhs) {
return *this;
}
void* queue_wrapper::queue() {

// Move the managed queue object.
m_managedQueue = std::move(rhs.m_managedQueue);
return m_impl->m_queue;
}

// Set the bare pointer.
if (m_managedQueue) {
m_queue = m_managedQueue.get();
} else {
m_queue = rhs.m_queue;
}
const void* queue_wrapper::queue() const {

// Return this object.
return *this;
return m_impl->m_queue;
}

void* queue_wrapper::queue() {
void queue_wrapper::synchronize() {

return m_queue;
assert(m_impl->m_queue != nullptr);
m_impl->m_queue->wait_and_throw();
}

const void* queue_wrapper::queue() const {
std::string queue_wrapper::device_name() const {

assert(m_impl->m_queue != nullptr);
return m_impl->m_queue->get_device().get_info<::sycl::info::device::name>();
}

bool queue_wrapper::is_cpu() const {

assert(m_impl->m_queue != nullptr);
return m_impl->m_queue->get_device().is_cpu();
}

bool queue_wrapper::is_gpu() const {

assert(m_impl->m_queue != nullptr);
return m_impl->m_queue->get_device().is_gpu();
}

bool queue_wrapper::is_accelerator() const {

assert(m_impl->m_queue != nullptr);
return m_impl->m_queue->get_device().is_accelerator();
}

bool queue_wrapper::is_opencl() const {

#if SYCL_BACKEND_OPENCL
assert(m_impl->m_queue != nullptr);
return (m_impl->m_queue->get_backend() == ::sycl::backend::opencl);
#else
return false;
#endif
}

bool queue_wrapper::is_level0() const {

#if SYCL_EXT_ONEAPI_BACKEND_LEVEL_ZERO
assert(m_impl->m_queue != nullptr);
return (m_impl->m_queue->get_backend() ==
::sycl::backend::ext_oneapi_level_zero);
#else
return false;
#endif
}

bool queue_wrapper::is_cuda() const {

#if SYCL_EXT_ONEAPI_BACKEND_CUDA
assert(m_impl->m_queue != nullptr);
return (m_impl->m_queue->get_backend() == ::sycl::backend::ext_oneapi_cuda);
#else
return false;
#endif
}

bool queue_wrapper::is_hip() const {

return m_queue;
#if SYCL_EXT_ONEAPI_BACKEND_HIP
assert(m_impl->m_queue != nullptr);
return (m_impl->m_queue->get_backend() == ::sycl::backend::ext_oneapi_hip);
#else
return false;
#endif
}

} // namespace vecmem::sycl

0 comments on commit 6b3ddd6

Please sign in to comment.