From b5ca7585c8d7a381cb75e164fe9dc14558ff2ede Mon Sep 17 00:00:00 2001 From: Steffen Larsen Date: Tue, 22 Feb 2022 20:59:47 +0300 Subject: [PATCH 01/14] [SYCL] Implement resource pool for implementation allocations These changes add a "resource pool" used by the SYCL implementation to get auxiliary device memory resources. When a resource is deleted it returns its memory to the pool to be reacquired by other internal logic. Additionally, reductions that need additional resources are made to use the pool when getting these. Signed-off-by: Steffen Larsen --- sycl/doc/EnvironmentVariables.md | 1 + sycl/include/CL/sycl/buffer.hpp | 5 + sycl/include/CL/sycl/detail/buffer_impl.hpp | 7 + sycl/include/CL/sycl/detail/resource_pool.hpp | 269 ++++++++++++++++++ .../include/CL/sycl/detail/sycl_mem_obj_t.hpp | 4 + sycl/include/CL/sycl/handler.hpp | 37 +++ sycl/include/sycl/ext/oneapi/reduction.hpp | 25 +- sycl/source/CMakeLists.txt | 1 + sycl/source/detail/config.def | 1 + sycl/source/detail/config.hpp | 10 + sycl/source/detail/context_impl.cpp | 5 + sycl/source/detail/context_impl.hpp | 9 + sycl/source/detail/resource_pool.cpp | 101 +++++++ sycl/source/detail/sycl_mem_obj_t.cpp | 14 + sycl/source/handler.cpp | 8 + sycl/test/abi/sycl_symbols_linux.dump | 12 + 16 files changed, 499 insertions(+), 10 deletions(-) create mode 100644 sycl/include/CL/sycl/detail/resource_pool.hpp create mode 100644 sycl/source/detail/resource_pool.cpp diff --git a/sycl/doc/EnvironmentVariables.md b/sycl/doc/EnvironmentVariables.md index 6b356ae858f20..abaab69a24f4e 100644 --- a/sycl/doc/EnvironmentVariables.md +++ b/sycl/doc/EnvironmentVariables.md @@ -11,6 +11,7 @@ compiler and runtime. | `SYCL_DEVICE_TYPE` (deprecated) | CPU, GPU, ACC, HOST | Force SYCL to use the specified device type. If unset, default selection rules are applied. If set to any unlisted value, this control has no effect. If the requested device type is not found, a `cl::sycl::runtime_error` exception is thrown. If a non-default device selector is used, a device must satisfy both the selector and this control to be chosen. This control only has effect on devices created with a selector. We are planning to deprecate `SYCL_DEVICE_TYPE` environment variable in the future. The specific grace period is not decided yet. Please use the new env var `SYCL_DEVICE_FILTER` instead. | | `SYCL_DEVICE_FILTER` | `backend:device_type:device_num` | See Section [`SYCL_DEVICE_FILTER`](#sycl_device_filter) below. | | `SYCL_DEVICE_ALLOWLIST` | See [below](#sycl_device_allowlist) | Filter out devices that do not match the pattern specified. `BackendName` accepts `host`, `opencl`, `level_zero` or `cuda`. `DeviceType` accepts `host`, `cpu`, `gpu` or `acc`. `DeviceVendorId` accepts uint32_t in hex form (`0xXYZW`). `DriverVersion`, `PlatformVersion`, `DeviceName` and `PlatformName` accept regular expression. Special characters, such as parenthesis, must be escaped. DPC++ runtime will select only those devices which satisfy provided values above and regex. More than one device can be specified using the piping symbol "\|".| +| `SYCL_DISABLE_AUXILIARY_RESOURCE_POOL` | Any(\*) | Disables the auxiliary resource pool, preventing the reuse of device resources by operations like reductions. | | `SYCL_DISABLE_PARALLEL_FOR_RANGE_ROUNDING` | Any(\*) | Disables automatic rounding-up of `parallel_for` invocation ranges. | | `SYCL_CACHE_DIR` | Path | Path to persistent cache root directory. Default values are `%AppData%\libsycl_cache` for Windows and `$XDG_CACHE_HOME/libsycl_cache` on Linux, if `XDG_CACHE_HOME` is not set then `$HOME/.cache/libsycl_cache`. When none of the environment variables are set SYCL persistent cache is disabled. | | `SYCL_CACHE_DISABLE_PERSISTENT (deprecated)` | Any(\*) | Has no effect. | diff --git a/sycl/include/CL/sycl/buffer.hpp b/sycl/include/CL/sycl/buffer.hpp index 52a2cdf8b75c7..24f96d7c8097e 100644 --- a/sycl/include/CL/sycl/buffer.hpp +++ b/sycl/include/CL/sycl/buffer.hpp @@ -24,6 +24,8 @@ class queue; template class range; namespace detail { +template struct ManagedResource; + template buffer make_buffer_helper(pi_native_handle Handle, const context &Ctx, event Evt) { @@ -511,6 +513,9 @@ class buffer { template friend buffer detail::make_buffer_helper(pi_native_handle, const context &, event); + template + friend struct detail::ManagedResource; + range Range; // Offset field specifies the origin of the sub buffer inside the parent // buffer diff --git a/sycl/include/CL/sycl/detail/buffer_impl.hpp b/sycl/include/CL/sycl/detail/buffer_impl.hpp index 09595d31bae52..8f71b435bdd13 100644 --- a/sycl/include/CL/sycl/detail/buffer_impl.hpp +++ b/sycl/include/CL/sycl/detail/buffer_impl.hpp @@ -153,6 +153,13 @@ class __SYCL_EXPORT buffer_impl final : public SYCLMemObjT { : BaseT(MemObject, SyclContext, SizeInBytes, std::move(AvailableEvent), std::move(Allocator)) {} + buffer_impl(RT::PiMem MemObject, const context &SyclContext, + const size_t SizeInBytes, + std::unique_ptr Allocator, + event AvailableEvent) + : BaseT(MemObject, SyclContext, SizeInBytes, std::move(AvailableEvent), + std::move(Allocator)) {} + void *allocateMem(ContextImplPtr Context, bool InitFromUserData, void *HostPtr, RT::PiEvent &OutEventToWait) override; void constructorNotification(const detail::code_location &CodeLoc, diff --git a/sycl/include/CL/sycl/detail/resource_pool.hpp b/sycl/include/CL/sycl/detail/resource_pool.hpp new file mode 100644 index 0000000000000..07cfaae90d702 --- /dev/null +++ b/sycl/include/CL/sycl/detail/resource_pool.hpp @@ -0,0 +1,269 @@ +//==------------- resource_pool.hpp - USM resource pool ---------*- 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 +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include +#include + +#include +#include +#include +#include + +__SYCL_INLINE_NAMESPACE(cl) { +namespace sycl { +namespace detail { + +// Forward declarations +class context_impl; +class queue_impl; +class device_impl; +class platform_impl; +class ResourcePool; + +struct __SYCL_EXPORT ManagedResourceBase { + ManagedResourceBase() = delete; + ~ManagedResourceBase(); + +protected: + ManagedResourceBase(size_t Size, RT::PiMem Mem, ResourcePool *Origin) + : MSize(Size), MMem(Mem), MOrigin(Origin) {} + + /// Size of the memory in the managed resource. + size_t MSize; + + /// Memory associated with the managed resource. + RT::PiMem MMem; + + /// The resource pool the resource was taken from. + ResourcePool *MOrigin; + + friend class ResourcePool; +}; + +template +struct ManagedResource : public ManagedResourceBase { + ManagedResource() = delete; + + /// Gets the buffer associated with the resource. + /// + /// \return the buffer associated with the resource. + buffer &getBuffer() { return MBuffer; } + +private: + /// Creates a buffer implementation. + /// + /// \param Size is the size of the memory passed to the buffer. + /// \param Mem is the memory for the buffer. + /// \param ContextImplPtr is the context implementation the memory is + /// associated with. + /// \param AvailableEvent is an event tied to the availability of the data in + /// the memory. + /// \return a shared pointer to the resulting buffer implementation. + static std::shared_ptr + createBufferImpl(size_t Size, RT::PiMem Mem, + const std::shared_ptr &ContextImplPtr, + event AvailableEvent) { + return std::make_shared( + Mem, createSyclObjFromImpl(ContextImplPtr), Size, + make_unique_ptr>(), + AvailableEvent); + } + + ManagedResource(size_t Size, RT::PiMem Mem, ResourcePool *Origin, + range Range, + const std::shared_ptr &ContextImplPtr, + event AvailableEvent = event{}) + : ManagedResourceBase(Size, Mem, Origin), + MBuffer(createBufferImpl(Size, Mem, ContextImplPtr, AvailableEvent), + Range, 0, + /*IsSubBuffer=*/false) {} + + // Constructor for when pool is disabled. + ManagedResource(ResourcePool *Origin, range Range, T *DataPtr) + : ManagedResourceBase(0, nullptr, Origin), MBuffer(DataPtr, Range) {} + + /// Buffer owned by the resource. + buffer MBuffer; + + friend class ResourcePool; +}; + +class __SYCL_EXPORT ResourcePool { +private: + /// Free entry in the resource pool. This represents an allocation owned by + /// the pool that is not currently in use. + struct FreeEntry { + /// Byte size of the free entry. + size_t Size; + /// Memory allocation of the free entry. + RT::PiMem Mem; + }; + + /// Comparison of free entries by size. This is used for fast lookup by size + /// in the pool. + struct FreeEntryCompare { + using is_transparent = void; + bool operator()(FreeEntry const &lhs, FreeEntry const &rhs) const { + return lhs.Size < rhs.Size; + } + bool operator()(FreeEntry const &lhs, size_t rhs) const { + return lhs.Size < rhs; + } + bool operator()(size_t lhs, FreeEntry const &rhs) const { + return lhs < rhs.Size; + } + }; + + /// Extracts a free entry from the pool that fits the size required. If there + /// is no suitable entry, new memory will be allocated. + /// + /// \param Range is the range of the resulting buffer. + /// \param ContextImplPtr is the context to allocate memory in. + /// \param DataPtr is the pointer to data on the host to initialize the + /// associated memory with. This will only be used if a new entry is + /// allocated. + /// \param IsNewEntry will be set to true if the entry was newly allocated in + /// the pool and false if it was found in the existing free entries in + /// the pool. This is not set if it is nullptr. + /// \return a shared pointer to the new managed resource. + FreeEntry + getOrAllocateEntry(const size_t Size, + const std::shared_ptr &ContextImplPtr, + void *DataPtr = nullptr, bool *IsNewEntry = nullptr); + + /// Extracts a free entry from the pool that fits the size required. If there + /// is no suitable entry, new memory will be allocated. The memory will be + /// initialized with the data given. + /// + /// \param Size is the size of the free entry to find or allocate. + /// \param QueueImplPtr is the queue with the context to allocate memory in. + /// \param DataPtr is the pointer to data on the host to initialize the + /// associated memory with. + /// \param AvailableEvent will be set to an event that is tied to the + /// initialization of the memory. + /// \param IsNewEntry will be set to true if the entry was newly allocated in + /// the pool and false if it was found in the existing free entries in + /// the pool. This is not set if it is nullptr. + /// \return a shared pointer to the new managed resource. + FreeEntry getOrAllocateEntry(const size_t Size, + const std::shared_ptr &QueueImplPtr, + void *DataPtr, event *AvailableEvent, + bool *IsNewEntry = nullptr); + + /// Gets the context implementation associtated with a queue implementation. + /// + /// \param QueueImplPtr is the queue implementation to get the context + /// implementation from. \return the context implementation from the queue + /// implementation. + static const std::shared_ptr & + getQueueContextImpl(const std::shared_ptr &QueueImplPtr); + + using ContextPtr = context_impl *; + +public: + /// Removes and deallocates all free entries currently in the pool. + void clear(); + + ResourcePool(); + ResourcePool(const ResourcePool &) = delete; + ~ResourcePool() { + clear(); + assert(MAllocCount == 0 && "Not all resources have returned to the pool."); + } + + /// Sets the platform of the resource pool. + void setPlatform(const std::shared_ptr &Platform) { + assert(MPlatform == nullptr && "Platform of pool has already been set."); + MPlatform = Platform; + } + + /// Creates a managed resource from the pool. + /// + /// \param Range is the range of the resulting buffer. + /// \param ContextImplPtr is the context to allocate memory in. + /// \return a shared pointer to the new managed resource. + template + std::shared_ptr> + getOrAllocateResource(range Range, + const std::shared_ptr &ContextImplPtr) { + // If pool is disabled we return a buffer that will not return to the pool. + if (!MIsPoolingEnabled) + return std::shared_ptr>{ + new ManagedResource(this, Range, nullptr)}; + + // Get or allocate a free entry that fits the requirements. + FreeEntry Entry = + getOrAllocateEntry(Range.size() * sizeof(T), ContextImplPtr); + return std::shared_ptr>{ + new ManagedResource(Entry.Size, Entry.Mem, this, Range, + ContextImplPtr)}; + } + + /// Creates a managed resource from the pool and sets te data of the + /// associated memory. + /// + /// \param Range is the range of the resulting buffer. + /// \param QueueImplPtr is the queue with the context to allocate memory in. + /// \param DataPtr is the pointer to data on the host to initialize the + /// resource with. This must contain at least the size of Range. + /// \return a shared pointer to the new managed resource. + template + std::shared_ptr> + getOrAllocateResource(range Range, + const std::shared_ptr &QueueImplPtr, + T *DataPtr) { + // If pool is disabled we return a buffer that will not return to the pool. + if (!MIsPoolingEnabled) + return std::shared_ptr>{ + new ManagedResource(this, Range, DataPtr)}; + + // Get or allocate a free entry that fits the requirements. + event AvailableEvent; + FreeEntry Entry = getOrAllocateEntry(Range.size() * sizeof(T), QueueImplPtr, + DataPtr, &AvailableEvent); + return std::shared_ptr>{ + new ManagedResource(Entry.Size, Entry.Mem, this, Range, + getQueueContextImpl(QueueImplPtr), + AvailableEvent)}; + } + +private: + /// Returns a resouce to the pool. + /// + /// \param Size is the size of the resource. + /// \param Mem is the memory of the resource. + void returnResourceToPool(const size_t Size, RT::PiMem Mem) { + std::lock_guard Lock{MMutex}; + MFreeEntries.insert({Size, Mem}); + } + + friend struct ManagedResourceBase; + + /// Is true if the pool is enabled and false otherwise. This is controlled by + /// the SYCL_DISABLE_AUXILIARY_RESOURCE_POOL config. + const bool MIsPoolingEnabled; + + /// The platform associated with the pool. + std::shared_ptr MPlatform; + + /// Counter for allocations done by the pool that are currently alive. This + /// includes managed resources that are currently alive. + size_t MAllocCount = 0; + + /// A set of all free entries in the pool. + std::multiset MFreeEntries; + + /// Mutex protecting access to the pool. + std::mutex MMutex; +}; + +} // namespace detail +} // namespace sycl +} // __SYCL_INLINE_NAMESPACE(cl) diff --git a/sycl/include/CL/sycl/detail/sycl_mem_obj_t.hpp b/sycl/include/CL/sycl/detail/sycl_mem_obj_t.hpp index 09639d011f923..add1145302e65 100644 --- a/sycl/include/CL/sycl/detail/sycl_mem_obj_t.hpp +++ b/sycl/include/CL/sycl/detail/sycl_mem_obj_t.hpp @@ -84,6 +84,10 @@ class __SYCL_EXPORT SYCLMemObjT : public SYCLMemObjI { const size_t SizeInBytes, event AvailableEvent, std::unique_ptr Allocator); + SYCLMemObjT(RT::PiMem MemObject, const context &SyclContext, + const size_t SizeInBytes, event AvailableEvent, + std::unique_ptr Allocator); + SYCLMemObjT(cl_mem MemObject, const context &SyclContext, event AvailableEvent, std::unique_ptr Allocator) diff --git a/sycl/include/CL/sycl/handler.hpp b/sycl/include/CL/sycl/handler.hpp index 341a46ca9679d..5caa620feb5aa 100644 --- a/sycl/include/CL/sycl/handler.hpp +++ b/sycl/include/CL/sycl/handler.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -478,6 +479,42 @@ class __SYCL_EXPORT handler { void addReduction(const std::shared_ptr &ReduObj) { MSharedPtrStorage.push_back(ReduObj); } + + /// Gets the context implementation of the context associated with the + /// handler. + /// + /// \return a reference to the shared pointer pointing to the context + /// implementation of the underlying context. + const std::shared_ptr &getContextImplPtr(); + + /// Gets the resource pool for the context associated with the handler. + /// + /// \return a reference to the resource pool of the underlying context. + detail::ResourcePool &getResourcePool(); + + /// Gets or allocates a new resource from the resource pool. + /// + /// \param Range is the range of the underlying buffer for the resource. + /// \return a shared pointer to the resulting resource. + template + std::shared_ptr> + getOrAllocateResourceFromPool(range Range) { + return getResourcePool().getOrAllocateResource( + Range, getContextImplPtr()); + } + + /// Gets or allocates a new resource from the resource pool and intialize it. + /// + /// \param Range is the range of the underlying buffer for the resource. + /// \param DataPtr is a pointer to the data to initialize the resource with. + /// The data pointed to must be at least the size of range in bytes. + /// \return a shared pointer to the resulting resource. + template + std::shared_ptr> + getOrAllocateResourceFromPool(range Range, T *DataPtr) { + return getResourcePool().getOrAllocateResource(Range, MQueue, + DataPtr); + } ~handler() = default; diff --git a/sycl/include/sycl/ext/oneapi/reduction.hpp b/sycl/include/sycl/ext/oneapi/reduction.hpp index 13e1c312fcc89..fd1fa28652d73 100644 --- a/sycl/include/sycl/ext/oneapi/reduction.hpp +++ b/sycl/include/sycl/ext/oneapi/reduction.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -646,7 +647,7 @@ class reduction_impl : private reduction_impl_base { accessor getReadAccToPreviousPartialReds(handler &CGH) const { CGH.addReduction(MOutBufPtr); - return {*MOutBufPtr, CGH}; + return {MOutBufPtr->getBuffer(), CGH}; } /// Returns user's USM pointer passed to reduction for editing. @@ -672,9 +673,10 @@ class reduction_impl : private reduction_impl_base { template std::enable_if_t getWriteMemForPartialReds(size_t Size, handler &CGH) { - MOutBufPtr = std::make_shared>(range<1>(Size)); + MOutBufPtr = + CGH.getOrAllocateResourceFromPool(range<1>(Size)); CGH.addReduction(MOutBufPtr); - return createHandlerWiredReadWriteAccessor(CGH, *MOutBufPtr); + return createHandlerWiredReadWriteAccessor(CGH, MOutBufPtr->getBuffer()); } /// Returns an accessor accessing the memory that will hold the reduction @@ -690,9 +692,10 @@ class reduction_impl : private reduction_impl_base { } // Create a new output buffer and return an accessor to it. - MOutBufPtr = std::make_shared>(range<1>(Size)); + MOutBufPtr = + CGH.getOrAllocateResourceFromPool(range<1>(Size)); CGH.addReduction(MOutBufPtr); - return createHandlerWiredReadWriteAccessor(CGH, *MOutBufPtr); + return createHandlerWiredReadWriteAccessor(CGH, MOutBufPtr->getBuffer()); } /// If reduction is initialized with read-write accessor, which does not @@ -708,9 +711,10 @@ class reduction_impl : private reduction_impl_base { auto RWReduVal = std::make_shared(MIdentity); CGH.addReduction(RWReduVal); - MOutBufPtr = std::make_shared>(RWReduVal.get(), range<1>(1)); + MOutBufPtr = CGH.getOrAllocateResourceFromPool( + range<1>(1), RWReduVal.get()); CGH.addReduction(MOutBufPtr); - return createHandlerWiredReadWriteAccessor(CGH, *MOutBufPtr); + return createHandlerWiredReadWriteAccessor(CGH, MOutBufPtr->getBuffer()); } accessor(0); CGH.addReduction(CounterMem); - auto CounterBuf = std::make_shared>(CounterMem.get(), 1); + auto CounterBuf = + CGH.getOrAllocateResourceFromPool(range<1>{1}, CounterMem.get()); CGH.addReduction(CounterBuf); - return {*CounterBuf, CGH}; + return {CounterBuf->getBuffer(), CGH}; } bool hasUserDiscardWriteAccessor() { return MDWAcc != nullptr; } @@ -775,7 +780,7 @@ class reduction_impl : private reduction_impl_base { std::shared_ptr MRWAcc; std::shared_ptr MDWAcc; - std::shared_ptr> MOutBufPtr; + std::shared_ptr> MOutBufPtr; /// USM pointer referencing the memory to where the result of the reduction /// must be written. Applicable/used only for USM reductions. diff --git a/sycl/source/CMakeLists.txt b/sycl/source/CMakeLists.txt index b89835c5f4864..a9cb831818988 100644 --- a/sycl/source/CMakeLists.txt +++ b/sycl/source/CMakeLists.txt @@ -157,6 +157,7 @@ set(SYCL_SOURCES "detail/persistent_device_code_cache.cpp" "detail/platform_util.cpp" "detail/reduction.cpp" + "detail/resource_pool.cpp" "detail/sampler_impl.cpp" "detail/stream_impl.cpp" "detail/scheduler/commands.cpp" diff --git a/sycl/source/detail/config.def b/sycl/source/detail/config.def index d0ac3d1c34766..c126911d7e8c8 100644 --- a/sycl/source/detail/config.def +++ b/sycl/source/detail/config.def @@ -17,6 +17,7 @@ CONFIG(SYCL_DEVICE_ALLOWLIST, 1024, __SYCL_DEVICE_ALLOWLIST) CONFIG(SYCL_BE, 16, __SYCL_BE) CONFIG(SYCL_PI_TRACE, 16, __SYCL_PI_TRACE) CONFIG(SYCL_PARALLEL_FOR_RANGE_ROUNDING_TRACE, 16, __SYCL_PARALLEL_FOR_RANGE_ROUNDING_TRACE) +CONFIG(SYCL_DISABLE_AUXILIARY_RESOURCE_POOL, 16, __SYCL_DISABLE_AUXILIARY_RESOURCE_POOL) CONFIG(SYCL_DISABLE_PARALLEL_FOR_RANGE_ROUNDING, 16, __SYCL_DISABLE_PARALLEL_FOR_RANGE_ROUNDING) CONFIG(SYCL_PARALLEL_FOR_RANGE_ROUNDING_PARAMS, 64, __SYCL_PARALLEL_FOR_RANGE_ROUNDING_PARAMS) CONFIG(SYCL_DEVICELIB_NO_FALLBACK, 1, __SYCL_DEVICELIB_NO_FALLBACK) diff --git a/sycl/source/detail/config.hpp b/sycl/source/detail/config.hpp index dd2f767ae098f..8a5c98cd672ca 100644 --- a/sycl/source/detail/config.hpp +++ b/sycl/source/detail/config.hpp @@ -217,6 +217,16 @@ template <> class SYCLConfig { } }; +template <> class SYCLConfig { + using BaseT = SYCLConfigBase; + +public: + static bool get() { + static const char *ValStr = BaseT::getRawValue(); + return ValStr != nullptr; + } +}; + template <> class SYCLConfig { using BaseT = SYCLConfigBase; diff --git a/sycl/source/detail/context_impl.cpp b/sycl/source/detail/context_impl.cpp index 18390606df128..87010fe0474fc 100644 --- a/sycl/source/detail/context_impl.cpp +++ b/sycl/source/detail/context_impl.cpp @@ -30,6 +30,7 @@ context_impl::context_impl(const device &Device, async_handler AsyncHandler, : MAsyncHandler(AsyncHandler), MDevices(1, Device), MContext(nullptr), MPlatform(), MPropList(PropList), MHostContext(Device.is_host()) { MKernelProgramCache.setContextPtr(this); + MAuxiliaryResourcePool.setPlatform(MPlatform); } context_impl::context_impl(const std::vector Devices, @@ -61,6 +62,7 @@ context_impl::context_impl(const std::vector Devices, } MKernelProgramCache.setContextPtr(this); + MAuxiliaryResourcePool.setPlatform(MPlatform); } context_impl::context_impl(RT::PiContext PiContext, async_handler AsyncHandler, @@ -99,6 +101,7 @@ context_impl::context_impl(RT::PiContext PiContext, async_handler AsyncHandler, getPlugin().call(MContext); } MKernelProgramCache.setContextPtr(this); + MAuxiliaryResourcePool.setPlatform(MPlatform); } cl_context context_impl::get() const { @@ -115,6 +118,8 @@ cl_context context_impl::get() const { bool context_impl::is_host() const { return MHostContext; } context_impl::~context_impl() { + // Clear resource pool before releasing the native context + MAuxiliaryResourcePool.clear(); for (auto LibProg : MCachedLibPrograms) { assert(LibProg.second && "Null program must not be kept in the cache"); getPlugin().call(LibProg.second); diff --git a/sycl/source/detail/context_impl.hpp b/sycl/source/detail/context_impl.hpp index d1a52181e9d33..fb775e5fd9a9f 100644 --- a/sycl/source/detail/context_impl.hpp +++ b/sycl/source/detail/context_impl.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -167,6 +168,13 @@ class context_impl { /// \return a native handle. pi_native_handle getNative() const; + /// Gets the resource pool of the SYCL context. + /// + /// \return a reference to the resource pool. + ResourcePool &getResourcePool() { + return MAuxiliaryResourcePool; + } + private: async_handler MAsyncHandler; std::vector MDevices; @@ -177,6 +185,7 @@ class context_impl { std::map, RT::PiProgram> MCachedLibPrograms; mutable KernelProgramCache MKernelProgramCache; + ResourcePool MAuxiliaryResourcePool; }; } // namespace detail diff --git a/sycl/source/detail/resource_pool.cpp b/sycl/source/detail/resource_pool.cpp new file mode 100644 index 0000000000000..9af5feeaaabbc --- /dev/null +++ b/sycl/source/detail/resource_pool.cpp @@ -0,0 +1,101 @@ +//==-------------- resource_pool.cpp - USM resource pool -------------------==// +// +// 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 +#include +#include +#include +#include +#include +#include + +__SYCL_INLINE_NAMESPACE(cl) { +namespace sycl { +namespace detail { + +ManagedResourceBase::~ManagedResourceBase() { + // Only return it to the pool if resource pooling is enabled. + if (MOrigin->MIsPoolingEnabled) + MOrigin->returnResourceToPool(MSize, MMem); +} + +ResourcePool::ResourcePool() + : MIsPoolingEnabled( + !SYCLConfig::get()) {} + +void ResourcePool::clear() { + std::lock_guard Lock{MMutex}; + MAllocCount -= MFreeEntries.size(); + for (auto Entry : MFreeEntries) + memReleaseHelper(MPlatform->getPlugin(), Entry.Mem); + MFreeEntries.clear(); +} + +ResourcePool::FreeEntry ResourcePool::getOrAllocateEntry( + const size_t Size, const std::shared_ptr &ContextImplPtr, + void *DataPtr, bool *IsNewEntry) { + assert(Size && "Size must be greater than 0"); + assert(ContextImplPtr->getPlatformImpl() == MPlatform && + "Context platform does not match the resource pool platform."); + std::lock_guard Lock{MMutex}; + + // Find the free entry with the smallest suitable size. + auto FoundFreeEntry = MFreeEntries.upper_bound(Size - 1); + + // If there was a fitting free entry in the pool, remove and return it. + const bool IsOldEntry = FoundFreeEntry != MFreeEntries.end(); + if (IsNewEntry) + *IsNewEntry = !IsOldEntry; + if (IsOldEntry) { + FreeEntry Entry = *FoundFreeEntry; + MFreeEntries.erase(FoundFreeEntry); + return Entry; + } + + // If there was no suitable free entry we allocate memory and return it in a + // new free entry. + RT::PiMemFlags MemFlags = PI_MEM_FLAGS_ACCESS_RW; + if (DataPtr) + MemFlags |= PI_MEM_FLAGS_HOST_PTR_COPY; + RT::PiMem NewResMem; + memBufferCreateHelper(MPlatform->getPlugin(), ContextImplPtr->getHandleRef(), + MemFlags, Size, DataPtr, &NewResMem, nullptr); + ++MAllocCount; + return {Size, NewResMem}; +} + +ResourcePool::FreeEntry ResourcePool::getOrAllocateEntry( + const size_t Size, const std::shared_ptr &QueueImplPtr, + void *DataPtr, event *AvailableEvent, bool *IsNewEntry) { + ResourcePool::FreeEntry Entry = getOrAllocateEntry( + Size, QueueImplPtr->getContextImplPtr(), DataPtr, IsNewEntry); + + // A new entry will have copied from the host pointer on creation. + if (IsNewEntry) { + *AvailableEvent = event{}; + return Entry; + } + + // If we get old memory we need to copy explicitly. + RT::PiEvent Event; + QueueImplPtr->getPlugin().call( + QueueImplPtr->getHandleRef(), Entry.Mem, + /*blocking_write=*/CL_FALSE, 0, Size, DataPtr, 0, nullptr, &Event); + *AvailableEvent = createSyclObjFromImpl( + std::make_shared(Event, QueueImplPtr->get_context())); + return Entry; +} + +const std::shared_ptr &ResourcePool::getQueueContextImpl( + const std::shared_ptr &QueueImplPtr) { + return QueueImplPtr->getContextImplPtr(); +} + +} // namespace detail +} // namespace sycl +} // __SYCL_INLINE_NAMESPACE(cl) diff --git a/sycl/source/detail/sycl_mem_obj_t.cpp b/sycl/source/detail/sycl_mem_obj_t.cpp index 191a15c0d5b8e..6a2dc9b0d7f59 100644 --- a/sycl/source/detail/sycl_mem_obj_t.cpp +++ b/sycl/source/detail/sycl_mem_obj_t.cpp @@ -51,6 +51,20 @@ SYCLMemObjT::SYCLMemObjT(pi_native_handle MemObject, const context &SyclContext, Plugin.call(Mem); } +// Special internal "interop" constructor. This is used by auxiliary resources. +SYCLMemObjT::SYCLMemObjT(RT::PiMem MemObject, const context &SyclContext, + const size_t SizeInBytes, event AvailableEvent, + std::unique_ptr Allocator) + : MAllocator(std::move(Allocator)), MProps(), + MInteropEvent(detail::getSyclObjImpl(std::move(AvailableEvent))), + MInteropContext(detail::getSyclObjImpl(SyclContext)), + MInteropMemObject(pi::cast(MemObject)), MOpenCLInterop(true), + MHostPtrReadOnly(false), MNeedWriteBack(false), MSizeInBytes(SizeInBytes), + MUserPtr(nullptr), MShadowCopy(nullptr), MUploadDataFunctor(nullptr), + MSharedPtrStorage(nullptr) { + getPlugin().call(MemObject); +} + void SYCLMemObjT::releaseMem(ContextImplPtr Context, void *MemAllocation) { void *Ptr = getUserPtr(); return MemoryManager::releaseMemObj(Context, this, MemAllocation, Ptr); diff --git a/sycl/source/handler.cpp b/sycl/source/handler.cpp index e9a9993ae6ed6..5a3b1458f319d 100644 --- a/sycl/source/handler.cpp +++ b/sycl/source/handler.cpp @@ -790,5 +790,13 @@ void handler::depends_on(const std::vector &Events) { } } +const std::shared_ptr &handler::getContextImplPtr() { + return MQueue->getContextImplPtr(); +} + +detail::ResourcePool &handler::getResourcePool() { + return getContextImplPtr()->getResourcePool(); +} + } // namespace sycl } // __SYCL_INLINE_NAMESPACE(cl) diff --git a/sycl/test/abi/sycl_symbols_linux.dump b/sycl/test/abi/sycl_symbols_linux.dump index 79d58722b4f4f..98c7e515bb214 100644 --- a/sycl/test/abi/sycl_symbols_linux.dump +++ b/sycl/test/abi/sycl_symbols_linux.dump @@ -3828,8 +3828,10 @@ _ZN2cl4sycl6detail11SYCLMemObjT16updateHostMemoryEv _ZN2cl4sycl6detail11SYCLMemObjT20getBufSizeForContextERKSt10shared_ptrINS1_12context_implEEP7_cl_mem _ZN2cl4sycl6detail11SYCLMemObjT20getBufSizeForContextERKSt10shared_ptrINS1_12context_implEEm _ZN2cl4sycl6detail11SYCLMemObjTC1EP7_cl_memRKNS0_7contextEmNS0_5eventESt10unique_ptrINS1_19SYCLMemObjAllocatorESt14default_deleteISA_EE +_ZN2cl4sycl6detail11SYCLMemObjTC1EP7_pi_memRKNS0_7contextEmNS0_5eventESt10unique_ptrINS1_19SYCLMemObjAllocatorESt14default_deleteISA_EE _ZN2cl4sycl6detail11SYCLMemObjTC1EmRKNS0_7contextEmNS0_5eventESt10unique_ptrINS1_19SYCLMemObjAllocatorESt14default_deleteIS8_EE _ZN2cl4sycl6detail11SYCLMemObjTC2EP7_cl_memRKNS0_7contextEmNS0_5eventESt10unique_ptrINS1_19SYCLMemObjAllocatorESt14default_deleteISA_EE +_ZN2cl4sycl6detail11SYCLMemObjTC2EP7_pi_memRKNS0_7contextEmNS0_5eventESt10unique_ptrINS1_19SYCLMemObjAllocatorESt14default_deleteISA_EE _ZN2cl4sycl6detail11SYCLMemObjTC2EmRKNS0_7contextEmNS0_5eventESt10unique_ptrINS1_19SYCLMemObjAllocatorESt14default_deleteIS8_EE _ZN2cl4sycl6detail11buffer_impl11allocateMemESt10shared_ptrINS1_12context_implEEbPvRP9_pi_event _ZN2cl4sycl6detail11buffer_impl22destructorNotificationEPv @@ -3846,6 +3848,12 @@ _ZN2cl4sycl6detail11stream_implC1EmmRKNS0_13property_listE _ZN2cl4sycl6detail11stream_implC1EmmRNS0_7handlerE _ZN2cl4sycl6detail11stream_implC2EmmRKNS0_13property_listE _ZN2cl4sycl6detail11stream_implC2EmmRNS0_7handlerE +_ZN2cl4sycl6detail12ResourcePool18getOrAllocateEntryEmRKSt10shared_ptrINS1_10queue_implEEPvPNS0_5eventEPb +_ZN2cl4sycl6detail12ResourcePool18getOrAllocateEntryEmRKSt10shared_ptrINS1_12context_implEEPvPb +_ZN2cl4sycl6detail12ResourcePool19getQueueContextImplERKSt10shared_ptrINS1_10queue_implEE +_ZN2cl4sycl6detail12ResourcePool5clearEv +_ZN2cl4sycl6detail12ResourcePoolC1Ev +_ZN2cl4sycl6detail12ResourcePoolC2Ev _ZN2cl4sycl6detail12compile_implERKNS0_13kernel_bundleILNS0_12bundle_stateE0EEERKSt6vectorINS0_6deviceESaIS8_EERKNS0_13property_listE _ZN2cl4sycl6detail12isOutOfRangeENS0_3vecIiLi4EEENS0_15addressing_modeENS0_5rangeILi3EEE _ZN2cl4sycl6detail12make_contextEmRKSt8functionIFvNS0_14exception_listEEENS0_7backendE @@ -3901,6 +3909,8 @@ _ZN2cl4sycl6detail18get_kernel_id_implENSt7__cxx1112basic_stringIcSt11char_trait _ZN2cl4sycl6detail18make_kernel_bundleEmRKNS0_7contextENS0_12bundle_stateENS0_7backendE _ZN2cl4sycl6detail18make_kernel_bundleEmRKNS0_7contextEbNS0_12bundle_stateENS0_7backendE _ZN2cl4sycl6detail18stringifyErrorCodeEi +_ZN2cl4sycl6detail19ManagedResourceBaseD1Ev +_ZN2cl4sycl6detail19ManagedResourceBaseD2Ev _ZN2cl4sycl6detail19convertChannelOrderE23_pi_image_channel_order _ZN2cl4sycl6detail19convertChannelOrderENS0_19image_channel_orderE _ZN2cl4sycl6detail19getImageElementSizeEhNS0_18image_channel_typeE @@ -3995,6 +4005,8 @@ _ZN2cl4sycl7handler10mem_adviseEPKvmi _ZN2cl4sycl7handler10processArgEPvRKNS0_6detail19kernel_param_kind_tEimRmb _ZN2cl4sycl7handler10processArgEPvRKNS0_6detail19kernel_param_kind_tEimRmbb _ZN2cl4sycl7handler13getKernelNameB5cxx11Ev +_ZN2cl4sycl7handler15getResourcePoolEv +_ZN2cl4sycl7handler17getContextImplPtrEv _ZN2cl4sycl7handler17use_kernel_bundleERKNS0_13kernel_bundleILNS0_12bundle_stateE2EEE _ZN2cl4sycl7handler18RangeRoundingTraceEv _ZN2cl4sycl7handler18ext_oneapi_barrierERKSt6vectorINS0_5eventESaIS3_EE From 7c2f4002556494d65d884825dbd3c4e23d7f9707 Mon Sep 17 00:00:00 2001 From: Steffen Larsen Date: Fri, 25 Feb 2022 01:02:00 +0300 Subject: [PATCH 02/14] Add missing Windows symbols Signed-off-by: Steffen Larsen --- sycl/test/abi/sycl_symbols_windows.dump | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sycl/test/abi/sycl_symbols_windows.dump b/sycl/test/abi/sycl_symbols_windows.dump index e6bb784eca0d8..e3262e533d870 100644 --- a/sycl/test/abi/sycl_symbols_windows.dump +++ b/sycl/test/abi/sycl_symbols_windows.dump @@ -295,16 +295,20 @@ ??0LocalAccessorImplHost@detail@sycl@cl@@QEAA@$$QEAV0123@@Z ??0LocalAccessorImplHost@detail@sycl@cl@@QEAA@AEBV0123@@Z ??0LocalAccessorImplHost@detail@sycl@cl@@QEAA@V?$range@$02@23@HH@Z +??0ManagedResourceBase@detail@sycl@cl@@IEAA@_KPEAU_pi_mem@@PEAVResourcePool@123@@Z +??0ResourcePool@detail@sycl@cl@@QEAA@XZ ??0SYCLCategory@detail@sycl@cl@@QEAA@XZ ??0SYCLMemObjT@detail@sycl@cl@@QEAA@AEBVproperty_list@23@V?$unique_ptr@VSYCLMemObjAllocator@detail@sycl@cl@@U?$default_delete@VSYCLMemObjAllocator@detail@sycl@cl@@@std@@@std@@@Z ??0SYCLMemObjT@detail@sycl@cl@@QEAA@PEAU_cl_mem@@AEBVcontext@23@Vevent@23@V?$unique_ptr@VSYCLMemObjAllocator@detail@sycl@cl@@U?$default_delete@VSYCLMemObjAllocator@detail@sycl@cl@@@std@@@std@@@Z ??0SYCLMemObjT@detail@sycl@cl@@QEAA@PEAU_cl_mem@@AEBVcontext@23@_KVevent@23@V?$unique_ptr@VSYCLMemObjAllocator@detail@sycl@cl@@U?$default_delete@VSYCLMemObjAllocator@detail@sycl@cl@@@std@@@std@@@Z +??0SYCLMemObjT@detail@sycl@cl@@QEAA@PEAU_pi_mem@@AEBVcontext@23@_KVevent@23@V?$unique_ptr@VSYCLMemObjAllocator@detail@sycl@cl@@U?$default_delete@VSYCLMemObjAllocator@detail@sycl@cl@@@std@@@std@@@Z ??0SYCLMemObjT@detail@sycl@cl@@QEAA@_KAEBVcontext@23@_KVevent@23@V?$unique_ptr@VSYCLMemObjAllocator@detail@sycl@cl@@U?$default_delete@VSYCLMemObjAllocator@detail@sycl@cl@@@std@@@std@@@Z ??0SYCLMemObjT@detail@sycl@cl@@QEAA@_KAEBVproperty_list@23@V?$unique_ptr@VSYCLMemObjAllocator@detail@sycl@cl@@U?$default_delete@VSYCLMemObjAllocator@detail@sycl@cl@@@std@@@std@@@Z ??0accelerator_selector@sycl@cl@@QEAA@$$QEAV012@@Z ??0accelerator_selector@sycl@cl@@QEAA@AEBV012@@Z ??0accelerator_selector@sycl@cl@@QEAA@XZ ??0buffer_impl@detail@sycl@cl@@QEAA@PEAU_cl_mem@@AEBVcontext@23@_KV?$unique_ptr@VSYCLMemObjAllocator@detail@sycl@cl@@U?$default_delete@VSYCLMemObjAllocator@detail@sycl@cl@@@std@@@std@@Vevent@23@@Z +??0buffer_impl@detail@sycl@cl@@QEAA@PEAU_pi_mem@@AEBVcontext@23@_KV?$unique_ptr@VSYCLMemObjAllocator@detail@sycl@cl@@U?$default_delete@VSYCLMemObjAllocator@detail@sycl@cl@@@std@@@std@@Vevent@23@@Z ??0buffer_impl@detail@sycl@cl@@QEAA@PEAX_K1AEBVproperty_list@23@V?$unique_ptr@VSYCLMemObjAllocator@detail@sycl@cl@@U?$default_delete@VSYCLMemObjAllocator@detail@sycl@cl@@@std@@@std@@@Z ??0buffer_impl@detail@sycl@cl@@QEAA@PEBX_K1AEBVproperty_list@23@V?$unique_ptr@VSYCLMemObjAllocator@detail@sycl@cl@@U?$default_delete@VSYCLMemObjAllocator@detail@sycl@cl@@@std@@@std@@@Z ??0buffer_impl@detail@sycl@cl@@QEAA@_K0AEBVproperty_list@23@V?$unique_ptr@VSYCLMemObjAllocator@detail@sycl@cl@@U?$default_delete@VSYCLMemObjAllocator@detail@sycl@cl@@@std@@@std@@@Z @@ -447,6 +451,8 @@ ??1?$image_impl@$02@detail@sycl@cl@@UEAA@XZ ??1AccessorImplHost@detail@sycl@cl@@QEAA@XZ ??1LocalAccessorImplHost@detail@sycl@cl@@QEAA@XZ +??1ManagedResourceBase@detail@sycl@cl@@QEAA@XZ +??1ResourcePool@detail@sycl@cl@@QEAA@XZ ??1SYCLCategory@detail@sycl@cl@@UEAA@XZ ??1SYCLMemObjT@detail@sycl@cl@@UEAA@XZ ??1accelerator_selector@sycl@cl@@UEAA@XZ @@ -480,6 +486,7 @@ ??4HostProfilingInfo@detail@sycl@cl@@QEAAAEAV0123@AEBV0123@@Z ??4LocalAccessorImplHost@detail@sycl@cl@@QEAAAEAV0123@$$QEAV0123@@Z ??4LocalAccessorImplHost@detail@sycl@cl@@QEAAAEAV0123@AEBV0123@@Z +??4ManagedResourceBase@detail@sycl@cl@@QEAAAEAU0123@AEBU0123@@Z ??4MemoryManager@detail@sycl@cl@@QEAAAEAV0123@$$QEAV0123@@Z ??4MemoryManager@detail@sycl@cl@@QEAAAEAV0123@AEBV0123@@Z ??4OSUtil@detail@sycl@cl@@QEAAAEAV0123@$$QEAV0123@@Z @@ -1447,6 +1454,7 @@ ?checkImageFormat@?$image_impl@$00@detail@sycl@cl@@AEAA_NAEBU_pi_image_format@@V?$shared_ptr@Vcontext_impl@detail@sycl@cl@@@std@@@Z ?checkImageFormat@?$image_impl@$01@detail@sycl@cl@@AEAA_NAEBU_pi_image_format@@V?$shared_ptr@Vcontext_impl@detail@sycl@cl@@@std@@@Z ?checkImageFormat@?$image_impl@$02@detail@sycl@cl@@AEAA_NAEBU_pi_image_format@@V?$shared_ptr@Vcontext_impl@detail@sycl@cl@@@std@@@Z +?clear@ResourcePool@detail@sycl@cl@@QEAAXXZ ?clz@__host_std@cl@@YA?AV?$vec@C$00@sycl@2@V342@@Z ?clz@__host_std@cl@@YA?AV?$vec@C$01@sycl@2@V342@@Z ?clz@__host_std@cl@@YA?AV?$vec@C$02@sycl@2@V342@@Z @@ -2141,6 +2149,7 @@ ?getChannelType@?$image_impl@$00@detail@sycl@cl@@QEBA?AW4image_channel_type@34@XZ ?getChannelType@?$image_impl@$01@detail@sycl@cl@@QEBA?AW4image_channel_type@34@XZ ?getChannelType@?$image_impl@$02@detail@sycl@cl@@QEBA?AW4image_channel_type@34@XZ +?getContextImplPtr@handler@sycl@cl@@AEAAAEBV?$shared_ptr@Vcontext_impl@detail@sycl@cl@@@std@@XZ ?getCurrentDSODir@OSUtil@detail@sycl@cl@@SA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ ?getDelinearizedIndex@handler@sycl@cl@@CA?AV?$id@$00@23@V?$range@$00@23@_K@Z ?getDelinearizedIndex@handler@sycl@cl@@CA?AV?$id@$01@23@V?$range@$01@23@_K@Z @@ -2186,12 +2195,16 @@ ?getNativeVector@event@sycl@cl@@AEBA?AV?$vector@_KV?$allocator@_K@std@@@std@@XZ ?getOSMemSize@OSUtil@detail@sycl@cl@@SA_KXZ ?getOSModuleHandle@OSUtil@detail@sycl@cl@@SA_JPEBX@Z +?getOrAllocateEntry@ResourcePool@detail@sycl@cl@@AEAA?AUFreeEntry@1234@_KAEBV?$shared_ptr@Vcontext_impl@detail@sycl@cl@@@std@@PEAXPEA_N@Z +?getOrAllocateEntry@ResourcePool@detail@sycl@cl@@AEAA?AUFreeEntry@1234@_KAEBV?$shared_ptr@Vqueue_impl@detail@sycl@cl@@@std@@PEAXPEAVevent@34@PEA_N@Z ?getOrCreateSampler@sampler_impl@detail@sycl@cl@@QEAAPEAU_pi_sampler@@AEBVcontext@34@@Z ?getOrInsertHandlerKernelBundle@handler@sycl@cl@@AEBA?AV?$shared_ptr@Vkernel_bundle_impl@detail@sycl@cl@@@std@@_N@Z ?getOrWaitEvents@detail@sycl@cl@@YA?AV?$vector@PEAU_pi_event@@V?$allocator@PEAU_pi_event@@@std@@@std@@V?$vector@Vevent@sycl@cl@@V?$allocator@Vevent@sycl@cl@@@std@@@5@V?$shared_ptr@Vcontext_impl@detail@sycl@cl@@@5@@Z ?getPixelCoordLinearFiltMode@detail@sycl@cl@@YA?AV?$vec@H$07@23@V?$vec@M$03@23@W4addressing_mode@23@V?$range@$02@23@AEAV523@@Z ?getPixelCoordNearestFiltMode@detail@sycl@cl@@YA?AV?$vec@H$03@23@V?$vec@M$03@23@W4addressing_mode@23@V?$range@$02@23@@Z ?getPlugin@SYCLMemObjT@detail@sycl@cl@@QEBAAEBVplugin@234@XZ +?getQueueContextImpl@ResourcePool@detail@sycl@cl@@CAAEBV?$shared_ptr@Vcontext_impl@detail@sycl@cl@@@std@@AEBV?$shared_ptr@Vqueue_impl@detail@sycl@cl@@@6@@Z +?getResourcePool@handler@sycl@cl@@AEAAAEAVResourcePool@detail@23@XZ ?getRowPitch@?$image_impl@$00@detail@sycl@cl@@QEBA_KXZ ?getRowPitch@?$image_impl@$01@detail@sycl@cl@@QEBA_KXZ ?getRowPitch@?$image_impl@$02@detail@sycl@cl@@QEBA_KXZ @@ -3189,6 +3202,7 @@ ?reset@filter_selector@oneapi@ext@sycl@cl@@QEBAXXZ ?resize@AccessorImplHost@detail@sycl@cl@@QEAAX_K@Z ?resize@buffer_impl@detail@sycl@cl@@QEAAX_K@Z +?returnResourceToPool@ResourcePool@detail@sycl@cl@@AEAAX_KPEAU_pi_mem@@@Z ?rint@__host_std@cl@@YA?AV?$vec@M$00@sycl@2@V342@@Z ?rint@__host_std@cl@@YA?AV?$vec@M$01@sycl@2@V342@@Z ?rint@__host_std@cl@@YA?AV?$vec@M$02@sycl@2@V342@@Z @@ -3937,6 +3951,7 @@ ?setPitches@?$image_impl@$00@detail@sycl@cl@@AEAAXXZ ?setPitches@?$image_impl@$01@detail@sycl@cl@@AEAAXXZ ?setPitches@?$image_impl@$02@detail@sycl@cl@@AEAAXXZ +?setPlatform@ResourcePool@detail@sycl@cl@@QEAAXAEBV?$shared_ptr@Vplatform_impl@detail@sycl@cl@@@std@@@Z ?setStateExplicitKernelBundle@handler@sycl@cl@@AEAAXXZ ?setStateSpecConstSet@handler@sycl@cl@@AEAAXXZ ?setType@handler@sycl@cl@@AEAAXW4CGTYPE@CG@detail@23@@Z From 255b422f013bdee1a3bc08ed80c1497c05fc0d8c Mon Sep 17 00:00:00 2001 From: Steffen Larsen Date: Tue, 8 Mar 2022 13:39:00 +0300 Subject: [PATCH 03/14] Clear resource pool when running out of memory Signed-off-by: Steffen Larsen --- sycl/include/CL/sycl/detail/resource_pool.hpp | 5 + sycl/source/detail/device_image_impl.hpp | 4 +- sycl/source/detail/mem_alloc_helper.hpp | 4 +- sycl/source/detail/memory_manager.cpp | 36 ++++++-- sycl/source/detail/resource_pool.cpp | 28 +++--- sycl/source/detail/usm/usm_impl.cpp | 91 ++++++++++++++----- 6 files changed, 120 insertions(+), 48 deletions(-) diff --git a/sycl/include/CL/sycl/detail/resource_pool.hpp b/sycl/include/CL/sycl/detail/resource_pool.hpp index 07cfaae90d702..a84ace835deff 100644 --- a/sycl/include/CL/sycl/detail/resource_pool.hpp +++ b/sycl/include/CL/sycl/detail/resource_pool.hpp @@ -184,6 +184,11 @@ class __SYCL_EXPORT ResourcePool { MPlatform = Platform; } + /// Returns true if the resource pool is enabled and false otherwise. + /// + /// \return a boolean value specifying whether the pool is enabled. + bool isEnabled() { return MIsPoolingEnabled; } + /// Creates a managed resource from the pool. /// /// \param Range is the range of the resulting buffer. diff --git a/sycl/source/detail/device_image_impl.hpp b/sycl/source/detail/device_image_impl.hpp index 4886c5c8ae25a..c08492a09d833 100644 --- a/sycl/source/detail/device_image_impl.hpp +++ b/sycl/source/detail/device_image_impl.hpp @@ -194,14 +194,12 @@ class device_image_impl { RT::PiMem &get_spec_const_buffer_ref() noexcept { std::lock_guard Lock{MSpecConstAccessMtx}; if (nullptr == MSpecConstsBuffer && !MSpecConstsBlob.empty()) { - const detail::plugin &Plugin = getSyclObjImpl(MContext)->getPlugin(); // Uses PI_MEM_FLAGS_HOST_PTR_COPY instead of PI_MEM_FLAGS_HOST_PTR_USE // since post-enqueue cleanup might trigger destruction of // device_image_impl and, as a result, destruction of MSpecConstsBlob // while MSpecConstsBuffer is still in use. // TODO consider changing the lifetime of device_image_impl instead - memBufferCreateHelper(Plugin, - detail::getSyclObjImpl(MContext)->getHandleRef(), + memBufferCreateHelper(detail::getSyclObjImpl(MContext), PI_MEM_FLAGS_ACCESS_RW | PI_MEM_FLAGS_HOST_PTR_COPY, MSpecConstsBlob.size(), MSpecConstsBlob.data(), &MSpecConstsBuffer, nullptr); diff --git a/sycl/source/detail/mem_alloc_helper.hpp b/sycl/source/detail/mem_alloc_helper.hpp index 0cbc8c4bada86..d8a876c7f76cf 100644 --- a/sycl/source/detail/mem_alloc_helper.hpp +++ b/sycl/source/detail/mem_alloc_helper.hpp @@ -13,7 +13,9 @@ __SYCL_INLINE_NAMESPACE(cl) { namespace sycl { namespace detail { -void memBufferCreateHelper(const plugin &Plugin, pi_context Ctx, +class context_impl; + +void memBufferCreateHelper(std::shared_ptr CtxImpl, pi_mem_flags Flags, size_t Size, void *HostPtr, pi_mem *RetMem, const pi_mem_properties *Props = nullptr); diff --git a/sycl/source/detail/memory_manager.cpp b/sycl/source/detail/memory_manager.cpp index 1cd77083e0c16..f6f433ed1927a 100644 --- a/sycl/source/detail/memory_manager.cpp +++ b/sycl/source/detail/memory_manager.cpp @@ -124,9 +124,11 @@ static void waitForEvents(const std::vector &Events) { } } -void memBufferCreateHelper(const plugin &Plugin, pi_context Ctx, - pi_mem_flags Flags, size_t Size, void *HostPtr, - pi_mem *RetMem, const pi_mem_properties *Props) { +static pi_result memBufferCreateNocheckHelper(const plugin &Plugin, + pi_context Ctx, + pi_mem_flags Flags, size_t Size, + void *HostPtr, pi_mem *RetMem, + const pi_mem_properties *Props) { #ifdef XPTI_ENABLE_INSTRUMENTATION uint64_t CorrID = 0; #endif @@ -147,11 +149,30 @@ void memBufferCreateHelper(const plugin &Plugin, pi_context Ctx, CorrID); }}; #endif - Plugin.call(Ctx, Flags, Size, HostPtr, RetMem, - Props); + return Plugin.call_nocheck( + Ctx, Flags, Size, HostPtr, RetMem, Props); } } +void memBufferCreateHelper(std::shared_ptr CtxImpl, + pi_mem_flags Flags, size_t Size, void *HostPtr, + pi_mem *RetMem, const pi_mem_properties *Props) { + const detail::plugin &Plugin = CtxImpl->getPlugin(); + RT::PiResult Err = memBufferCreateNocheckHelper( + Plugin, CtxImpl->getHandleRef(), Flags, Size, HostPtr, RetMem, Props); + + ResourcePool &Resources = CtxImpl->getResourcePool(); + if (Err == PI_MEM_OBJECT_ALLOCATION_FAILURE && Resources.isEnabled()) { + // Clear resource pool and retry allocation. + Resources.clear(); + Err = memBufferCreateNocheckHelper(Plugin, CtxImpl->getHandleRef(), Flags, + Size, HostPtr, RetMem, Props); + } + + if (Err != PI_SUCCESS) + Plugin.reportPiError(Err, "memBufferCreateHelper()"); +} + void memReleaseHelper(const plugin &Plugin, pi_mem Mem) { // FIXME piMemRelease does not guarante memory release. It is only true if // reference counter is 1. However, SYCL runtime currently only calls @@ -361,9 +382,8 @@ MemoryManager::allocateBufferObject(ContextImplPtr TargetContext, void *UserPtr, CreationFlags |= PI_MEM_FLAGS_HOST_PTR_ALLOC; RT::PiMem NewMem = nullptr; - const detail::plugin &Plugin = TargetContext->getPlugin(); - memBufferCreateHelper(Plugin, TargetContext->getHandleRef(), CreationFlags, - Size, UserPtr, &NewMem, nullptr); + memBufferCreateHelper(TargetContext, CreationFlags, Size, UserPtr, &NewMem, + nullptr); return NewMem; } diff --git a/sycl/source/detail/resource_pool.cpp b/sycl/source/detail/resource_pool.cpp index 9af5feeaaabbc..8edf10b15ec65 100644 --- a/sycl/source/detail/resource_pool.cpp +++ b/sycl/source/detail/resource_pool.cpp @@ -42,19 +42,21 @@ ResourcePool::FreeEntry ResourcePool::getOrAllocateEntry( assert(Size && "Size must be greater than 0"); assert(ContextImplPtr->getPlatformImpl() == MPlatform && "Context platform does not match the resource pool platform."); - std::lock_guard Lock{MMutex}; + { + std::lock_guard Lock{MMutex}; - // Find the free entry with the smallest suitable size. - auto FoundFreeEntry = MFreeEntries.upper_bound(Size - 1); + // Find the free entry with the smallest suitable size. + auto FoundFreeEntry = MFreeEntries.upper_bound(Size - 1); - // If there was a fitting free entry in the pool, remove and return it. - const bool IsOldEntry = FoundFreeEntry != MFreeEntries.end(); - if (IsNewEntry) - *IsNewEntry = !IsOldEntry; - if (IsOldEntry) { - FreeEntry Entry = *FoundFreeEntry; - MFreeEntries.erase(FoundFreeEntry); - return Entry; + // If there was a fitting free entry in the pool, remove and return it. + const bool IsOldEntry = FoundFreeEntry != MFreeEntries.end(); + if (IsNewEntry) + *IsNewEntry = !IsOldEntry; + if (IsOldEntry) { + FreeEntry Entry = *FoundFreeEntry; + MFreeEntries.erase(FoundFreeEntry); + return Entry; + } } // If there was no suitable free entry we allocate memory and return it in a @@ -63,8 +65,8 @@ ResourcePool::FreeEntry ResourcePool::getOrAllocateEntry( if (DataPtr) MemFlags |= PI_MEM_FLAGS_HOST_PTR_COPY; RT::PiMem NewResMem; - memBufferCreateHelper(MPlatform->getPlugin(), ContextImplPtr->getHandleRef(), - MemFlags, Size, DataPtr, &NewResMem, nullptr); + memBufferCreateHelper(ContextImplPtr, MemFlags, Size, DataPtr, &NewResMem, + nullptr); ++MAllocCount; return {Size, NewResMem}; } diff --git a/sycl/source/detail/usm/usm_impl.cpp b/sycl/source/detail/usm/usm_impl.cpp index 0650877131c50..fcdb72c315744 100644 --- a/sycl/source/detail/usm/usm_impl.cpp +++ b/sycl/source/detail/usm/usm_impl.cpp @@ -43,12 +43,15 @@ using alloc = cl::sycl::usm::alloc; namespace detail { namespace usm { -void *alignedAllocHost(size_t Alignment, size_t Size, const context &Ctxt, - alloc Kind, const detail::code_location &CL) { +static pi_result alignedAllocHostHelper(size_t Alignment, size_t Size, + const context &Ctxt, alloc Kind, + const detail::code_location &CL, + void **OutPtr) { XPTI_CREATE_TRACEPOINT(CL); - void *RetVal = nullptr; - if (Size == 0) - return nullptr; + if (Size == 0) { + *OutPtr = nullptr; + return PI_SUCCESS; + } if (Ctxt.is_host()) { if (!Alignment) { // worst case default @@ -57,10 +60,11 @@ void *alignedAllocHost(size_t Alignment, size_t Size, const context &Ctxt, aligned_allocator Alloc(Alignment); try { - RetVal = Alloc.allocate(Size); + *OutPtr = Alloc.allocate(Size); } catch (const std::bad_alloc &) { // Conform with Specification behavior - RetVal = nullptr; + *OutPtr = nullptr; + return PI_MEM_OBJECT_ALLOCATION_FAILURE; } } else { std::shared_ptr CtxImpl = detail::getSyclObjImpl(Ctxt); @@ -71,13 +75,13 @@ void *alignedAllocHost(size_t Alignment, size_t Size, const context &Ctxt, switch (Kind) { case alloc::host: { Error = Plugin.call_nocheck( - &RetVal, C, nullptr, Size, Alignment); + OutPtr, C, nullptr, Size, Alignment); break; } case alloc::device: case alloc::shared: case alloc::unknown: { - RetVal = nullptr; + *OutPtr = nullptr; Error = PI_INVALID_VALUE; break; } @@ -86,21 +90,41 @@ void *alignedAllocHost(size_t Alignment, size_t Size, const context &Ctxt, // Error is for debugging purposes. // The spec wants a nullptr returned, not an exception. if (Error != PI_SUCCESS) - return nullptr; + *OutPtr = nullptr; + + return Error; + } + return PI_SUCCESS; +} + +void *alignedAllocHost(size_t Alignment, size_t Size, const context &Ctxt, + alloc Kind, const detail::code_location &CL) { + void *RetVal; + pi_result Err = + alignedAllocHostHelper(Alignment, Size, Ctxt, Kind, CL, &RetVal); + + std::shared_ptr CtxImpl = detail::getSyclObjImpl(Ctxt); + ResourcePool &Resources = CtxImpl->getResourcePool(); + if (Err == PI_OUT_OF_RESOURCES && Resources.isEnabled()) { + // Clear resource pool and retry allocation. + Resources.clear(); + alignedAllocHostHelper(Alignment, Size, Ctxt, Kind, CL, &RetVal); } return RetVal; } -void *alignedAlloc(size_t Alignment, size_t Size, const context &Ctxt, - const device &Dev, alloc Kind, - const detail::code_location &CL) { +static pi_result alignedAllocHelper(size_t Alignment, size_t Size, + const context &Ctxt, const device &Dev, + alloc Kind, const detail::code_location &CL, + void **OutPtr) { XPTI_CREATE_TRACEPOINT(CL); - void *RetVal = nullptr; - if (Size == 0) - return nullptr; + if (Size == 0) { + *OutPtr = nullptr; + return PI_SUCCESS; + } if (Ctxt.is_host()) { if (Kind == alloc::unknown) { - RetVal = nullptr; + *OutPtr = nullptr; } else { if (!Alignment) { // worst case default @@ -109,10 +133,11 @@ void *alignedAlloc(size_t Alignment, size_t Size, const context &Ctxt, aligned_allocator Alloc(Alignment); try { - RetVal = Alloc.allocate(Size); + *OutPtr = Alloc.allocate(Size); } catch (const std::bad_alloc &) { // Conform with Specification behavior - RetVal = nullptr; + *OutPtr = nullptr; + return PI_MEM_OBJECT_ALLOCATION_FAILURE; } } } else { @@ -126,18 +151,18 @@ void *alignedAlloc(size_t Alignment, size_t Size, const context &Ctxt, case alloc::device: { Id = detail::getSyclObjImpl(Dev)->getHandleRef(); Error = Plugin.call_nocheck( - &RetVal, C, Id, nullptr, Size, Alignment); + OutPtr, C, Id, nullptr, Size, Alignment); break; } case alloc::shared: { Id = detail::getSyclObjImpl(Dev)->getHandleRef(); Error = Plugin.call_nocheck( - &RetVal, C, Id, nullptr, Size, Alignment); + OutPtr, C, Id, nullptr, Size, Alignment); break; } case alloc::host: case alloc::unknown: { - RetVal = nullptr; + *OutPtr = nullptr; Error = PI_INVALID_VALUE; break; } @@ -146,7 +171,27 @@ void *alignedAlloc(size_t Alignment, size_t Size, const context &Ctxt, // Error is for debugging purposes. // The spec wants a nullptr returned, not an exception. if (Error != PI_SUCCESS) - return nullptr; + *OutPtr = nullptr; + + return Error; + } + + return PI_SUCCESS; +} + +void *alignedAlloc(size_t Alignment, size_t Size, const context &Ctxt, + const device &Dev, alloc Kind, + const detail::code_location &CL) { + void *RetVal; + pi_result Err = + alignedAllocHelper(Alignment, Size, Ctxt, Dev, Kind, CL, &RetVal); + + std::shared_ptr CtxImpl = detail::getSyclObjImpl(Ctxt); + ResourcePool &Resources = CtxImpl->getResourcePool(); + if (Err == PI_OUT_OF_RESOURCES && Resources.isEnabled()) { + // Clear resource pool and retry allocation. + Resources.clear(); + alignedAllocHelper(Alignment, Size, Ctxt, Dev, Kind, CL, &RetVal); } return RetVal; } From b671e7b34591abd158e09b265ebfa76cfb67fe29 Mon Sep 17 00:00:00 2001 From: Steffen Larsen Date: Tue, 8 Mar 2022 14:30:10 +0300 Subject: [PATCH 04/14] Fix formatting Signed-off-by: Steffen Larsen --- sycl/include/CL/sycl/buffer.hpp | 3 +-- sycl/include/CL/sycl/handler.hpp | 2 +- sycl/source/detail/context_impl.hpp | 4 +--- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/sycl/include/CL/sycl/buffer.hpp b/sycl/include/CL/sycl/buffer.hpp index 24f96d7c8097e..50efeb9c48be8 100644 --- a/sycl/include/CL/sycl/buffer.hpp +++ b/sycl/include/CL/sycl/buffer.hpp @@ -513,8 +513,7 @@ class buffer { template friend buffer detail::make_buffer_helper(pi_native_handle, const context &, event); - template - friend struct detail::ManagedResource; + template friend struct detail::ManagedResource; range Range; // Offset field specifies the origin of the sub buffer inside the parent diff --git a/sycl/include/CL/sycl/handler.hpp b/sycl/include/CL/sycl/handler.hpp index 5caa620feb5aa..b0a817fdcd588 100644 --- a/sycl/include/CL/sycl/handler.hpp +++ b/sycl/include/CL/sycl/handler.hpp @@ -479,7 +479,7 @@ class __SYCL_EXPORT handler { void addReduction(const std::shared_ptr &ReduObj) { MSharedPtrStorage.push_back(ReduObj); } - + /// Gets the context implementation of the context associated with the /// handler. /// diff --git a/sycl/source/detail/context_impl.hpp b/sycl/source/detail/context_impl.hpp index fb775e5fd9a9f..53bc15edb3fb1 100644 --- a/sycl/source/detail/context_impl.hpp +++ b/sycl/source/detail/context_impl.hpp @@ -171,9 +171,7 @@ class context_impl { /// Gets the resource pool of the SYCL context. /// /// \return a reference to the resource pool. - ResourcePool &getResourcePool() { - return MAuxiliaryResourcePool; - } + ResourcePool &getResourcePool() { return MAuxiliaryResourcePool; } private: async_handler MAsyncHandler; From 168cb44333eaa3fc64ab4a6d176305dfeabd8b42 Mon Sep 17 00:00:00 2001 From: Steffen Larsen Date: Tue, 8 Mar 2022 23:01:29 +0300 Subject: [PATCH 05/14] Set platform pointer during first allocation Signed-off-by: Steffen Larsen --- sycl/include/CL/sycl/detail/resource_pool.hpp | 6 ------ sycl/source/detail/context_impl.cpp | 3 --- sycl/source/detail/resource_pool.cpp | 7 +++++-- sycl/test/abi/sycl_symbols_windows.dump | 1 - 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/sycl/include/CL/sycl/detail/resource_pool.hpp b/sycl/include/CL/sycl/detail/resource_pool.hpp index a84ace835deff..c69b2dc3ab26f 100644 --- a/sycl/include/CL/sycl/detail/resource_pool.hpp +++ b/sycl/include/CL/sycl/detail/resource_pool.hpp @@ -178,12 +178,6 @@ class __SYCL_EXPORT ResourcePool { assert(MAllocCount == 0 && "Not all resources have returned to the pool."); } - /// Sets the platform of the resource pool. - void setPlatform(const std::shared_ptr &Platform) { - assert(MPlatform == nullptr && "Platform of pool has already been set."); - MPlatform = Platform; - } - /// Returns true if the resource pool is enabled and false otherwise. /// /// \return a boolean value specifying whether the pool is enabled. diff --git a/sycl/source/detail/context_impl.cpp b/sycl/source/detail/context_impl.cpp index 87010fe0474fc..fa923dce03809 100644 --- a/sycl/source/detail/context_impl.cpp +++ b/sycl/source/detail/context_impl.cpp @@ -30,7 +30,6 @@ context_impl::context_impl(const device &Device, async_handler AsyncHandler, : MAsyncHandler(AsyncHandler), MDevices(1, Device), MContext(nullptr), MPlatform(), MPropList(PropList), MHostContext(Device.is_host()) { MKernelProgramCache.setContextPtr(this); - MAuxiliaryResourcePool.setPlatform(MPlatform); } context_impl::context_impl(const std::vector Devices, @@ -62,7 +61,6 @@ context_impl::context_impl(const std::vector Devices, } MKernelProgramCache.setContextPtr(this); - MAuxiliaryResourcePool.setPlatform(MPlatform); } context_impl::context_impl(RT::PiContext PiContext, async_handler AsyncHandler, @@ -101,7 +99,6 @@ context_impl::context_impl(RT::PiContext PiContext, async_handler AsyncHandler, getPlugin().call(MContext); } MKernelProgramCache.setContextPtr(this); - MAuxiliaryResourcePool.setPlatform(MPlatform); } cl_context context_impl::get() const { diff --git a/sycl/source/detail/resource_pool.cpp b/sycl/source/detail/resource_pool.cpp index 8edf10b15ec65..b8892314ccfed 100644 --- a/sycl/source/detail/resource_pool.cpp +++ b/sycl/source/detail/resource_pool.cpp @@ -40,11 +40,14 @@ ResourcePool::FreeEntry ResourcePool::getOrAllocateEntry( const size_t Size, const std::shared_ptr &ContextImplPtr, void *DataPtr, bool *IsNewEntry) { assert(Size && "Size must be greater than 0"); - assert(ContextImplPtr->getPlatformImpl() == MPlatform && - "Context platform does not match the resource pool platform."); + { std::lock_guard Lock{MMutex}; + // Store platform to allow future freeing. + if (!MPlatform) + MPlatform = ContextImplPtr->getPlatformImpl(); + // Find the free entry with the smallest suitable size. auto FoundFreeEntry = MFreeEntries.upper_bound(Size - 1); diff --git a/sycl/test/abi/sycl_symbols_windows.dump b/sycl/test/abi/sycl_symbols_windows.dump index e3262e533d870..a3c290b38bbe2 100644 --- a/sycl/test/abi/sycl_symbols_windows.dump +++ b/sycl/test/abi/sycl_symbols_windows.dump @@ -3951,7 +3951,6 @@ ?setPitches@?$image_impl@$00@detail@sycl@cl@@AEAAXXZ ?setPitches@?$image_impl@$01@detail@sycl@cl@@AEAAXXZ ?setPitches@?$image_impl@$02@detail@sycl@cl@@AEAAXXZ -?setPlatform@ResourcePool@detail@sycl@cl@@QEAAXAEBV?$shared_ptr@Vplatform_impl@detail@sycl@cl@@@std@@@Z ?setStateExplicitKernelBundle@handler@sycl@cl@@AEAAXXZ ?setStateSpecConstSet@handler@sycl@cl@@AEAAXXZ ?setType@handler@sycl@cl@@AEAAXW4CGTYPE@CG@detail@23@@Z From e1b2436e277efda0c8d0bd95a4306a6973260790 Mon Sep 17 00:00:00 2001 From: Steffen Larsen Date: Mon, 21 Mar 2022 15:51:20 +0300 Subject: [PATCH 06/14] Add missing Windows symbol Signed-off-by: Steffen Larsen --- sycl/test/abi/sycl_symbols_windows.dump | 1 + 1 file changed, 1 insertion(+) diff --git a/sycl/test/abi/sycl_symbols_windows.dump b/sycl/test/abi/sycl_symbols_windows.dump index d8fb3f0bdca54..9f2a02607b8bb 100644 --- a/sycl/test/abi/sycl_symbols_windows.dump +++ b/sycl/test/abi/sycl_symbols_windows.dump @@ -2451,6 +2451,7 @@ ?ilogb@__host_std@cl@@YAHN@Z ?ilogb@__host_std@cl@@YAHVhalf@half_impl@detail@sycl@2@@Z ?isConstOrGlobal@handler@sycl@cl@@CA_NW4target@access@23@@Z +?isEnabled@ResourcePool@detail@sycl@cl@@QEAA_NXZ ?isImageOrImageArray@handler@sycl@cl@@CA_NW4target@access@23@@Z ?isInterop@SYCLMemObjT@detail@sycl@cl@@QEBA_NXZ ?isOutOfRange@detail@sycl@cl@@YA_NV?$vec@H$03@23@W4addressing_mode@23@V?$range@$02@23@@Z From cf71eb8bd2fd7af4032a0fc8f87c2c5d2dfc46e5 Mon Sep 17 00:00:00 2001 From: Steffen Larsen Date: Mon, 21 Mar 2022 21:06:18 +0300 Subject: [PATCH 07/14] Make base destructor virtual Signed-off-by: Steffen Larsen --- sycl/include/CL/sycl/detail/resource_pool.hpp | 2 +- sycl/test/abi/sycl_symbols_linux.dump | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sycl/include/CL/sycl/detail/resource_pool.hpp b/sycl/include/CL/sycl/detail/resource_pool.hpp index c69b2dc3ab26f..577a3a899a38a 100644 --- a/sycl/include/CL/sycl/detail/resource_pool.hpp +++ b/sycl/include/CL/sycl/detail/resource_pool.hpp @@ -29,7 +29,7 @@ class ResourcePool; struct __SYCL_EXPORT ManagedResourceBase { ManagedResourceBase() = delete; - ~ManagedResourceBase(); + virtual ~ManagedResourceBase(); protected: ManagedResourceBase(size_t Size, RT::PiMem Mem, ResourcePool *Origin) diff --git a/sycl/test/abi/sycl_symbols_linux.dump b/sycl/test/abi/sycl_symbols_linux.dump index b3fa047ff9374..0eb9166e23fea 100644 --- a/sycl/test/abi/sycl_symbols_linux.dump +++ b/sycl/test/abi/sycl_symbols_linux.dump @@ -3909,6 +3909,7 @@ _ZN2cl4sycl6detail18get_kernel_id_implENSt7__cxx1112basic_stringIcSt11char_trait _ZN2cl4sycl6detail18make_kernel_bundleEmRKNS0_7contextENS0_12bundle_stateENS0_7backendE _ZN2cl4sycl6detail18make_kernel_bundleEmRKNS0_7contextEbNS0_12bundle_stateENS0_7backendE _ZN2cl4sycl6detail18stringifyErrorCodeEi +_ZN2cl4sycl6detail19ManagedResourceBaseD0Ev _ZN2cl4sycl6detail19ManagedResourceBaseD1Ev _ZN2cl4sycl6detail19ManagedResourceBaseD2Ev _ZN2cl4sycl6detail19convertChannelOrderE23_pi_image_channel_order From 44e2a7c51579d44d3f3d280d550605a7980a80b7 Mon Sep 17 00:00:00 2001 From: Steffen Larsen Date: Tue, 22 Mar 2022 13:17:37 +0300 Subject: [PATCH 08/14] Fix windows symbols Signed-off-by: Steffen Larsen --- sycl/test/abi/sycl_symbols_windows.dump | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sycl/test/abi/sycl_symbols_windows.dump b/sycl/test/abi/sycl_symbols_windows.dump index 9f2a02607b8bb..d7a75bf926283 100644 --- a/sycl/test/abi/sycl_symbols_windows.dump +++ b/sycl/test/abi/sycl_symbols_windows.dump @@ -299,6 +299,7 @@ ??0LocalAccessorImplHost@detail@sycl@cl@@QEAA@AEBV0123@@Z ??0LocalAccessorImplHost@detail@sycl@cl@@QEAA@V?$range@$02@23@HH@Z ??0ManagedResourceBase@detail@sycl@cl@@IEAA@_KPEAU_pi_mem@@PEAVResourcePool@123@@Z +??0ManagedResourceBase@detail@sycl@cl@@QEAA@AEBU0123@@Z ??0ResourcePool@detail@sycl@cl@@QEAA@XZ ??0SYCLCategory@detail@sycl@cl@@QEAA@XZ ??0SYCLMemObjT@detail@sycl@cl@@QEAA@AEBVproperty_list@23@V?$unique_ptr@VSYCLMemObjAllocator@detail@sycl@cl@@U?$default_delete@VSYCLMemObjAllocator@detail@sycl@cl@@@std@@@std@@@Z @@ -454,7 +455,7 @@ ??1?$image_impl@$02@detail@sycl@cl@@UEAA@XZ ??1AccessorImplHost@detail@sycl@cl@@QEAA@XZ ??1LocalAccessorImplHost@detail@sycl@cl@@QEAA@XZ -??1ManagedResourceBase@detail@sycl@cl@@QEAA@XZ +??1ManagedResourceBase@detail@sycl@cl@@UEAA@XZ ??1ResourcePool@detail@sycl@cl@@QEAA@XZ ??1SYCLCategory@detail@sycl@cl@@UEAA@XZ ??1SYCLMemObjT@detail@sycl@cl@@UEAA@XZ @@ -592,6 +593,7 @@ ??Zhalf_v2@host_half_impl@detail@sycl@cl@@QEAAAEAV01234@AEBV01234@@Z ??_0half@host_half_impl@detail@sycl@cl@@QEAAAEAV01234@AEBV01234@@Z ??_0half_v2@host_half_impl@detail@sycl@cl@@QEAAAEAV01234@AEBV01234@@Z +??_7ManagedResourceBase@detail@sycl@cl@@6B@ ??_7?$image_impl@$00@detail@sycl@cl@@6B@ ??_7?$image_impl@$01@detail@sycl@cl@@6B@ ??_7?$image_impl@$02@detail@sycl@cl@@6B@ From 7b60471751e7cee1726ec45e03c7e21e446464cc Mon Sep 17 00:00:00 2001 From: Steffen Larsen Date: Tue, 22 Mar 2022 15:19:31 +0300 Subject: [PATCH 09/14] Make isEnabled const and align alloc API Signed-off-by: Steffen Larsen --- sycl/include/CL/sycl/detail/resource_pool.hpp | 14 +++++++------- sycl/include/CL/sycl/handler.hpp | 10 +--------- sycl/source/detail/resource_pool.cpp | 12 ++++++------ sycl/source/handler.cpp | 6 +----- sycl/test/abi/sycl_symbols_linux.dump | 3 +-- sycl/test/abi/sycl_symbols_windows.dump | 3 +-- 6 files changed, 17 insertions(+), 31 deletions(-) diff --git a/sycl/include/CL/sycl/detail/resource_pool.hpp b/sycl/include/CL/sycl/detail/resource_pool.hpp index 577a3a899a38a..00a3649b270dc 100644 --- a/sycl/include/CL/sycl/detail/resource_pool.hpp +++ b/sycl/include/CL/sycl/detail/resource_pool.hpp @@ -125,7 +125,7 @@ class __SYCL_EXPORT ResourcePool { /// is no suitable entry, new memory will be allocated. /// /// \param Range is the range of the resulting buffer. - /// \param ContextImplPtr is the context to allocate memory in. + /// \param QueueImplPtr is the queue with the context to allocate memory in. /// \param DataPtr is the pointer to data on the host to initialize the /// associated memory with. This will only be used if a new entry is /// allocated. @@ -135,7 +135,7 @@ class __SYCL_EXPORT ResourcePool { /// \return a shared pointer to the new managed resource. FreeEntry getOrAllocateEntry(const size_t Size, - const std::shared_ptr &ContextImplPtr, + const std::shared_ptr &QueueImplPtr, void *DataPtr = nullptr, bool *IsNewEntry = nullptr); /// Extracts a free entry from the pool that fits the size required. If there @@ -181,17 +181,17 @@ class __SYCL_EXPORT ResourcePool { /// Returns true if the resource pool is enabled and false otherwise. /// /// \return a boolean value specifying whether the pool is enabled. - bool isEnabled() { return MIsPoolingEnabled; } + bool isEnabled() const { return MIsPoolingEnabled; } /// Creates a managed resource from the pool. /// /// \param Range is the range of the resulting buffer. - /// \param ContextImplPtr is the context to allocate memory in. + /// \param QueueImplPtr is the queue with the context to allocate memory in. /// \return a shared pointer to the new managed resource. template std::shared_ptr> getOrAllocateResource(range Range, - const std::shared_ptr &ContextImplPtr) { + const std::shared_ptr &QueueImplPtr) { // If pool is disabled we return a buffer that will not return to the pool. if (!MIsPoolingEnabled) return std::shared_ptr>{ @@ -199,10 +199,10 @@ class __SYCL_EXPORT ResourcePool { // Get or allocate a free entry that fits the requirements. FreeEntry Entry = - getOrAllocateEntry(Range.size() * sizeof(T), ContextImplPtr); + getOrAllocateEntry(Range.size() * sizeof(T), QueueImplPtr); return std::shared_ptr>{ new ManagedResource(Entry.Size, Entry.Mem, this, Range, - ContextImplPtr)}; + getQueueContextImpl(QueueImplPtr))}; } /// Creates a managed resource from the pool and sets te data of the diff --git a/sycl/include/CL/sycl/handler.hpp b/sycl/include/CL/sycl/handler.hpp index 05970e2dcee47..7fb04db1dea0e 100644 --- a/sycl/include/CL/sycl/handler.hpp +++ b/sycl/include/CL/sycl/handler.hpp @@ -477,13 +477,6 @@ class __SYCL_EXPORT handler { /// @param ReduObj is a pointer to object that must be stored. void addReduction(const std::shared_ptr &ReduObj); - /// Gets the context implementation of the context associated with the - /// handler. - /// - /// \return a reference to the shared pointer pointing to the context - /// implementation of the underlying context. - const std::shared_ptr &getContextImplPtr(); - /// Gets the resource pool for the context associated with the handler. /// /// \return a reference to the resource pool of the underlying context. @@ -496,8 +489,7 @@ class __SYCL_EXPORT handler { template std::shared_ptr> getOrAllocateResourceFromPool(range Range) { - return getResourcePool().getOrAllocateResource( - Range, getContextImplPtr()); + return getResourcePool().getOrAllocateResource(Range, MQueue); } /// Gets or allocates a new resource from the resource pool and intialize it. diff --git a/sycl/source/detail/resource_pool.cpp b/sycl/source/detail/resource_pool.cpp index b8892314ccfed..84735360a63e8 100644 --- a/sycl/source/detail/resource_pool.cpp +++ b/sycl/source/detail/resource_pool.cpp @@ -37,7 +37,7 @@ void ResourcePool::clear() { } ResourcePool::FreeEntry ResourcePool::getOrAllocateEntry( - const size_t Size, const std::shared_ptr &ContextImplPtr, + const size_t Size, const std::shared_ptr &QueueImplPtr, void *DataPtr, bool *IsNewEntry) { assert(Size && "Size must be greater than 0"); @@ -46,7 +46,7 @@ ResourcePool::FreeEntry ResourcePool::getOrAllocateEntry( // Store platform to allow future freeing. if (!MPlatform) - MPlatform = ContextImplPtr->getPlatformImpl(); + MPlatform = QueueImplPtr->getContextImplPtr()->getPlatformImpl(); // Find the free entry with the smallest suitable size. auto FoundFreeEntry = MFreeEntries.upper_bound(Size - 1); @@ -68,8 +68,8 @@ ResourcePool::FreeEntry ResourcePool::getOrAllocateEntry( if (DataPtr) MemFlags |= PI_MEM_FLAGS_HOST_PTR_COPY; RT::PiMem NewResMem; - memBufferCreateHelper(ContextImplPtr, MemFlags, Size, DataPtr, &NewResMem, - nullptr); + memBufferCreateHelper(QueueImplPtr->getContextImplPtr(), MemFlags, Size, + DataPtr, &NewResMem, nullptr); ++MAllocCount; return {Size, NewResMem}; } @@ -77,8 +77,8 @@ ResourcePool::FreeEntry ResourcePool::getOrAllocateEntry( ResourcePool::FreeEntry ResourcePool::getOrAllocateEntry( const size_t Size, const std::shared_ptr &QueueImplPtr, void *DataPtr, event *AvailableEvent, bool *IsNewEntry) { - ResourcePool::FreeEntry Entry = getOrAllocateEntry( - Size, QueueImplPtr->getContextImplPtr(), DataPtr, IsNewEntry); + ResourcePool::FreeEntry Entry = + getOrAllocateEntry(Size, QueueImplPtr, DataPtr, IsNewEntry); // A new entry will have copied from the host pointer on creation. if (IsNewEntry) { diff --git a/sycl/source/handler.cpp b/sycl/source/handler.cpp index 146a81e22abf0..528731779f210 100644 --- a/sycl/source/handler.cpp +++ b/sycl/source/handler.cpp @@ -814,12 +814,8 @@ void handler::depends_on(const std::vector &Events) { } } -const std::shared_ptr &handler::getContextImplPtr() { - return MQueue->getContextImplPtr(); -} - detail::ResourcePool &handler::getResourcePool() { - return getContextImplPtr()->getResourcePool(); + return MQueue->getContextImplPtr()->getResourcePool(); } } // namespace sycl diff --git a/sycl/test/abi/sycl_symbols_linux.dump b/sycl/test/abi/sycl_symbols_linux.dump index 0eb9166e23fea..2964672ef794b 100644 --- a/sycl/test/abi/sycl_symbols_linux.dump +++ b/sycl/test/abi/sycl_symbols_linux.dump @@ -3849,7 +3849,7 @@ _ZN2cl4sycl6detail11stream_implC1EmmRNS0_7handlerE _ZN2cl4sycl6detail11stream_implC2EmmRKNS0_13property_listE _ZN2cl4sycl6detail11stream_implC2EmmRNS0_7handlerE _ZN2cl4sycl6detail12ResourcePool18getOrAllocateEntryEmRKSt10shared_ptrINS1_10queue_implEEPvPNS0_5eventEPb -_ZN2cl4sycl6detail12ResourcePool18getOrAllocateEntryEmRKSt10shared_ptrINS1_12context_implEEPvPb +_ZN2cl4sycl6detail12ResourcePool18getOrAllocateEntryEmRKSt10shared_ptrINS1_10queue_implEEPvPb _ZN2cl4sycl6detail12ResourcePool19getQueueContextImplERKSt10shared_ptrINS1_10queue_implEE _ZN2cl4sycl6detail12ResourcePool5clearEv _ZN2cl4sycl6detail12ResourcePoolC1Ev @@ -4008,7 +4008,6 @@ _ZN2cl4sycl7handler10processArgEPvRKNS0_6detail19kernel_param_kind_tEimRmbb _ZN2cl4sycl7handler12addReductionERKSt10shared_ptrIKvE _ZN2cl4sycl7handler13getKernelNameB5cxx11Ev _ZN2cl4sycl7handler15getResourcePoolEv -_ZN2cl4sycl7handler17getContextImplPtrEv _ZN2cl4sycl7handler17use_kernel_bundleERKNS0_13kernel_bundleILNS0_12bundle_stateE2EEE _ZN2cl4sycl7handler18RangeRoundingTraceEv _ZN2cl4sycl7handler18ext_oneapi_barrierERKSt6vectorINS0_5eventESaIS3_EE diff --git a/sycl/test/abi/sycl_symbols_windows.dump b/sycl/test/abi/sycl_symbols_windows.dump index d7a75bf926283..f952fdc83e26c 100644 --- a/sycl/test/abi/sycl_symbols_windows.dump +++ b/sycl/test/abi/sycl_symbols_windows.dump @@ -2157,7 +2157,6 @@ ?getChannelType@?$image_impl@$00@detail@sycl@cl@@QEBA?AW4image_channel_type@34@XZ ?getChannelType@?$image_impl@$01@detail@sycl@cl@@QEBA?AW4image_channel_type@34@XZ ?getChannelType@?$image_impl@$02@detail@sycl@cl@@QEBA?AW4image_channel_type@34@XZ -?getContextImplPtr@handler@sycl@cl@@AEAAAEBV?$shared_ptr@Vcontext_impl@detail@sycl@cl@@@std@@XZ ?getCurrentDSODir@OSUtil@detail@sycl@cl@@SA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ ?getDelinearizedIndex@handler@sycl@cl@@CA?AV?$id@$00@23@V?$range@$00@23@_K@Z ?getDelinearizedIndex@handler@sycl@cl@@CA?AV?$id@$01@23@V?$range@$01@23@_K@Z @@ -2203,7 +2202,7 @@ ?getNativeVector@event@sycl@cl@@AEBA?AV?$vector@_KV?$allocator@_K@std@@@std@@XZ ?getOSMemSize@OSUtil@detail@sycl@cl@@SA_KXZ ?getOSModuleHandle@OSUtil@detail@sycl@cl@@SA_JPEBX@Z -?getOrAllocateEntry@ResourcePool@detail@sycl@cl@@AEAA?AUFreeEntry@1234@_KAEBV?$shared_ptr@Vcontext_impl@detail@sycl@cl@@@std@@PEAXPEA_N@Z +?getOrAllocateEntry@ResourcePool@detail@sycl@cl@@AEAA?AUFreeEntry@1234@_KAEBV?$shared_ptr@Vqueue_impl@detail@sycl@cl@@@std@@PEAXPEA_N@Z ?getOrAllocateEntry@ResourcePool@detail@sycl@cl@@AEAA?AUFreeEntry@1234@_KAEBV?$shared_ptr@Vqueue_impl@detail@sycl@cl@@@std@@PEAXPEAVevent@34@PEA_N@Z ?getOrCreateSampler@sampler_impl@detail@sycl@cl@@QEAAPEAU_pi_sampler@@AEBVcontext@34@@Z ?getOrInsertHandlerKernelBundle@handler@sycl@cl@@AEBA?AV?$shared_ptr@Vkernel_bundle_impl@detail@sycl@cl@@@std@@_N@Z From ced4794f7b1fe38e92598ef15ec9beb15320037c Mon Sep 17 00:00:00 2001 From: Steffen Larsen Date: Tue, 22 Mar 2022 15:24:45 +0300 Subject: [PATCH 10/14] Fix formatting Signed-off-by: Steffen Larsen --- sycl/include/CL/sycl/detail/resource_pool.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sycl/include/CL/sycl/detail/resource_pool.hpp b/sycl/include/CL/sycl/detail/resource_pool.hpp index 00a3649b270dc..729e065c9f1d0 100644 --- a/sycl/include/CL/sycl/detail/resource_pool.hpp +++ b/sycl/include/CL/sycl/detail/resource_pool.hpp @@ -133,10 +133,10 @@ class __SYCL_EXPORT ResourcePool { /// the pool and false if it was found in the existing free entries in /// the pool. This is not set if it is nullptr. /// \return a shared pointer to the new managed resource. - FreeEntry - getOrAllocateEntry(const size_t Size, - const std::shared_ptr &QueueImplPtr, - void *DataPtr = nullptr, bool *IsNewEntry = nullptr); + FreeEntry getOrAllocateEntry(const size_t Size, + const std::shared_ptr &QueueImplPtr, + void *DataPtr = nullptr, + bool *IsNewEntry = nullptr); /// Extracts a free entry from the pool that fits the size required. If there /// is no suitable entry, new memory will be allocated. The memory will be From c13928360305fb28265c364a03ed8b64e1d1e44f Mon Sep 17 00:00:00 2001 From: Steffen Larsen Date: Tue, 22 Mar 2022 16:28:56 +0300 Subject: [PATCH 11/14] Fix creation of available event Signed-off-by: Steffen Larsen --- sycl/source/detail/resource_pool.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sycl/source/detail/resource_pool.cpp b/sycl/source/detail/resource_pool.cpp index 84735360a63e8..cf3e256c3f64b 100644 --- a/sycl/source/detail/resource_pool.cpp +++ b/sycl/source/detail/resource_pool.cpp @@ -87,12 +87,13 @@ ResourcePool::FreeEntry ResourcePool::getOrAllocateEntry( } // If we get old memory we need to copy explicitly. - RT::PiEvent Event; + auto EventImpl = std::make_shared(QueueImplPtr); + EventImpl->setContextImpl(QueueImplPtr->getContextImplPtr()); QueueImplPtr->getPlugin().call( QueueImplPtr->getHandleRef(), Entry.Mem, - /*blocking_write=*/CL_FALSE, 0, Size, DataPtr, 0, nullptr, &Event); - *AvailableEvent = createSyclObjFromImpl( - std::make_shared(Event, QueueImplPtr->get_context())); + /*blocking_write=*/CL_FALSE, 0, Size, DataPtr, 0, nullptr, + &EventImpl->getHandleRef()); + *AvailableEvent = createSyclObjFromImpl(EventImpl); return Entry; } From 62aab53ff3fbc84dbbef76080b09a4a63954fdb3 Mon Sep 17 00:00:00 2001 From: Steffen Larsen Date: Tue, 22 Mar 2022 18:18:45 +0300 Subject: [PATCH 12/14] Fix Windows symbol Signed-off-by: Steffen Larsen --- sycl/test/abi/sycl_symbols_windows.dump | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sycl/test/abi/sycl_symbols_windows.dump b/sycl/test/abi/sycl_symbols_windows.dump index f952fdc83e26c..c3348afc3132c 100644 --- a/sycl/test/abi/sycl_symbols_windows.dump +++ b/sycl/test/abi/sycl_symbols_windows.dump @@ -2452,7 +2452,7 @@ ?ilogb@__host_std@cl@@YAHN@Z ?ilogb@__host_std@cl@@YAHVhalf@half_impl@detail@sycl@2@@Z ?isConstOrGlobal@handler@sycl@cl@@CA_NW4target@access@23@@Z -?isEnabled@ResourcePool@detail@sycl@cl@@QEAA_NXZ +?isEnabled@ResourcePool@detail@sycl@cl@@QEBA_NXZ ?isImageOrImageArray@handler@sycl@cl@@CA_NW4target@access@23@@Z ?isInterop@SYCLMemObjT@detail@sycl@cl@@QEBA_NXZ ?isOutOfRange@detail@sycl@cl@@YA_NV?$vec@H$03@23@W4addressing_mode@23@V?$range@$02@23@@Z From 604c15fb25f1699d957157a0c207fcb2d754791c Mon Sep 17 00:00:00 2001 From: Steffen Larsen Date: Tue, 22 Mar 2022 20:51:37 +0300 Subject: [PATCH 13/14] Add unittests for resource pool Signed-off-by: Steffen Larsen --- sycl/unittests/misc/CMakeLists.txt | 1 + sycl/unittests/misc/ResourcePool.cpp | 421 +++++++++++++++++++++++++++ 2 files changed, 422 insertions(+) create mode 100644 sycl/unittests/misc/ResourcePool.cpp diff --git a/sycl/unittests/misc/CMakeLists.txt b/sycl/unittests/misc/CMakeLists.txt index 127089d85ebaa..e3cca400403dc 100644 --- a/sycl/unittests/misc/CMakeLists.txt +++ b/sycl/unittests/misc/CMakeLists.txt @@ -4,4 +4,5 @@ add_sycl_unittest(MiscTests SHARED CircularBuffer.cpp KernelBuildOptions.cpp OsUtils.cpp + ResourcePool.cpp ) diff --git a/sycl/unittests/misc/ResourcePool.cpp b/sycl/unittests/misc/ResourcePool.cpp new file mode 100644 index 0000000000000..88e481e3091c9 --- /dev/null +++ b/sycl/unittests/misc/ResourcePool.cpp @@ -0,0 +1,421 @@ +//==---- ResourcePool.cpp --------------------------------------------------==// +// +// 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 +#include +#include +#include + +#include +#include + +#include + +using namespace sycl; + +thread_local size_t AllocCounter = 0; +thread_local std::map AllocRefCountMap; + +static pi_result +redefinedMemBufferCreate(pi_context context, pi_mem_flags flags, size_t size, + void *host_ptr, pi_mem *ret_mem, + const pi_mem_properties *properties = nullptr) { + *ret_mem = reinterpret_cast(++AllocCounter); + AllocRefCountMap.insert({*ret_mem, 1}); + return PI_SUCCESS; +} + +static pi_result redefinedMemRetain(pi_mem mem) { + ++AllocRefCountMap[mem]; + return PI_SUCCESS; +} + +static pi_result redefinedMemRelease(pi_mem mem) { + --AllocRefCountMap[mem]; + return PI_SUCCESS; +} + +static void setupMock(sycl::unittest::PiMock &Mock) { + setupDefaultMockAPIs(Mock); + Mock.redefine(redefinedMemBufferCreate); + Mock.redefine(redefinedMemRetain); + Mock.redefine(redefinedMemRelease); + AllocCounter = 0; + AllocRefCountMap.clear(); +} + +template +using ManagedResourcePtr = std::shared_ptr>; + +template +static pi_mem getResourceMem(ManagedResourcePtr &MR) { + return reinterpret_cast( + detail::getSyclObjImpl(MR->getBuffer())->getUserPtr()); +} + +// Tests that allocated pool resources are correctly allocated, cached, and +// freed. +TEST(ResourcePool, TestResourcePoolAllocate) { + platform Plt{default_selector()}; + if (Plt.is_host()) { + std::cout << "Not run on host" << std::endl; + return; + } + + unittest::PiMock Mock{Plt}; + setupMock(Mock); + + queue Q{Plt.get_devices()[0]}; + std::shared_ptr QImpl = detail::getSyclObjImpl(Q); + + detail::ResourcePool Pool; + pi_mem ResourceMem; + { + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(1), QImpl); + ResourceMem = getResourceMem(Res); + } + ASSERT_EQ(AllocRefCountMap[ResourceMem], 1u) + << "Managed resource was released and not returned to the pool."; + Pool.clear(); + ASSERT_EQ(AllocRefCountMap[ResourceMem], 0u) + << "Pool is not empty after clear."; +} + +// Tests that reallocating a resource with the same size and type will reuse +// memory from a previous allocation. +TEST(ResourcePool, TestResourcePoolReallocate) { + platform Plt{default_selector()}; + if (Plt.is_host()) { + std::cout << "Not run on host" << std::endl; + return; + } + + unittest::PiMock Mock{Plt}; + setupMock(Mock); + + queue Q{Plt.get_devices()[0]}; + std::shared_ptr QImpl = detail::getSyclObjImpl(Q); + + detail::ResourcePool Pool; + pi_mem ResourceMem; + { + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(1), QImpl); + ResourceMem = getResourceMem(Res); + } + { + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(1), QImpl); + pi_mem ReallocedResourceMem = getResourceMem(Res); + ASSERT_EQ(ResourceMem, ReallocedResourceMem) + << "Reallocation did not result in the same resource memory."; + } + ASSERT_EQ(AllocRefCountMap[ResourceMem], 1u) + << "Managed resource was released and not returned to the pool."; + Pool.clear(); + ASSERT_EQ(AllocRefCountMap[ResourceMem], 0u) + << "Pool is not empty after clear."; +} + +// Tests that reallocating a resource with the same type but fewer element will +// reuse memory from a previous allocation with more allocated space. +TEST(ResourcePool, TestResourcePoolReallocateSmaller) { + platform Plt{default_selector()}; + if (Plt.is_host()) { + std::cout << "Not run on host" << std::endl; + return; + } + + unittest::PiMock Mock{Plt}; + setupMock(Mock); + + queue Q{Plt.get_devices()[0]}; + std::shared_ptr QImpl = detail::getSyclObjImpl(Q); + + detail::ResourcePool Pool; + pi_mem ResourceMem; + { + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(250), QImpl); + ResourceMem = getResourceMem(Res); + } + { + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(200), QImpl); + pi_mem ReallocedResourceMem = getResourceMem(Res); + ASSERT_EQ(ResourceMem, ReallocedResourceMem) + << "Reallocation did not result in the same resource memory."; + } + ASSERT_EQ(AllocRefCountMap[ResourceMem], 1u) + << "Managed resource was released and not returned to the pool."; + Pool.clear(); + ASSERT_EQ(AllocRefCountMap[ResourceMem], 0u) + << "Pool is not empty after clear."; +} + +// Tests that reallocating a resource with more elements but a smaller element +// type, requiring a smaller allocation, will reuse memory from a previous +// allocation with more allocated space. +TEST(ResourcePool, TestResourcePoolReallocateSmallerByType) { + platform Plt{default_selector()}; + if (Plt.is_host()) { + std::cout << "Not run on host" << std::endl; + return; + } + + unittest::PiMock Mock{Plt}; + setupMock(Mock); + + queue Q{Plt.get_devices()[0]}; + std::shared_ptr QImpl = detail::getSyclObjImpl(Q); + + detail::ResourcePool Pool; + pi_mem ResourceMem; + { + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(250), QImpl); + ResourceMem = getResourceMem(Res); + } + { + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(300), QImpl); + pi_mem ReallocedResourceMem = getResourceMem(Res); + ASSERT_EQ(ResourceMem, ReallocedResourceMem) + << "Reallocation did not result in the same resource memory."; + } + ASSERT_EQ(AllocRefCountMap[ResourceMem], 1u) + << "Managed resource was released and not returned to the pool."; + Pool.clear(); + ASSERT_EQ(AllocRefCountMap[ResourceMem], 0u) + << "Pool is not empty after clear."; +} + +// Tests that reallocating a resource that requires more elements of the same +// type as a previous reduction does not result in a reuse of the memory from +// the previous allocation. +TEST(ResourcePool, TestResourcePoolReallocateLarger) { + platform Plt{default_selector()}; + if (Plt.is_host()) { + std::cout << "Not run on host" << std::endl; + return; + } + + unittest::PiMock Mock{Plt}; + setupMock(Mock); + + queue Q{Plt.get_devices()[0]}; + std::shared_ptr QImpl = detail::getSyclObjImpl(Q); + + detail::ResourcePool Pool; + pi_mem ResourceMem1, ResourceMem2; + { + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(250), QImpl); + ResourceMem1 = getResourceMem(Res); + } + { + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(300), QImpl); + ResourceMem2 = getResourceMem(Res); + } + ASSERT_NE(ResourceMem1, ResourceMem2) + << "Reallocation unexpectedly resulted in the same resource memory."; + ASSERT_EQ(AllocRefCountMap[ResourceMem1], 1u) + << "Managed resource 1 was released and not returned to the pool."; + ASSERT_EQ(AllocRefCountMap[ResourceMem2], 1u) + << "Managed resource 2 was released and not returned to the pool."; + Pool.clear(); + ASSERT_EQ(AllocRefCountMap[ResourceMem1] + AllocRefCountMap[ResourceMem2], 0u) + << "Pool is not empty after clear."; +} + +// Tests that reallocating a resource that requires more memory than a previous +// allocation due to the type, but with a smaller number of elements, does not +// result in a reuse of the memory from the previous allocation. +TEST(ResourcePool, TestResourcePoolReallocateLargerByType) { + platform Plt{default_selector()}; + if (Plt.is_host()) { + std::cout << "Not run on host" << std::endl; + return; + } + + unittest::PiMock Mock{Plt}; + setupMock(Mock); + + queue Q{Plt.get_devices()[0]}; + std::shared_ptr QImpl = detail::getSyclObjImpl(Q); + + detail::ResourcePool Pool; + pi_mem ResourceMem1, ResourceMem2; + { + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(250), QImpl); + ResourceMem1 = getResourceMem(Res); + } + { + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(200), QImpl); + ResourceMem2 = getResourceMem(Res); + } + ASSERT_NE(ResourceMem1, ResourceMem2) + << "Reallocation unexpectedly resulted in the same resource memory."; + ASSERT_EQ(AllocRefCountMap[ResourceMem1], 1u) + << "Managed resource 1 was released and not returned to the pool."; + ASSERT_EQ(AllocRefCountMap[ResourceMem2], 1u) + << "Managed resource 2 was released and not returned to the pool."; + Pool.clear(); + ASSERT_EQ(AllocRefCountMap[ResourceMem1] + AllocRefCountMap[ResourceMem2], 0u) + << "Pool is not empty after clear."; +} + +// Tests that allocating a resource that fits in multiple of the available free +// allocations will pick the smallest of these allocations. +TEST(ResourcePool, TestResourcePoolReallocatePickOptimal) { + platform Plt{default_selector()}; + if (Plt.is_host()) { + std::cout << "Not run on host" << std::endl; + return; + } + + unittest::PiMock Mock{Plt}; + setupMock(Mock); + + queue Q{Plt.get_devices()[0]}; + std::shared_ptr QImpl = detail::getSyclObjImpl(Q); + + detail::ResourcePool Pool; + pi_mem OptimalReuseMem; + { + ManagedResourcePtr Res1 = + Pool.getOrAllocateResource(range<1>(250), QImpl); + ManagedResourcePtr Res2 = + Pool.getOrAllocateResource(range<1>(210), QImpl); + ManagedResourcePtr Res3 = + Pool.getOrAllocateResource(range<1>(220), QImpl); + ManagedResourcePtr Res4 = + Pool.getOrAllocateResource(range<1>(199), QImpl); + // Res3 is optimal as it is the smallest allocation with room for at least + // 200 ints. + OptimalReuseMem = getResourceMem(Res3); + } + { + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(200), QImpl); + pi_mem ReusedMem = getResourceMem(Res); + ASSERT_NE(ReusedMem, OptimalReuseMem) + << "Reallocation did not pick the optimal available memory."; + } + ASSERT_EQ(AllocRefCountMap[OptimalReuseMem], 1u) + << "Managed resource was released and not returned to the pool."; + Pool.clear(); + ASSERT_EQ(AllocRefCountMap[OptimalReuseMem], 0u) + << "Pool is not empty after clear."; +} + +// Tests that allocating another resource of the same size as another living +// resource does not cause a reuse of the living resource. +TEST(ResourcePool, TestResourcePoolMultipleLiving) { + platform Plt{default_selector()}; + if (Plt.is_host()) { + std::cout << "Not run on host" << std::endl; + return; + } + + unittest::PiMock Mock{Plt}; + setupMock(Mock); + + queue Q{Plt.get_devices()[0]}; + std::shared_ptr QImpl = detail::getSyclObjImpl(Q); + + detail::ResourcePool Pool; + pi_mem ResourceMem1, ResourceMem2; + { + ManagedResourcePtr Res1 = + Pool.getOrAllocateResource(range<1>(1), QImpl); + ResourceMem1 = getResourceMem(Res1); + ManagedResourcePtr Res2 = Pool.getOrAllocateResource( + range<1>(1), detail::getSyclObjImpl(Q)); + ResourceMem2 = getResourceMem(Res2); + } + ASSERT_NE(ResourceMem1, ResourceMem2) + << "Reallocation unexpectedly resulted in the same resource memory."; + ASSERT_EQ(AllocRefCountMap[ResourceMem1], 1u) + << "Managed resource 1 was released and not returned to the pool."; + ASSERT_EQ(AllocRefCountMap[ResourceMem2], 1u) + << "Managed resource 2 was released and not returned to the pool."; + Pool.clear(); + ASSERT_EQ(AllocRefCountMap[ResourceMem1] + AllocRefCountMap[ResourceMem2], 0u) + << "Pool is not empty after clear."; +} + +// Tests that clearing the pool while a resource is alive does not cause the +// resource to be freed. +TEST(ResourcePool, TestResourcePoolClearWhileAlive) { + platform Plt{default_selector()}; + if (Plt.is_host()) { + std::cout << "Not run on host" << std::endl; + return; + } + + unittest::PiMock Mock{Plt}; + setupMock(Mock); + + queue Q{Plt.get_devices()[0]}; + std::shared_ptr QImpl = detail::getSyclObjImpl(Q); + + detail::ResourcePool Pool; + pi_mem ResourceMem; + { + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(1), QImpl); + ResourceMem = getResourceMem(Res); + ASSERT_GE(AllocRefCountMap[ResourceMem], 1u) + << "Managed resource was dead before clear."; + Pool.clear(); + ASSERT_GE(AllocRefCountMap[ResourceMem], 1u) + << "Managed resource was dead after clear."; + } + ASSERT_EQ(AllocRefCountMap[ResourceMem], 1u) + << "Managed resource was released and not returned to the pool."; + Pool.clear(); + ASSERT_EQ(AllocRefCountMap[ResourceMem], 0u) + << "Pool is not empty after clear."; +} + +// Tests that the resource pool owned by a context correctly clears when the +// context dies. +TEST(ResourcePool, TestResourcePoolClearOnContext) { + platform Plt{default_selector()}; + if (Plt.is_host()) { + std::cout << "Not run on host" << std::endl; + return; + } + + unittest::PiMock Mock{Plt}; + setupMock(Mock); + + pi_mem ResourceMem; + { + context Ctx{Plt}; + queue Q{Ctx, Ctx.get_devices()[0]}; + std::shared_ptr CtxImpl = detail::getSyclObjImpl(Ctx); + std::shared_ptr QImpl = detail::getSyclObjImpl(Q); + + detail::ResourcePool &Pool = CtxImpl->getResourcePool(); + { + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(1), QImpl); + ResourceMem = getResourceMem(Res); + } + ASSERT_EQ(AllocRefCountMap[ResourceMem], 1u) + << "Managed resource was released and not returned to the pool."; + } + ASSERT_EQ(AllocRefCountMap[ResourceMem], 0u) + << "Context pool was not cleared after destruction."; +} From 5679ab30bf5989cafc56203d6a4eb8761ab3db74 Mon Sep 17 00:00:00 2001 From: Steffen Larsen Date: Wed, 23 Mar 2022 13:19:53 +0300 Subject: [PATCH 14/14] Switch testing to fixed-width integers Signed-off-by: Steffen Larsen --- sycl/unittests/misc/ResourcePool.cpp | 80 ++++++++++++++-------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/sycl/unittests/misc/ResourcePool.cpp b/sycl/unittests/misc/ResourcePool.cpp index 88e481e3091c9..ca7cf496c8953 100644 --- a/sycl/unittests/misc/ResourcePool.cpp +++ b/sycl/unittests/misc/ResourcePool.cpp @@ -76,8 +76,8 @@ TEST(ResourcePool, TestResourcePoolAllocate) { detail::ResourcePool Pool; pi_mem ResourceMem; { - ManagedResourcePtr Res = - Pool.getOrAllocateResource(range<1>(1), QImpl); + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(1), QImpl); ResourceMem = getResourceMem(Res); } ASSERT_EQ(AllocRefCountMap[ResourceMem], 1u) @@ -105,13 +105,13 @@ TEST(ResourcePool, TestResourcePoolReallocate) { detail::ResourcePool Pool; pi_mem ResourceMem; { - ManagedResourcePtr Res = - Pool.getOrAllocateResource(range<1>(1), QImpl); + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(1), QImpl); ResourceMem = getResourceMem(Res); } { - ManagedResourcePtr Res = - Pool.getOrAllocateResource(range<1>(1), QImpl); + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(1), QImpl); pi_mem ReallocedResourceMem = getResourceMem(Res); ASSERT_EQ(ResourceMem, ReallocedResourceMem) << "Reallocation did not result in the same resource memory."; @@ -141,13 +141,13 @@ TEST(ResourcePool, TestResourcePoolReallocateSmaller) { detail::ResourcePool Pool; pi_mem ResourceMem; { - ManagedResourcePtr Res = - Pool.getOrAllocateResource(range<1>(250), QImpl); + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(250), QImpl); ResourceMem = getResourceMem(Res); } { - ManagedResourcePtr Res = - Pool.getOrAllocateResource(range<1>(200), QImpl); + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(200), QImpl); pi_mem ReallocedResourceMem = getResourceMem(Res); ASSERT_EQ(ResourceMem, ReallocedResourceMem) << "Reallocation did not result in the same resource memory."; @@ -178,13 +178,13 @@ TEST(ResourcePool, TestResourcePoolReallocateSmallerByType) { detail::ResourcePool Pool; pi_mem ResourceMem; { - ManagedResourcePtr Res = - Pool.getOrAllocateResource(range<1>(250), QImpl); + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(250), QImpl); ResourceMem = getResourceMem(Res); } { - ManagedResourcePtr Res = - Pool.getOrAllocateResource(range<1>(300), QImpl); + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(300), QImpl); pi_mem ReallocedResourceMem = getResourceMem(Res); ASSERT_EQ(ResourceMem, ReallocedResourceMem) << "Reallocation did not result in the same resource memory."; @@ -215,13 +215,13 @@ TEST(ResourcePool, TestResourcePoolReallocateLarger) { detail::ResourcePool Pool; pi_mem ResourceMem1, ResourceMem2; { - ManagedResourcePtr Res = - Pool.getOrAllocateResource(range<1>(250), QImpl); + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(250), QImpl); ResourceMem1 = getResourceMem(Res); } { - ManagedResourcePtr Res = - Pool.getOrAllocateResource(range<1>(300), QImpl); + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(300), QImpl); ResourceMem2 = getResourceMem(Res); } ASSERT_NE(ResourceMem1, ResourceMem2) @@ -254,13 +254,13 @@ TEST(ResourcePool, TestResourcePoolReallocateLargerByType) { detail::ResourcePool Pool; pi_mem ResourceMem1, ResourceMem2; { - ManagedResourcePtr Res = - Pool.getOrAllocateResource(range<1>(250), QImpl); + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(250), QImpl); ResourceMem1 = getResourceMem(Res); } { - ManagedResourcePtr Res = - Pool.getOrAllocateResource(range<1>(200), QImpl); + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(200), QImpl); ResourceMem2 = getResourceMem(Res); } ASSERT_NE(ResourceMem1, ResourceMem2) @@ -292,21 +292,21 @@ TEST(ResourcePool, TestResourcePoolReallocatePickOptimal) { detail::ResourcePool Pool; pi_mem OptimalReuseMem; { - ManagedResourcePtr Res1 = - Pool.getOrAllocateResource(range<1>(250), QImpl); - ManagedResourcePtr Res2 = - Pool.getOrAllocateResource(range<1>(210), QImpl); - ManagedResourcePtr Res3 = - Pool.getOrAllocateResource(range<1>(220), QImpl); - ManagedResourcePtr Res4 = - Pool.getOrAllocateResource(range<1>(199), QImpl); + ManagedResourcePtr Res1 = + Pool.getOrAllocateResource(range<1>(250), QImpl); + ManagedResourcePtr Res2 = + Pool.getOrAllocateResource(range<1>(210), QImpl); + ManagedResourcePtr Res3 = + Pool.getOrAllocateResource(range<1>(220), QImpl); + ManagedResourcePtr Res4 = + Pool.getOrAllocateResource(range<1>(199), QImpl); // Res3 is optimal as it is the smallest allocation with room for at least // 200 ints. OptimalReuseMem = getResourceMem(Res3); } { - ManagedResourcePtr Res = - Pool.getOrAllocateResource(range<1>(200), QImpl); + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(200), QImpl); pi_mem ReusedMem = getResourceMem(Res); ASSERT_NE(ReusedMem, OptimalReuseMem) << "Reallocation did not pick the optimal available memory."; @@ -336,11 +336,11 @@ TEST(ResourcePool, TestResourcePoolMultipleLiving) { detail::ResourcePool Pool; pi_mem ResourceMem1, ResourceMem2; { - ManagedResourcePtr Res1 = - Pool.getOrAllocateResource(range<1>(1), QImpl); + ManagedResourcePtr Res1 = + Pool.getOrAllocateResource(range<1>(1), QImpl); ResourceMem1 = getResourceMem(Res1); - ManagedResourcePtr Res2 = Pool.getOrAllocateResource( - range<1>(1), detail::getSyclObjImpl(Q)); + ManagedResourcePtr Res2 = + Pool.getOrAllocateResource(range<1>(1), QImpl); ResourceMem2 = getResourceMem(Res2); } ASSERT_NE(ResourceMem1, ResourceMem2) @@ -372,8 +372,8 @@ TEST(ResourcePool, TestResourcePoolClearWhileAlive) { detail::ResourcePool Pool; pi_mem ResourceMem; { - ManagedResourcePtr Res = - Pool.getOrAllocateResource(range<1>(1), QImpl); + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(1), QImpl); ResourceMem = getResourceMem(Res); ASSERT_GE(AllocRefCountMap[ResourceMem], 1u) << "Managed resource was dead before clear."; @@ -409,8 +409,8 @@ TEST(ResourcePool, TestResourcePoolClearOnContext) { detail::ResourcePool &Pool = CtxImpl->getResourcePool(); { - ManagedResourcePtr Res = - Pool.getOrAllocateResource(range<1>(1), QImpl); + ManagedResourcePtr Res = + Pool.getOrAllocateResource(range<1>(1), QImpl); ResourceMem = getResourceMem(Res); } ASSERT_EQ(AllocRefCountMap[ResourceMem], 1u)