[libsycl] Add liboffload context handler to default context (#213249)
Signed-off-by: Tikhomirova, Kseniya <kseniya.tikhomirova@intel.com>
This commit is contained in:
parent
8719d58faf
commit
1505b3e83d
7 changed files with 115 additions and 19 deletions
|
|
@ -13,15 +13,41 @@ _LIBSYCL_BEGIN_NAMESPACE_SYCL
|
|||
|
||||
namespace detail {
|
||||
|
||||
void ContextImpl::iterateDevices(
|
||||
const std::function<void(DeviceImpl *)> &callback) const {
|
||||
// TODO: Intentionally don't store devices in context now. This class should
|
||||
// be reimplemented once liboffload adds context support. Treat context as
|
||||
// default context that is associated with all devices in the platform.
|
||||
return MPlatform.iterateDevices(info::device_type::all, callback);
|
||||
ContextImpl::ContextImpl(std::vector<DeviceImpl *> &&DeviceList,
|
||||
const async_handler &AsyncHandler,
|
||||
const property_list &PropList, Private)
|
||||
: MAsyncHandler(AsyncHandler), MDevices(DeviceList) {
|
||||
(void)PropList;
|
||||
|
||||
assert(!MDevices.empty() && "Device list must not be empty");
|
||||
|
||||
std::vector<ol_device_handle_t> DeviceIds;
|
||||
DeviceIds.reserve(MDevices.size());
|
||||
for (DeviceImpl *D : MDevices) {
|
||||
assert(D && "Device list must not contain null entries");
|
||||
DeviceIds.push_back(D->getOLHandle());
|
||||
}
|
||||
|
||||
backend ContextImpl::getBackend() const { return MPlatform.getBackend(); }
|
||||
callAndThrow(olCreateContext, DeviceIds.size(), DeviceIds.data(),
|
||||
&MOffloadContext);
|
||||
}
|
||||
|
||||
ContextImpl::~ContextImpl() {
|
||||
assert(MOffloadContext && "Context must be created in ctor");
|
||||
std::ignore = olDestroyContext(MOffloadContext);
|
||||
}
|
||||
|
||||
PlatformImpl &ContextImpl::getPlatformImpl() const {
|
||||
return MDevices[0]->getPlatformImpl();
|
||||
}
|
||||
|
||||
void ContextImpl::iterateDevices(
|
||||
const std::function<void(DeviceImpl *)> &callback) const {
|
||||
for (DeviceImpl *Device : MDevices)
|
||||
callback(Device);
|
||||
}
|
||||
|
||||
backend ContextImpl::getBackend() const { return MDevices[0]->getBackend(); }
|
||||
|
||||
} // namespace detail
|
||||
_LIBSYCL_END_NAMESPACE_SYCL
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#ifndef _LIBSYCL_CONTEXT_IMPL
|
||||
#define _LIBSYCL_CONTEXT_IMPL
|
||||
|
||||
#include <sycl/__impl/async_handler.hpp>
|
||||
#include <sycl/__impl/context.hpp>
|
||||
#include <sycl/__impl/detail/config.hpp>
|
||||
|
||||
|
|
@ -23,16 +24,14 @@
|
|||
#include <functional>
|
||||
|
||||
_LIBSYCL_BEGIN_NAMESPACE_SYCL
|
||||
|
||||
class property_list;
|
||||
|
||||
namespace detail {
|
||||
|
||||
class PlatformImpl;
|
||||
class DeviceImpl;
|
||||
|
||||
// TODO: Presence of context object is essential for many APIs. Current
|
||||
// implementation of this class is a way to support them in case of absence of
|
||||
// context support in liboffload. For backends where context exists and
|
||||
// participates in operations, liboffload plugins create and use default context
|
||||
// that represents all devices in that platform. Duplicating this logic here.
|
||||
/// Context represents the runtime data structures and state required by a SYCL
|
||||
/// backend API to interact with a group of devices associated with a platform.
|
||||
class ContextImpl : public std::enable_shared_from_this<ContextImpl> {
|
||||
|
|
@ -41,12 +40,22 @@ class ContextImpl : public std::enable_shared_from_this<ContextImpl> {
|
|||
};
|
||||
|
||||
public:
|
||||
/// Constructs a ContextImpl using a platform.
|
||||
/// Constructs a context implementation for the provided devices.
|
||||
///
|
||||
/// Newly created instance represents all devices in platform.
|
||||
/// \param DeviceList is the list of devices associated with this context.
|
||||
/// \param AsyncHandler is a SYCL asynchronous exception handler.
|
||||
/// \param PropList is a list of context properties.
|
||||
ContextImpl(std::vector<DeviceImpl *> &&DeviceList,
|
||||
const async_handler &AsyncHandler, const property_list &PropList,
|
||||
Private);
|
||||
|
||||
/// Releases the underlying offload context handle.
|
||||
~ContextImpl();
|
||||
|
||||
/// Gets asynchronous exception handler.
|
||||
///
|
||||
/// \param Platform is a platform to associate this context with.
|
||||
ContextImpl(PlatformImpl &Platform, Private) : MPlatform(Platform) {}
|
||||
/// \return an instance of SYCL async_handler.
|
||||
const async_handler &get_async_handler() const { return MAsyncHandler; }
|
||||
|
||||
/// Constructs a ContextImpl with a provided arguments. Variadic helper.
|
||||
/// Restrics ways of ContextImpl creation.
|
||||
|
|
@ -55,8 +64,16 @@ public:
|
|||
return std::make_shared<ContextImpl>(std::forward<Ts>(args)..., Private{});
|
||||
}
|
||||
|
||||
/// Returns the raw underlying offload context handle.
|
||||
///
|
||||
/// The caller is responsible for ensuring that the returned handle is only
|
||||
/// used while this ContextImpl object is alive.
|
||||
///
|
||||
/// \return the raw offload context handle.
|
||||
const ol_context_handle_t &getOLHandleRef() const { return MOffloadContext; }
|
||||
|
||||
/// \return the platform this context is associated with.
|
||||
PlatformImpl &getPlatformImpl() const { return MPlatform; }
|
||||
PlatformImpl &getPlatformImpl() const;
|
||||
|
||||
/// Calls "callback" with every device associated
|
||||
/// with this context.
|
||||
|
|
@ -66,7 +83,9 @@ public:
|
|||
backend getBackend() const;
|
||||
|
||||
private:
|
||||
PlatformImpl &MPlatform;
|
||||
const async_handler MAsyncHandler;
|
||||
const std::vector<DeviceImpl *> MDevices;
|
||||
ol_context_handle_t MOffloadContext{};
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <sycl/__impl/detail/config.hpp>
|
||||
#include <sycl/__impl/detail/obj_utils.hpp>
|
||||
#include <sycl/__impl/property_list.hpp>
|
||||
|
||||
#include <detail/context_impl.hpp>
|
||||
#include <detail/device_impl.hpp>
|
||||
|
|
@ -92,7 +93,13 @@ PlatformImpl::PlatformImpl(ol_platform_handle_t Platform, size_t PlatformIndex,
|
|||
Device, *this, DeviceImpl::PrivateTag{}));
|
||||
});
|
||||
|
||||
MDefaultContext = ContextImpl::create(*this);
|
||||
std::vector<DeviceImpl *> DeviceImpls;
|
||||
DeviceImpls.reserve(MRootDevices.size());
|
||||
for (const auto &Device : MRootDevices)
|
||||
DeviceImpls.push_back(Device.get());
|
||||
|
||||
MDefaultContext = ContextImpl::create(std::move(DeviceImpls),
|
||||
defaultAsyncHandler, property_list{});
|
||||
}
|
||||
|
||||
const std::vector<DeviceImplUPtr> &PlatformImpl::getRootDevices() const {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <detail/queue_impl.hpp>
|
||||
|
||||
#include <detail/context_impl.hpp>
|
||||
#include <detail/device_impl.hpp>
|
||||
#include <detail/event_impl.hpp>
|
||||
#include <detail/global_objects.hpp>
|
||||
|
|
@ -66,6 +67,8 @@ QueueImpl::QueueImpl(DeviceImpl &deviceImpl, const async_handler &asyncHandler,
|
|||
: MIsInorder(false), MAsyncHandler(asyncHandler), MPropList(propList),
|
||||
MDevice(deviceImpl),
|
||||
MContext(MDevice.getPlatformImpl().getDefaultContext()) {
|
||||
assert(MContext.getOLHandleRef() &&
|
||||
"Queue must be associated with a valid offload context");
|
||||
callAndThrow(olCreateQueue, MDevice.getOLHandle(), &MOffloadQueue);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -181,6 +181,33 @@ void mock::MockLiboffload::initDefault() {
|
|||
return OL_SUCCESS;
|
||||
});
|
||||
|
||||
ON_CALL(*this, olCreateContext)
|
||||
.WillByDefault([this](size_t NumDevices, ol_device_handle_t *Devices,
|
||||
ol_context_handle_t *Context) -> ol_result_t {
|
||||
if (!Devices || !Context)
|
||||
return makeEmptyStrError(OL_ERRC_INVALID_NULL_POINTER);
|
||||
if (NumDevices == 0)
|
||||
return makeEmptyStrError(OL_ERRC_INVALID_SIZE);
|
||||
for (size_t I = 0; I < NumDevices; ++I) {
|
||||
if (!Devices[I])
|
||||
return makeEmptyStrError(OL_ERRC_INVALID_NULL_HANDLE);
|
||||
}
|
||||
|
||||
// Preserve the first device in payload for tests that may need to
|
||||
// inspect what device set the context was created from.
|
||||
*Context = mock::createDummyHandleWithData<ol_context_handle_t>(
|
||||
reinterpret_cast<unsigned char *>(&Devices[0]), sizeof(Devices[0]));
|
||||
return OL_SUCCESS;
|
||||
});
|
||||
|
||||
ON_CALL(*this, olDestroyContext)
|
||||
.WillByDefault([this](ol_context_handle_t Context) -> ol_result_t {
|
||||
if (!Context)
|
||||
return makeEmptyStrError(OL_ERRC_INVALID_NULL_HANDLE);
|
||||
mock::releaseDummyHandle(Context);
|
||||
return OL_SUCCESS;
|
||||
});
|
||||
|
||||
ON_CALL(*this, olCreateProgram)
|
||||
.WillByDefault([this](ol_device_handle_t Device, const void *ProgData,
|
||||
size_t ProgDataSize,
|
||||
|
|
|
|||
|
|
@ -89,6 +89,10 @@ public:
|
|||
MOCK_METHOD(ol_result_t, olIterateDevices,
|
||||
(ol_device_iterate_cb_t Callback, void *UserData));
|
||||
MOCK_METHOD(ol_result_t, olDestroyProgram, (ol_program_handle_t Program));
|
||||
MOCK_METHOD(ol_result_t, olCreateContext,
|
||||
(size_t NumDevices, ol_device_handle_t *Devices,
|
||||
ol_context_handle_t *Context));
|
||||
MOCK_METHOD(ol_result_t, olDestroyContext, (ol_context_handle_t Context));
|
||||
MOCK_METHOD(ol_result_t, olCreateQueue,
|
||||
(ol_device_handle_t Device, ol_queue_handle_t *Queue));
|
||||
MOCK_METHOD(ol_result_t, olDestroyQueue, (ol_queue_handle_t Queue));
|
||||
|
|
|
|||
|
|
@ -50,6 +50,16 @@ ol_result_t olDestroyProgram(ol_program_handle_t Program) {
|
|||
return mock::getMockLiboffload().olDestroyProgram(Program);
|
||||
}
|
||||
|
||||
ol_result_t olCreateContext(size_t NumDevices, ol_device_handle_t *Devices,
|
||||
ol_context_handle_t *Context) {
|
||||
return mock::getMockLiboffload().olCreateContext(NumDevices, Devices,
|
||||
Context);
|
||||
}
|
||||
|
||||
ol_result_t olDestroyContext(ol_context_handle_t Context) {
|
||||
return mock::getMockLiboffload().olDestroyContext(Context);
|
||||
}
|
||||
|
||||
ol_result_t olCreateQueue(ol_device_handle_t Device, ol_queue_handle_t *Queue) {
|
||||
return mock::getMockLiboffload().olCreateQueue(Device, Queue);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue