Skip to content

[SYCL] Introduce interop handle for host task #1747

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

Merged
merged 13 commits into from
Jun 9, 2020
Merged
1 change: 1 addition & 0 deletions sycl/include/CL/sycl/detail/cg.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <CL/sycl/detail/type_traits.hpp>
#include <CL/sycl/group.hpp>
#include <CL/sycl/id.hpp>
#include <CL/sycl/interop_handle.hpp>
#include <CL/sycl/interop_handler.hpp>
#include <CL/sycl/kernel.hpp>
#include <CL/sycl/nd_item.hpp>
Expand Down
147 changes: 147 additions & 0 deletions sycl/include/CL/sycl/interop_handle.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
//==------------ interop_handle.hpp --- SYCL interop handle ----------------==//
//
// 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
//
//===----------------------------------------------------------------------===//

#pragma once

#include <CL/sycl/access/access.hpp>
#include <CL/sycl/accessor.hpp>
#include <CL/sycl/backend_types.hpp>
#include <CL/sycl/detail/accessor_impl.hpp>
#include <CL/sycl/detail/common.hpp>
#include <CL/sycl/detail/defines.hpp>
#include <CL/sycl/detail/pi.hpp>

#include <memory>

__SYCL_INLINE_NAMESPACE(cl) {
namespace sycl {

namespace detail {
class AccessorBaseHost;
class ExecCGCommand;
class DispatchHostTask;
class queue_impl;
class device_impl;
class context_impl;
} // namespace detail

class queue;
class device;
class context;

class interop_handle {
public:
/// Receives a SYCL accessor that has been defined as a requirement for the
/// command group, and returns the underlying OpenCL memory object that is
/// used by the SYCL runtime. If the accessor passed as parameter is not part
/// of the command group requirements (e.g. it is an unregistered placeholder
/// accessor), the exception `cl::sycl::invalid_object` is thrown
/// asynchronously.
template <backend BackendName = backend::opencl, typename DataT, int Dims,
access::mode Mode, access::target Target, access::placeholder IsPlh>
typename std::enable_if<
Target != access::target::host_buffer,
typename interop<BackendName,
accessor<DataT, Dims, Mode, Target, IsPlh>>::type>::type
get_native_mem(const accessor<DataT, Dims, Mode, Target, IsPlh> &Acc) const {
#ifndef __SYCL_DEVICE_ONLY__
const auto *AccBase = static_cast<const detail::AccessorBaseHost *>(&Acc);
return getMemImpl<BackendName, DataT, Dims, Mode, Target, IsPlh>(
detail::getSyclObjImpl(*AccBase).get());
#else
(void)Acc;
// we believe this won't be ever called on device side
return nullptr;
#endif
}

template <backend BackendName = backend::opencl, typename DataT, int Dims,
access::mode Mode, access::target Target, access::placeholder IsPlh>
typename std::enable_if<
Target == access::target::host_buffer,
typename interop<BackendName,
accessor<DataT, Dims, Mode, Target, IsPlh>>::type>::type
get_native_mem(const accessor<DataT, Dims, Mode, Target, IsPlh> &) const {
throw invalid_object_error("Getting memory object out of host accessor is "
"not allowed",
PI_INVALID_MEM_OBJECT);
}

/// Returns an underlying OpenCL queue for the SYCL queue used to submit the
/// command group, or the fallback queue if this command-group is re-trying
/// execution on an OpenCL queue. The OpenCL command queue returned is
/// implementation-defined in cases where the SYCL queue maps to multiple
/// underlying OpenCL objects. It is responsibility of the SYCL runtime to
/// ensure the OpenCL queue returned is in a state that can be used to
/// dispatch work, and that other potential OpenCL command queues associated
/// with the same SYCL command queue are not executing commands while the host
/// task is executing.
template <backend BackendName = backend::opencl>
auto get_native_queue() const noexcept ->
typename interop<BackendName, queue>::type {
return reinterpret_cast<typename interop<BackendName, queue>::type>(
getNativeQueue());
}

/// Returns an underlying OpenCL device associated with the SYCL queue used
/// to submit the command group, or the fallback queue if this command-group
/// is re-trying execution on an OpenCL queue.
template <backend BackendName = backend::opencl>
auto get_native_device() const noexcept ->
typename interop<BackendName, device>::type {
return reinterpret_cast<typename interop<BackendName, device>::type>(
getNativeDevice());
}

/// Returns an underlying OpenCL context associated with the SYCL queue used
/// to submit the command group, or the fallback queue if this command-group
/// is re-trying execution on an OpenCL queue.
template <backend BackendName = backend::opencl>
auto get_native_context() const noexcept ->
typename interop<BackendName, context>::type {
return reinterpret_cast<typename interop<BackendName, context>::type>(
getNativeContext());
}

private:
using ReqToMem = std::pair<detail::Requirement *, pi_mem>;

public:
// TODO set c-tor private
interop_handle(std::vector<ReqToMem> MemObjs,
const std::shared_ptr<detail::queue_impl> &Queue,
const std::shared_ptr<detail::device_impl> &Device,
const std::shared_ptr<detail::context_impl> &Context)
: MQueue(Queue), MDevice(Device), MContext(Context),
MMemObjs(std::move(MemObjs)) {}

private:
template <backend BackendName, typename DataT, int Dims, access::mode Mode,
access::target Target, access::placeholder IsPlh>
auto getMemImpl(detail::Requirement *Req) const ->
typename interop<BackendName,
accessor<DataT, Dims, Mode, Target, IsPlh>>::type {
return reinterpret_cast<typename interop<
BackendName, accessor<DataT, Dims, Mode, Target, IsPlh>>::type>(
getNativeMem(Req));
}

pi_native_handle getNativeMem(detail::Requirement *Req) const;
pi_native_handle getNativeQueue() const;
pi_native_handle getNativeDevice() const;
pi_native_handle getNativeContext() const;

std::shared_ptr<detail::queue_impl> MQueue;
std::shared_ptr<detail::device_impl> MDevice;
std::shared_ptr<detail::context_impl> MContext;

std::vector<ReqToMem> MMemObjs;
};

} // namespace sycl
} // __SYCL_INLINE_NAMESPACE(cl)
1 change: 1 addition & 0 deletions sycl/source/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ set(SYCL_SOURCES
"function_pointer.cpp"
"half_type.cpp"
"handler.cpp"
"interop_handle.cpp"
"interop_handler.cpp"
"kernel.cpp"
"platform.cpp"
Expand Down
50 changes: 50 additions & 0 deletions sycl/source/interop_handle.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//==------------ interop_handle.cpp --- SYCL interop handle ----------------==//
//
// 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
//
//===----------------------------------------------------------------------===//

#include <CL/sycl/detail/accessor_impl.hpp>
#include <CL/sycl/exception.hpp>
#include <CL/sycl/interop_handle.hpp>
#include <detail/context_impl.hpp>
#include <detail/device_impl.hpp>
#include <detail/queue_impl.hpp>

#include <algorithm>

__SYCL_INLINE_NAMESPACE(cl) {
namespace sycl {

pi_native_handle interop_handle::getNativeMem(detail::Requirement *Req) const {
auto Iter = std::find_if(std::begin(MMemObjs), std::end(MMemObjs),
[=](ReqToMem Elem) { return (Elem.first == Req); });

if (Iter == std::end(MMemObjs)) {
throw invalid_object_error("Invalid memory object used inside interop",
PI_INVALID_MEM_OBJECT);
}

auto Plugin = MQueue->getPlugin();
pi_native_handle Handle;
Plugin.call<detail::PiApiKind::piextMemGetNativeHandle>(Iter->second,
&Handle);
return Handle;
}

pi_native_handle interop_handle::getNativeDevice() const {
return MDevice->getNative();
}

pi_native_handle interop_handle::getNativeContext() const {
return MContext->getNative();
}

pi_native_handle interop_handle::getNativeQueue() const {
return MQueue->getNative();
}

} // namespace sycl
} // __SYCL_INLINE_NAMESPACE(cl)