From 99d40951df87790fb884ce1c42d5e2a7a0009ee0 Mon Sep 17 00:00:00 2001 From: Georgios Pinitas Date: Mon, 23 Apr 2018 16:26:46 +0100 Subject: COMPMID-1023: Import memory for OpenCL Change-Id: I201bc00a1261814737e6b6878ecfe9904bae0cc1 Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/128212 Tested-by: Jenkins Reviewed-by: Anthony Barbier --- arm_compute/runtime/Allocator.h | 7 +- arm_compute/runtime/CL/CLBufferAllocator.h | 5 +- arm_compute/runtime/CL/CLMemory.h | 82 ++++++++++ arm_compute/runtime/CL/CLMemoryRegion.h | 178 +++++++++++++++++++++ arm_compute/runtime/CL/CLTensor.h | 2 +- arm_compute/runtime/CL/CLTensorAllocator.h | 26 +-- arm_compute/runtime/CL/SVMMemory.h | 57 ------- .../runtime/GLES_COMPUTE/GCBufferAllocator.h | 3 +- arm_compute/runtime/IAllocator.h | 14 +- arm_compute/runtime/IMemoryRegion.h | 83 ++++++++++ arm_compute/runtime/Memory.h | 36 ++--- arm_compute/runtime/MemoryRegion.h | 83 ++++++++++ src/runtime/Allocator.cpp | 10 +- src/runtime/CL/CLBufferAllocator.cpp | 10 +- src/runtime/CL/CLMemory.cpp | 67 ++++++++ src/runtime/CL/CLMemoryRegion.cpp | 152 ++++++++++++++++++ src/runtime/CL/CLTensor.cpp | 4 +- src/runtime/CL/CLTensorAllocator.cpp | 147 +++++++---------- src/runtime/GLES_COMPUTE/GCBufferAllocator.cpp | 6 + src/runtime/Memory.cpp | 45 +++--- src/runtime/TensorAllocator.cpp | 29 ++-- tests/validation/CL/UNIT/TensorAllocator.cpp | 80 +++++++++ tests/validation/NEON/UNIT/TensorAllocator.cpp | 12 +- 23 files changed, 912 insertions(+), 226 deletions(-) create mode 100644 arm_compute/runtime/CL/CLMemory.h create mode 100644 arm_compute/runtime/CL/CLMemoryRegion.h delete mode 100644 arm_compute/runtime/CL/SVMMemory.h create mode 100644 arm_compute/runtime/IMemoryRegion.h create mode 100644 arm_compute/runtime/MemoryRegion.h create mode 100644 src/runtime/CL/CLMemory.cpp create mode 100644 src/runtime/CL/CLMemoryRegion.cpp create mode 100644 tests/validation/CL/UNIT/TensorAllocator.cpp diff --git a/arm_compute/runtime/Allocator.h b/arm_compute/runtime/Allocator.h index cf6f07b211..963c2d8eef 100644 --- a/arm_compute/runtime/Allocator.h +++ b/arm_compute/runtime/Allocator.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017-2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -26,12 +26,14 @@ #include "arm_compute/runtime/IAllocator.h" +#include "arm_compute/runtime/IMemoryRegion.h" + #include namespace arm_compute { /** Default malloc allocator implementation */ -class Allocator : public IAllocator +class Allocator final : public IAllocator { public: /** Default constructor */ @@ -40,6 +42,7 @@ public: // Inherited methods overridden: void *allocate(size_t size, size_t alignment) override; void free(void *ptr) override; + std::unique_ptr make_region(size_t size, size_t alignment) override; }; } // arm_compute #endif /*__ARM_COMPUTE_ALLOCATOR_H__ */ diff --git a/arm_compute/runtime/CL/CLBufferAllocator.h b/arm_compute/runtime/CL/CLBufferAllocator.h index 05b0363dc3..19a3e627ca 100644 --- a/arm_compute/runtime/CL/CLBufferAllocator.h +++ b/arm_compute/runtime/CL/CLBufferAllocator.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017-2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -34,7 +34,7 @@ namespace arm_compute { /** Default OpenCL cl buffer allocator implementation */ -class CLBufferAllocator : public IAllocator +class CLBufferAllocator final : public IAllocator { public: /** Default constructor */ @@ -43,6 +43,7 @@ public: // Inherited methods overridden: void *allocate(size_t size, size_t alignment) override; void free(void *ptr) override; + std::unique_ptr make_region(size_t size, size_t alignment) override; private: cl::Context _context; diff --git a/arm_compute/runtime/CL/CLMemory.h b/arm_compute/runtime/CL/CLMemory.h new file mode 100644 index 0000000000..edd9de8097 --- /dev/null +++ b/arm_compute/runtime/CL/CLMemory.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2018 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __ARM_COMPUTE_RUNTIME_CL_CLMEMORY_H__ +#define __ARM_COMPUTE_RUNTIME_CL_CLMEMORY_H__ + +#include "arm_compute/core/CL/OpenCL.h" +#include "arm_compute/runtime/CL/CLMemoryRegion.h" + +#include +#include + +namespace arm_compute +{ +/** OpenCL implementation of memory object */ +class CLMemory +{ +public: + /** Default Constructor */ + CLMemory(); + /** Default Constructor + * + * @param[in] memory Memory to be imported + */ + CLMemory(std::shared_ptr memory); + /** Default Constructor + * + * @note Ownership of the memory is not transferred to this object. + * Thus management (allocate/free) should be done by the client. + * + * @param[in] memory Memory to be imported + */ + CLMemory(ICLMemoryRegion *memory); + /** Allow instances of this class to be copied */ + CLMemory(const CLMemory &) = default; + /** Allow instances of this class to be copy assigned */ + CLMemory &operator=(const CLMemory &) = default; + /** Allow instances of this class to be moved */ + CLMemory(CLMemory &&) noexcept = default; + /** Allow instances of this class to be move assigned */ + CLMemory &operator=(CLMemory &&) noexcept = default; + /** Region accessor + * + * @return Memory region + */ + ICLMemoryRegion *region(); + /** Region accessor + * + * @return Memory region + */ + ICLMemoryRegion *region() const; + +private: + /** Creates empty region */ + void create_empty_region(); + +private: + ICLMemoryRegion *_region; + std::shared_ptr _region_owned; +}; +} // namespace arm_compute +#endif /* __ARM_COMPUTE_RUNTIME_CL_CLMEMORY_H__ */ diff --git a/arm_compute/runtime/CL/CLMemoryRegion.h b/arm_compute/runtime/CL/CLMemoryRegion.h new file mode 100644 index 0000000000..01dd54e391 --- /dev/null +++ b/arm_compute/runtime/CL/CLMemoryRegion.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2018 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __ARM_COMPUTE_RUNTIME_CL_CL_MEMORY_REGION_H__ +#define __ARM_COMPUTE_RUNTIME_CL_CL_MEMORY_REGION_H__ + +#include "arm_compute/core/CL/OpenCL.h" +#include "arm_compute/runtime/IMemoryRegion.h" + +#include + +namespace arm_compute +{ +/** OpenCL memory region interface */ +class ICLMemoryRegion : public IMemoryRegion +{ +public: + /** Constructor + * + * @param[in] ctx OpenCL context + * @param[in] size Region size + */ + ICLMemoryRegion(cl::Context ctx, size_t size); + /** Default Destructor */ + virtual ~ICLMemoryRegion() = default; + /** Prevent instances of this class from being copied (As this class contains pointers) */ + ICLMemoryRegion(const ICLMemoryRegion &) = delete; + /** Default move constructor */ + ICLMemoryRegion(ICLMemoryRegion &&) = default; + /** Prevent instances of this class from being copied (As this class contains pointers) */ + ICLMemoryRegion &operator=(const ICLMemoryRegion &) = delete; + /** Default move assignment operator */ + ICLMemoryRegion &operator=(ICLMemoryRegion &&) = default; + /** Returns the underlying CL buffer + * + * @return CL memory buffer object + */ + const cl::Buffer &cl_data() const; + /** Host/SVM pointer accessor + * + * @return Host/SVM pointer base + */ + virtual void *ptr() = 0; + /** Enqueue a map operation of the allocated buffer on the given queue. + * + * @param[in,out] q The CL command queue to use for the mapping operation. + * @param[in] blocking If true, then the mapping will be ready to use by the time + * this method returns, else it is the caller's responsibility + * to flush the queue and wait for the mapping operation to have completed before using the returned mapping pointer. + * + * @return The mapping address. + */ + virtual void *map(cl::CommandQueue &q, bool blocking) = 0; + /** Enqueue an unmap operation of the allocated buffer on the given queue. + * + * @note This method simply enqueue the unmap operation, it is the caller's responsibility to flush the queue and make sure the unmap is finished before + * the memory is accessed by the device. + * + * @param[in,out] q The CL command queue to use for the mapping operation. + */ + virtual void unmap(cl::CommandQueue &q) = 0; + + // Inherited methods overridden : + void *buffer() override; + void *buffer() const override; + void **handle() override; + +protected: + cl::Context _ctx; + void *_mapping; + cl::Buffer _mem; +}; + +/** OpenCL buffer memory region implementation */ +class CLBufferMemoryRegion final : public ICLMemoryRegion +{ +public: + /** Constructor + * + * @param[in] ctx OpenCL context + * @param[in] flags Memory flags + * @param[in] size Region size + */ + CLBufferMemoryRegion(cl::Context ctx, cl_mem_flags flags, size_t size); + + // Inherited methods overridden : + void *ptr() override; + void *map(cl::CommandQueue &q, bool blocking) override; + void unmap(cl::CommandQueue &q) override; +}; + +/** OpenCL SVM memory region interface */ +class ICLSVMMemoryRegion : public ICLMemoryRegion +{ +protected: + /** Constructor + * + * @param[in] ctx OpenCL context + * @param[in] flags Memory flags + * @param[in] size Region size + * @param[in] alignment Alignment + */ + ICLSVMMemoryRegion(cl::Context ctx, cl_mem_flags flags, size_t size, size_t alignment); + /** Destructor */ + virtual ~ICLSVMMemoryRegion(); + /** Prevent instances of this class from being copied (As this class contains pointers) */ + ICLSVMMemoryRegion(const ICLSVMMemoryRegion &) = delete; + /** Default move constructor */ + ICLSVMMemoryRegion(ICLSVMMemoryRegion &&) = default; + /** Prevent instances of this class from being copied (As this class contains pointers) */ + ICLSVMMemoryRegion &operator=(const ICLSVMMemoryRegion &) = delete; + /** Default move assignment operator */ + ICLSVMMemoryRegion &operator=(ICLSVMMemoryRegion &&) = default; + + // Inherited methods overridden : + void *ptr() override; + +protected: + void *_ptr; +}; + +/** OpenCL coarse-grain SVM memory region implementation */ +class CLCoarseSVMMemoryRegion final : public ICLSVMMemoryRegion +{ +public: + /** Constructor + * + * @param[in] ctx OpenCL context + * @param[in] flags Memory flags + * @param[in] size Region size + * @param[in] alignment Alignment + */ + CLCoarseSVMMemoryRegion(cl::Context ctx, cl_mem_flags flags, size_t size, size_t alignment); + + // Inherited methods overridden : + void *map(cl::CommandQueue &q, bool blocking) override; + void unmap(cl::CommandQueue &q) override; +}; + +/** OpenCL fine-grain SVM memory region implementation */ +class CLFineSVMMemoryRegion final : public ICLSVMMemoryRegion +{ +public: + /** Constructor + * + * @param[in] ctx OpenCL context + * @param[in] flags Memory flags + * @param[in] size Region size + * @param[in] alignment Alignment + */ + CLFineSVMMemoryRegion(cl::Context ctx, cl_mem_flags flags, size_t size, size_t alignment); + + // Inherited methods overridden : + void *map(cl::CommandQueue &q, bool blocking) override; + void unmap(cl::CommandQueue &q) override; +}; +} // namespace arm_compute +#endif /* __ARM_COMPUTE_RUNTIME_CL_CL_MEMORY_REGION_H__ */ diff --git a/arm_compute/runtime/CL/CLTensor.h b/arm_compute/runtime/CL/CLTensor.h index e05f307621..c47d2be1b0 100644 --- a/arm_compute/runtime/CL/CLTensor.h +++ b/arm_compute/runtime/CL/CLTensor.h @@ -45,7 +45,7 @@ public: * * @return A pointer to the tensor's allocator */ - ITensorAllocator *allocator(); + CLTensorAllocator *allocator(); /** Enqueue a map operation of the allocated buffer. * * @param[in] blocking If true, then the mapping will be ready to use by the time diff --git a/arm_compute/runtime/CL/CLTensorAllocator.h b/arm_compute/runtime/CL/CLTensorAllocator.h index 6929d551fb..a372195555 100644 --- a/arm_compute/runtime/CL/CLTensorAllocator.h +++ b/arm_compute/runtime/CL/CLTensorAllocator.h @@ -24,10 +24,11 @@ #ifndef __ARM_COMPUTE_CLTENSORALLOCATOR_H__ #define __ARM_COMPUTE_CLTENSORALLOCATOR_H__ +#include "arm_compute/runtime/CL/CLMemory.h" #include "arm_compute/runtime/ITensorAllocator.h" #include "arm_compute/core/CL/OpenCL.h" -#include "arm_compute/runtime/CL/SVMMemory.h" + #include namespace arm_compute @@ -47,8 +48,6 @@ public: * @param[in] owner (Optional) Owner of the allocator. */ CLTensorAllocator(CLTensor *owner = nullptr); - /** Default destructor */ - ~CLTensorAllocator(); /** Prevent instances of this class from being copied (As this class contains pointers) */ CLTensorAllocator(const CLTensorAllocator &) = delete; /** Prevent instances of this class from being copy assigned (As this class contains pointers) */ @@ -68,8 +67,6 @@ public: * @return pointer to the CL data. */ const cl::Buffer &cl_data() const; - /** SVM memory */ - void *svm_ptr(); /** Enqueue a map operation of the allocated buffer on the given queue. * @@ -104,6 +101,19 @@ public: * */ void free() override; + /** Import an existing memory as a tensor's backing memory + * + * @warning If the tensor is flagged to be managed by a memory manager, + * this call will lead to an error. + * @warning Ownership of memory depends on the way the @ref CLMemory object was constructed + * @note Calling free on a tensor with imported memory will just clear + * the internal pointer value. + * + * @param[in] memory Memory to import + * + * @return error status + */ + arm_compute::Status import_memory(CLMemory memory); /** Associates the tensor with a memory group * * @param[in] associated_memory_group Memory group to associate the tensor with @@ -121,10 +131,8 @@ protected: private: CLMemoryGroup *_associated_memory_group; /**< Registered memory manager */ - cl::Buffer _buffer; /**< OpenCL buffer containing the tensor data. */ - uint8_t *_mapping; /**< Pointer to the CPU mapping of the OpenCL buffer. */ + CLMemory _memory; /**< OpenCL memory */ CLTensor *_owner; /**< Owner of the allocator */ - SVMMemory _svm_memory; /**< Svm memory */ }; -} +} // namespace arm_compute #endif /* __ARM_COMPUTE_CLTENSORALLOCATOR_H__ */ diff --git a/arm_compute/runtime/CL/SVMMemory.h b/arm_compute/runtime/CL/SVMMemory.h deleted file mode 100644 index 9029388c70..0000000000 --- a/arm_compute/runtime/CL/SVMMemory.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2018 ARM Limited. - * - * SPDX-License-Identifier: MIT - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef __ARM_COMPUTE_SVMMEMORY_H__ -#define __ARM_COMPUTE_SVMMEMORY_H__ - -namespace arm_compute -{ -class SVMMemory final -{ -public: - SVMMemory() = default; - SVMMemory(void *ptr, bool fine_grain) - : _ptr(ptr), _fine_grain(fine_grain), _size(0) - { - } - void *ptr() const - { - return _ptr; - } - bool fine_grain() const - { - return _fine_grain; - } - size_t size() const - { - return _size; - } - void *allocate(cl_context context, size_t size, cl_svm_mem_flags flags, cl_uint alignment); - -private: - void *_ptr{ nullptr }; - bool _fine_grain{ false }; - size_t _size{ 0 }; -}; -} -#endif /* __ARM_COMPUTE_SVMMEMORY_H__ */ diff --git a/arm_compute/runtime/GLES_COMPUTE/GCBufferAllocator.h b/arm_compute/runtime/GLES_COMPUTE/GCBufferAllocator.h index 8fa13e59a6..674297a63c 100644 --- a/arm_compute/runtime/GLES_COMPUTE/GCBufferAllocator.h +++ b/arm_compute/runtime/GLES_COMPUTE/GCBufferAllocator.h @@ -34,7 +34,7 @@ namespace arm_compute { /** Default GLES buffer allocator implementation */ -class GCBufferAllocator : public IAllocator +class GCBufferAllocator final : public IAllocator { public: /** Default constructor */ @@ -43,6 +43,7 @@ public: // Inherited methods overridden: void *allocate(size_t size, size_t alignment) override; void free(void *ptr) override; + std::unique_ptr make_region(size_t size, size_t alignment) override; }; } // namespace arm_compute #endif /*__ARM_COMPUTE_GCBUFFERALLOCATOR_H__ */ diff --git a/arm_compute/runtime/IAllocator.h b/arm_compute/runtime/IAllocator.h index 3edb34a9ea..591ae0bff4 100644 --- a/arm_compute/runtime/IAllocator.h +++ b/arm_compute/runtime/IAllocator.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017-2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -24,7 +24,10 @@ #ifndef __ARM_COMPUTE_IALLOCATOR_H__ #define __ARM_COMPUTE_IALLOCATOR_H__ +#include "arm_compute/runtime/IMemoryRegion.h" + #include +#include namespace arm_compute { @@ -34,6 +37,7 @@ class IAllocator public: /** Default virtual destructor. */ virtual ~IAllocator() = default; + // TODO (COMPMID-1088) : Change allocator and rest interfaces to use IMemoryRegion /** Interface to be implemented by the child class to allocate bytes * * @param[in] size Size to allocate @@ -44,6 +48,14 @@ public: virtual void *allocate(size_t size, size_t alignment) = 0; /** Interface to be implemented by the child class to free the allocated tensor */ virtual void free(void *ptr) = 0; + /** Create self-managed memory region + * + * @param[in] size Size of the memory region + * @param[in] alignment Alignment of the memory region + * + * @return The memory region object + */ + virtual std::unique_ptr make_region(size_t size, size_t alignment) = 0; }; } // arm_compute #endif /*__ARM_COMPUTE_IALLOCATOR_H__ */ diff --git a/arm_compute/runtime/IMemoryRegion.h b/arm_compute/runtime/IMemoryRegion.h new file mode 100644 index 0000000000..4c08b4ab09 --- /dev/null +++ b/arm_compute/runtime/IMemoryRegion.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2018 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __ARM_COMPUTE_RUNTIME_IMEMORY_REGION_H__ +#define __ARM_COMPUTE_RUNTIME_IMEMORY_REGION_H__ + +#include + +namespace arm_compute +{ +/** Memory region interface */ +class IMemoryRegion +{ +public: + /** Default constructor + * + * @param[in] size Region size + */ + IMemoryRegion(size_t size) + : _size(size) + { + } + /** Virtual Destructor */ + virtual ~IMemoryRegion() = default; + /** Returns the pointer to the allocated data. + * + * @return Pointer to the allocated data + */ + virtual void *buffer() = 0; + /** Returns the pointer to the allocated data. + * + * @return Pointer to the allocated data + */ + virtual void *buffer() const = 0; + /** Handle of internal memory + * + * @return Handle of memory + */ + virtual void **handle() = 0; + /** Memory region size accessor + * + * @return Memory region size + */ + size_t size() + { + return _size; + } + /** Sets size of region + * + * @warning This should only be used in correlation with handle + * + * @param[in] size Size to set + */ + void set_size(size_t size) + { + _size = size; + } + +protected: + size_t _size; +}; +} // namespace arm_compute +#endif /* __ARM_COMPUTE_RUNTIME_IMEMORY_REGION_H__ */ diff --git a/arm_compute/runtime/Memory.h b/arm_compute/runtime/Memory.h index 98bbb70239..2dadccf254 100644 --- a/arm_compute/runtime/Memory.h +++ b/arm_compute/runtime/Memory.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017-2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -24,6 +24,8 @@ #ifndef __ARM_COMPUTE_MEMORY_H__ #define __ARM_COMPUTE_MEMORY_H__ +#include "arm_compute/runtime/IMemoryRegion.h" + #include #include @@ -36,12 +38,10 @@ public: /** Default Constructor */ Memory(); /** Default Constructor - * - * @note Ownership of the memory is transferred to this object * * @param[in] memory Memory to be imported */ - Memory(std::shared_ptr memory); + Memory(std::shared_ptr memory); /** Default Constructor * * @note Ownership of the memory is not transferred to this object. @@ -49,7 +49,7 @@ public: * * @param[in] memory Memory to be imported */ - Memory(uint8_t *memory); + Memory(IMemoryRegion *memory); /** Allow instances of this class to be copied */ Memory(const Memory &) = default; /** Allow instances of this class to be copy assigned */ @@ -58,26 +58,24 @@ public: Memory(Memory &&) noexcept = default; /** Allow instances of this class to be move assigned */ Memory &operator=(Memory &&) noexcept = default; - - /** Returns the pointer to the allocated data. + /** Region accessor * - * @return Pointer to the allocated data + * @return Memory region */ - uint8_t *buffer(); - /** Returns the pointer to the allocated data. + IMemoryRegion *region(); + /** Region accessor * - * @return Pointer to the allocated data + * @return Memory region */ - uint8_t *buffer() const; - /** Handle of internal memory - * - * @return Handle of memory - */ - uint8_t **handle(); + IMemoryRegion *region() const; + +private: + /** Creates empty region */ + void create_empty_region(); private: - uint8_t *_memory; - std::shared_ptr _memory_owned; + IMemoryRegion *_region; + std::shared_ptr _region_owned; }; } #endif /* __ARM_COMPUTE_MEMORY_H__ */ diff --git a/arm_compute/runtime/MemoryRegion.h b/arm_compute/runtime/MemoryRegion.h new file mode 100644 index 0000000000..bf4e1719de --- /dev/null +++ b/arm_compute/runtime/MemoryRegion.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2018 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __ARM_COMPUTE_RUNTIME_MEMORY_REGION_H__ +#define __ARM_COMPUTE_RUNTIME_MEMORY_REGION_H__ + +#include "arm_compute/runtime/IMemoryRegion.h" + +#include "arm_compute/core/Error.h" + +#include + +namespace arm_compute +{ +/** Memory region CPU implementation */ +class MemoryRegion final : public IMemoryRegion +{ +public: + /** Default constructor + * + * @param[in] size Region size + */ + MemoryRegion(size_t size) + : IMemoryRegion(size), _mem(nullptr), _ptr(nullptr) + { + if(size != 0) + { + _mem = std::shared_ptr(new uint8_t[size](), [](uint8_t *ptr) + { + delete[] ptr; + }); + _ptr = _mem.get(); + } + } + /** Prevent instances of this class from being copied (As this class contains pointers) */ + MemoryRegion(const MemoryRegion &) = delete; + /** Default move constructor */ + MemoryRegion(MemoryRegion &&) = default; + /** Prevent instances of this class from being copied (As this class contains pointers) */ + MemoryRegion &operator=(const MemoryRegion &) = delete; + /** Default move assignment operator */ + MemoryRegion &operator=(MemoryRegion &&) = default; + + // Inherited methods overridden : + void *buffer() final + { + return _mem.get(); + } + void *buffer() const final + { + return _mem.get(); + } + void **handle() final + { + return reinterpret_cast(&_mem); + } + +protected: + std::shared_ptr _mem; + uint8_t *_ptr; +}; +} // namespace arm_compute +#endif /* __ARM_COMPUTE_RUNTIME_MEMORY_REGION_H__ */ diff --git a/src/runtime/Allocator.cpp b/src/runtime/Allocator.cpp index 50b0f0e6bb..7f0e37495e 100644 --- a/src/runtime/Allocator.cpp +++ b/src/runtime/Allocator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017-2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -22,8 +22,10 @@ * SOFTWARE. */ #include "arm_compute/runtime/Allocator.h" +#include "arm_compute/runtime/MemoryRegion.h" #include "arm_compute/core/Error.h" +#include "support/ToolchainSupport.h" #include @@ -39,3 +41,9 @@ void Allocator::free(void *ptr) { ::operator delete(ptr); } + +std::unique_ptr Allocator::make_region(size_t size, size_t alignment) +{ + ARM_COMPUTE_UNUSED(alignment); + return arm_compute::support::cpp14::make_unique(size); +} \ No newline at end of file diff --git a/src/runtime/CL/CLBufferAllocator.cpp b/src/runtime/CL/CLBufferAllocator.cpp index 9a5c13ac5a..84789e70d2 100644 --- a/src/runtime/CL/CLBufferAllocator.cpp +++ b/src/runtime/CL/CLBufferAllocator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017-2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -22,9 +22,11 @@ * SOFTWARE. */ #include "arm_compute/runtime/CL/CLBufferAllocator.h" +#include "arm_compute/runtime/CL/CLMemoryRegion.h" #include "arm_compute/core/CL/OpenCL.h" #include "arm_compute/core/Error.h" +#include "support/ToolchainSupport.h" #include @@ -47,3 +49,9 @@ void CLBufferAllocator::free(void *ptr) ARM_COMPUTE_ERROR_ON(ptr == nullptr); clReleaseMemObject(static_cast(ptr)); } + +std::unique_ptr CLBufferAllocator::make_region(size_t size, size_t alignment) +{ + ARM_COMPUTE_UNUSED(alignment); + return arm_compute::support::cpp14::make_unique(_context, CL_MEM_ALLOC_HOST_PTR | CL_MEM_READ_WRITE, size); +} diff --git a/src/runtime/CL/CLMemory.cpp b/src/runtime/CL/CLMemory.cpp new file mode 100644 index 0000000000..534c4f9e34 --- /dev/null +++ b/src/runtime/CL/CLMemory.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "arm_compute/runtime/CL/CLMemory.h" + +#include "arm_compute/core/Error.h" + +namespace arm_compute +{ +CLMemory::CLMemory() + : _region(nullptr), _region_owned(nullptr) +{ + create_empty_region(); +} + +CLMemory::CLMemory(std::shared_ptr memory) + : _region(nullptr), _region_owned(std::move(memory)) +{ + if(_region_owned == nullptr) + { + create_empty_region(); + } + _region = _region_owned.get(); +} + +CLMemory::CLMemory(ICLMemoryRegion *memory) + : _region(memory), _region_owned(nullptr) +{ + _region = memory; +} + +ICLMemoryRegion *CLMemory::region() +{ + return _region; +} + +ICLMemoryRegion *CLMemory::region() const +{ + return _region; +} + +void CLMemory::create_empty_region() +{ + _region_owned = std::make_shared(cl::Context::getDefault(), CL_MEM_ALLOC_HOST_PTR | CL_MEM_READ_WRITE, 0); + _region = _region_owned.get(); +} +} // namespace arm_compute \ No newline at end of file diff --git a/src/runtime/CL/CLMemoryRegion.cpp b/src/runtime/CL/CLMemoryRegion.cpp new file mode 100644 index 0000000000..15fd7f333e --- /dev/null +++ b/src/runtime/CL/CLMemoryRegion.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2018 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "arm_compute/runtime/CL/CLMemoryRegion.h" + +#include "arm_compute/core/Error.h" +#include "arm_compute/runtime/CL/CLScheduler.h" + +namespace arm_compute +{ +ICLMemoryRegion::ICLMemoryRegion(cl::Context ctx, size_t size) + : IMemoryRegion(size), _ctx(std::move(ctx)), _mapping(nullptr), _mem() +{ +} + +const cl::Buffer &ICLMemoryRegion::cl_data() const +{ + return _mem; +} + +void *ICLMemoryRegion::buffer() +{ + return _mapping; +} + +void *ICLMemoryRegion::buffer() const +{ + return _mapping; +} + +void **ICLMemoryRegion::handle() +{ + return reinterpret_cast(&_mem); +} + +CLBufferMemoryRegion::CLBufferMemoryRegion(cl::Context ctx, cl_mem_flags flags, size_t size) + : ICLMemoryRegion(std::move(ctx), size) +{ + if(_size != 0) + { + _mem = cl::Buffer(_ctx, flags, _size); + } +} + +void *CLBufferMemoryRegion::ptr() +{ + return nullptr; +} + +void *CLBufferMemoryRegion::map(cl::CommandQueue &q, bool blocking) +{ + ARM_COMPUTE_ERROR_ON(_mem.get() == nullptr); + _mapping = q.enqueueMapBuffer(_mem, blocking ? CL_TRUE : CL_FALSE, CL_MAP_READ | CL_MAP_WRITE, 0, _size); + return _mapping; +} + +void CLBufferMemoryRegion::unmap(cl::CommandQueue &q) +{ + ARM_COMPUTE_ERROR_ON(_mem.get() == nullptr); + q.enqueueUnmapMemObject(_mem, _mapping); + _mapping = nullptr; +} + +ICLSVMMemoryRegion::ICLSVMMemoryRegion(cl::Context ctx, cl_mem_flags flags, size_t size, size_t alignment) + : ICLMemoryRegion(std::move(ctx), size), _ptr(nullptr) +{ + if(size != 0) + { + _ptr = clSVMAlloc(_ctx.get(), flags, size, alignment); + if(_ptr != nullptr) + { + _mem = cl::Buffer(_ctx, CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, _size, _ptr); + } + } +} + +ICLSVMMemoryRegion::~ICLSVMMemoryRegion() +{ + if(_ptr != nullptr) + { + clFinish(CLScheduler::get().queue().get()); + _mem = cl::Buffer(); + clSVMFree(_ctx.get(), _ptr); + } +} + +void *ICLSVMMemoryRegion::ptr() +{ + return _ptr; +} + +CLCoarseSVMMemoryRegion::CLCoarseSVMMemoryRegion(cl::Context ctx, cl_mem_flags flags, size_t size, size_t alignment) + : ICLSVMMemoryRegion(std::move(ctx), flags, size, alignment) +{ +} + +void *CLCoarseSVMMemoryRegion::map(cl::CommandQueue &q, bool blocking) +{ + ARM_COMPUTE_ERROR_ON(_ptr == nullptr); + clEnqueueSVMMap(q.get(), blocking ? CL_TRUE : CL_FALSE, CL_MAP_READ | CL_MAP_WRITE, _ptr, _size, 0, nullptr, nullptr); + _mapping = _ptr; + return _mapping; +} + +void CLCoarseSVMMemoryRegion::unmap(cl::CommandQueue &q) +{ + ARM_COMPUTE_ERROR_ON(_ptr == nullptr); + clEnqueueSVMUnmap(q.get(), _ptr, 0, nullptr, nullptr); + _mapping = nullptr; +} + +CLFineSVMMemoryRegion::CLFineSVMMemoryRegion(cl::Context ctx, cl_mem_flags flags, size_t size, size_t alignment) + : ICLSVMMemoryRegion(std::move(ctx), flags, size, alignment) +{ +} + +void *CLFineSVMMemoryRegion::map(cl::CommandQueue &q, bool blocking) +{ + if(blocking) + { + clFinish(q.get()); + } + _mapping = _ptr; + return _mapping; +} + +void CLFineSVMMemoryRegion::unmap(cl::CommandQueue &q) +{ + ARM_COMPUTE_UNUSED(q); + _mapping = nullptr; +} +} // namespace arm_compute \ No newline at end of file diff --git a/src/runtime/CL/CLTensor.cpp b/src/runtime/CL/CLTensor.cpp index bc513d139b..dd277384c7 100644 --- a/src/runtime/CL/CLTensor.cpp +++ b/src/runtime/CL/CLTensor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017 ARM Limited. + * Copyright (c) 2016-2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -47,7 +47,7 @@ const cl::Buffer &CLTensor::cl_buffer() const return _allocator.cl_data(); } -ITensorAllocator *CLTensor::allocator() +CLTensorAllocator *CLTensor::allocator() { return &_allocator; } diff --git a/src/runtime/CL/CLTensorAllocator.cpp b/src/runtime/CL/CLTensorAllocator.cpp index c5524b1ccb..54e7c5b336 100644 --- a/src/runtime/CL/CLTensorAllocator.cpp +++ b/src/runtime/CL/CLTensorAllocator.cpp @@ -30,67 +30,57 @@ using namespace arm_compute; -CLTensorAllocator::CLTensorAllocator(CLTensor *owner) - : _associated_memory_group(nullptr), _buffer(), _mapping(nullptr), _owner(owner), _svm_memory() +namespace +{ +std::shared_ptr allocate_region(cl::Context context, size_t size, cl_uint alignment) { + // Try fine-grain SVM + std::shared_ptr region = std::make_shared(context, CL_MEM_READ_WRITE | CL_MEM_SVM_FINE_GRAIN_BUFFER, size, alignment); + + // Try coarse-grain SVM in case of failure + if(region != nullptr && region->ptr() == nullptr) + { + region = std::make_shared(context, CL_MEM_READ_WRITE, size, alignment); + } + // Try legacy buffer memory in case of failure + if(region != nullptr && region->ptr() == nullptr) + { + region = std::make_shared(context, CL_MEM_ALLOC_HOST_PTR | CL_MEM_READ_WRITE, size); + } + return region; } +} // namespace -CLTensorAllocator::~CLTensorAllocator() +CLTensorAllocator::CLTensorAllocator(CLTensor *owner) + : _associated_memory_group(nullptr), _memory(), _owner(owner) { - _buffer = cl::Buffer(); } uint8_t *CLTensorAllocator::data() { - return _mapping; + ARM_COMPUTE_ERROR_ON(_memory.region() == nullptr); + return reinterpret_cast(_memory.region()->buffer()); } const cl::Buffer &CLTensorAllocator::cl_data() const { - return _buffer; -} - -void *SVMMemory::allocate(cl_context context, size_t size, cl_svm_mem_flags flags, cl_uint alignment) -{ - ARM_COMPUTE_ERROR_ON_NULLPTR(context); - ARM_COMPUTE_ERROR_ON(size == 0); - ARM_COMPUTE_ERROR_ON(_ptr != nullptr); - ARM_COMPUTE_ERROR_ON(size > CL_DEVICE_MAX_MEM_ALLOC_SIZE); - _ptr = clSVMAlloc(context, flags, size, alignment); - if(_ptr != nullptr) - { - _size = size; - _fine_grain = static_cast(flags & CL_MEM_SVM_FINE_GRAIN_BUFFER); - } - return _ptr; -} -void *CLTensorAllocator::svm_ptr() -{ - return _svm_memory.ptr(); + ARM_COMPUTE_ERROR_ON(_memory.region() == nullptr); + return _memory.region()->cl_data(); } void CLTensorAllocator::allocate() { + ARM_COMPUTE_ERROR_ON(_memory.region() == nullptr); + if(_associated_memory_group == nullptr) { - ARM_COMPUTE_ERROR_ON(_buffer.get() != nullptr); - if(_svm_memory.allocate(CLScheduler::get().context()(), CL_MEM_READ_WRITE | CL_MEM_SVM_FINE_GRAIN_BUFFER, info().total_size(), 0) == nullptr) - { - // try at coarse grain svm memory - _svm_memory.allocate(CLScheduler::get().context()(), CL_MEM_READ_WRITE, info().total_size(), 0); - } - if(_svm_memory.ptr() != nullptr) - { - _buffer = cl::Buffer(CLScheduler::get().context(), CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, info().total_size(), _svm_memory.ptr()); - } - else - { - _buffer = cl::Buffer(CLScheduler::get().context(), CL_MEM_ALLOC_HOST_PTR | CL_MEM_READ_WRITE, info().total_size()); - } + ARM_COMPUTE_ERROR_ON(_memory.region()->cl_data().get() != nullptr); + _memory = CLMemory(allocate_region(CLScheduler::get().context(), info().total_size(), 0)); } else { - _associated_memory_group->finalize_memory(_owner, reinterpret_cast(&_buffer()), info().total_size()); + _associated_memory_group->finalize_memory(_owner, _memory.region()->handle(), info().total_size()); + _memory.region()->set_size(info().total_size()); } info().set_is_resizable(false); } @@ -99,80 +89,55 @@ void CLTensorAllocator::free() { if(_associated_memory_group == nullptr) { - _buffer = cl::Buffer(); - if(_svm_memory.ptr() != nullptr) - { - clSVMFree(CLScheduler::get().context()(), _svm_memory.ptr()); - } + _memory = CLMemory(); info().set_is_resizable(true); } } +arm_compute::Status CLTensorAllocator::import_memory(CLMemory memory) +{ + ARM_COMPUTE_ERROR_ON(_memory.region() == nullptr); + ARM_COMPUTE_RETURN_ERROR_ON(memory.region()->cl_data().get() == nullptr); + ARM_COMPUTE_RETURN_ERROR_ON(_associated_memory_group != nullptr); + _memory = memory; + info().set_is_resizable(false); + + return Status{}; +} + void CLTensorAllocator::set_associated_memory_group(CLMemoryGroup *associated_memory_group) { + ARM_COMPUTE_ERROR_ON(_memory.region() == nullptr); ARM_COMPUTE_ERROR_ON(associated_memory_group == nullptr); ARM_COMPUTE_ERROR_ON(_associated_memory_group != nullptr); - ARM_COMPUTE_ERROR_ON(_buffer.get() != nullptr); + ARM_COMPUTE_ERROR_ON(_memory.region()->cl_data().get() != nullptr); + _memory = CLMemory(std::make_shared(CLScheduler::get().context(), CL_MEM_ALLOC_HOST_PTR | CL_MEM_READ_WRITE, 0)); _associated_memory_group = associated_memory_group; } uint8_t *CLTensorAllocator::lock() { - ARM_COMPUTE_ERROR_ON(_mapping != nullptr); - _mapping = map(CLScheduler::get().queue(), true); - return _mapping; + return map(CLScheduler::get().queue(), true); } void CLTensorAllocator::unlock() { - ARM_COMPUTE_ERROR_ON(_mapping == nullptr); - unmap(CLScheduler::get().queue(), _mapping); - _mapping = nullptr; + ARM_COMPUTE_ERROR_ON(_memory.region() == nullptr); + unmap(CLScheduler::get().queue(), reinterpret_cast(_memory.region()->buffer())); } uint8_t *CLTensorAllocator::map(cl::CommandQueue &q, bool blocking) { - const bool svm_mem = _svm_memory.ptr() != nullptr; - const bool fine_grain_svm = _svm_memory.fine_grain(); - if(!svm_mem) - { - ARM_COMPUTE_ERROR_ON(_buffer.get() == nullptr); - return static_cast(q.enqueueMapBuffer(_buffer, blocking ? CL_TRUE : CL_FALSE, CL_MAP_READ | CL_MAP_WRITE, 0, info().total_size())); - } - else if(!fine_grain_svm) - { - const cl_int ret = clEnqueueSVMMap(q(), blocking ? CL_TRUE : CL_FALSE, CL_MAP_READ | CL_MAP_WRITE, _svm_memory.ptr(), _svm_memory.size(), 0, nullptr, nullptr); - ARM_COMPUTE_ERROR_ON(ret != CL_SUCCESS); - if(ret == CL_SUCCESS) - { - return reinterpret_cast(_svm_memory.ptr()); - } - else - { - return nullptr; - } - } - else - { - if(blocking) - { - clFinish(q()); - } - return reinterpret_cast(_svm_memory.ptr()); - } + ARM_COMPUTE_ERROR_ON(_memory.region() == nullptr); + ARM_COMPUTE_ERROR_ON(_memory.region()->buffer() != nullptr); + _memory.region()->map(q, blocking); + return reinterpret_cast(_memory.region()->buffer()); } void CLTensorAllocator::unmap(cl::CommandQueue &q, uint8_t *mapping) { - const bool svm_mem = _svm_memory.ptr() != nullptr; - const bool fine_grain_svm = _svm_memory.fine_grain(); - if(!svm_mem) - { - ARM_COMPUTE_ERROR_ON(_buffer.get() == nullptr); - q.enqueueUnmapMemObject(_buffer, mapping); - } - else if(!fine_grain_svm) - { - clEnqueueSVMUnmap(q(), _svm_memory.ptr(), 0, nullptr, nullptr); - } + ARM_COMPUTE_UNUSED(mapping); + ARM_COMPUTE_ERROR_ON(_memory.region() == nullptr); + ARM_COMPUTE_ERROR_ON(_memory.region()->buffer() == nullptr); + _memory.region()->unmap(q); } diff --git a/src/runtime/GLES_COMPUTE/GCBufferAllocator.cpp b/src/runtime/GLES_COMPUTE/GCBufferAllocator.cpp index d8f6867634..cdd12c3ad5 100644 --- a/src/runtime/GLES_COMPUTE/GCBufferAllocator.cpp +++ b/src/runtime/GLES_COMPUTE/GCBufferAllocator.cpp @@ -48,4 +48,10 @@ void GCBufferAllocator::free(void *ptr) auto *gl_buffer = reinterpret_cast(ptr); delete gl_buffer; } + +std::unique_ptr GCBufferAllocator::make_region(size_t size, size_t alignment) +{ + ARM_COMPUTE_UNUSED(size, alignment); + return nullptr; +} } // namespace arm_compute diff --git a/src/runtime/Memory.cpp b/src/runtime/Memory.cpp index 35d0c824bb..15bbb17675 100644 --- a/src/runtime/Memory.cpp +++ b/src/runtime/Memory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017-2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -23,40 +23,45 @@ */ #include "arm_compute/runtime/Memory.h" -#include "arm_compute/core/Error.h" - -using namespace arm_compute; +#include "arm_compute/runtime/MemoryRegion.h" +namespace arm_compute +{ Memory::Memory() - : _memory(nullptr), _memory_owned(nullptr) + : _region(nullptr), _region_owned(nullptr) { + create_empty_region(); } -Memory::Memory(std::shared_ptr memory) - : _memory(nullptr), _memory_owned(std::move(memory)) +Memory::Memory(std::shared_ptr memory) + : _region(nullptr), _region_owned(std::move(memory)) { - ARM_COMPUTE_ERROR_ON(_memory_owned.get() == nullptr); - _memory = _memory_owned.get(); + if(_region_owned == nullptr) + { + create_empty_region(); + } + _region = _region_owned.get(); } -Memory::Memory(uint8_t *memory) - : _memory(memory), _memory_owned(nullptr) +Memory::Memory(IMemoryRegion *memory) + : _region(memory), _region_owned(nullptr) { - ARM_COMPUTE_ERROR_ON(memory == nullptr); + _region = memory; } -uint8_t *Memory::buffer() +IMemoryRegion *Memory::region() { - return _memory; + return _region; } -uint8_t *Memory::buffer() const +IMemoryRegion *Memory::region() const { - return _memory; + return _region; } -uint8_t **Memory::handle() +void Memory::create_empty_region() { - ARM_COMPUTE_ERROR_ON(_memory_owned.get() != nullptr); - return &_memory; -} \ No newline at end of file + _region_owned = std::make_shared(0); + _region = _region_owned.get(); +} +} // namespace arm_compute diff --git a/src/runtime/TensorAllocator.cpp b/src/runtime/TensorAllocator.cpp index a0d41b28ee..993a95b6c3 100644 --- a/src/runtime/TensorAllocator.cpp +++ b/src/runtime/TensorAllocator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017 ARM Limited. + * Copyright (c) 2016-2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -27,6 +27,7 @@ #include "arm_compute/core/Error.h" #include "arm_compute/core/TensorInfo.h" #include "arm_compute/runtime/MemoryGroup.h" +#include "arm_compute/runtime/MemoryRegion.h" #include "support/ToolchainSupport.h" #include @@ -114,7 +115,7 @@ void TensorAllocator::init(const TensorAllocator &allocator, const Coordinates & ARM_COMPUTE_UNUSED(validate_subtensor_shape); // Copy pointer to buffer - _memory = Memory(allocator._memory.buffer()); + _memory = Memory(allocator._memory.region()); // Init tensor info with new dimensions size_t total_size = parent_info.offset_element_in_bytes(coords) + sub_info.total_size() - sub_info.offset_first_element_in_bytes(); @@ -126,22 +127,23 @@ void TensorAllocator::init(const TensorAllocator &allocator, const Coordinates & uint8_t *TensorAllocator::data() const { - return _memory.buffer(); + ARM_COMPUTE_ERROR_ON(_memory.region() == nullptr); + return reinterpret_cast(_memory.region()->buffer()); } void TensorAllocator::allocate() { - ARM_COMPUTE_ERROR_ON(_memory.buffer() != nullptr); + ARM_COMPUTE_ERROR_ON(_memory.region() == nullptr); + ARM_COMPUTE_ERROR_ON(_memory.region()->buffer() != nullptr); + if(_associated_memory_group == nullptr) { - _memory = Memory(std::shared_ptr(new uint8_t[info().total_size()](), [](uint8_t *ptr) - { - delete[] ptr; - })); + _memory = Memory(std::make_shared(info().total_size())); } else { - _associated_memory_group->finalize_memory(_owner, reinterpret_cast(_memory.handle()), info().total_size()); + _associated_memory_group->finalize_memory(_owner, reinterpret_cast(_memory.region()->handle()), info().total_size()); + _memory.region()->set_size(info().total_size()); } info().set_is_resizable(false); } @@ -154,7 +156,8 @@ void TensorAllocator::free() arm_compute::Status TensorAllocator::import_memory(Memory memory) { - ARM_COMPUTE_RETURN_ERROR_ON(memory.buffer() == nullptr); + ARM_COMPUTE_ERROR_ON(_memory.region() == nullptr); + ARM_COMPUTE_RETURN_ERROR_ON(memory.region()->buffer() == nullptr); ARM_COMPUTE_RETURN_ERROR_ON(_associated_memory_group != nullptr); _memory = memory; info().set_is_resizable(false); @@ -164,15 +167,17 @@ arm_compute::Status TensorAllocator::import_memory(Memory memory) void TensorAllocator::set_associated_memory_group(MemoryGroup *associated_memory_group) { + ARM_COMPUTE_ERROR_ON(_memory.region() == nullptr); ARM_COMPUTE_ERROR_ON(associated_memory_group == nullptr); ARM_COMPUTE_ERROR_ON(_associated_memory_group != nullptr); - ARM_COMPUTE_ERROR_ON(_memory.buffer() != nullptr); + ARM_COMPUTE_ERROR_ON(_memory.region()->buffer() != nullptr); _associated_memory_group = associated_memory_group; } uint8_t *TensorAllocator::lock() { - return _memory.buffer(); + ARM_COMPUTE_ERROR_ON(_memory.region() == nullptr); + return reinterpret_cast(_memory.region()->buffer()); } void TensorAllocator::unlock() diff --git a/tests/validation/CL/UNIT/TensorAllocator.cpp b/tests/validation/CL/UNIT/TensorAllocator.cpp new file mode 100644 index 0000000000..a34a37eb7b --- /dev/null +++ b/tests/validation/CL/UNIT/TensorAllocator.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "arm_compute/runtime/CL/CLTensorAllocator.h" + +#include "arm_compute/runtime/CL/CLMemoryGroup.h" +#include "arm_compute/runtime/CL/CLScheduler.h" +#include "tests/framework/Asserts.h" +#include "tests/framework/Macros.h" + +#include + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +TEST_SUITE(CL) +TEST_SUITE(UNIT) +TEST_SUITE(TensorAllocator) + +TEST_CASE(ImportMemory, framework::DatasetMode::ALL) +{ + // Init tensor info + TensorInfo info(TensorShape(24U, 16U, 3U), 1, DataType::F32); + + // Allocate memory + auto buf = std::make_shared(CLScheduler::get().context(), CL_MEM_ALLOC_HOST_PTR | CL_MEM_READ_WRITE, info.total_size()); + + // Negative case : Import empty memory + CLTensor t1; + t1.allocator()->init(info); + ARM_COMPUTE_EXPECT(!bool(t1.allocator()->import_memory(CLMemory())), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(t1.info()->is_resizable(), framework::LogLevel::ERRORS); + + // Negative case : Import memory to a tensor that is memory managed + CLTensor t2; + CLMemoryGroup mg; + t2.allocator()->set_associated_memory_group(&mg); + ARM_COMPUTE_EXPECT(!bool(t2.allocator()->import_memory(CLMemory(buf))), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(t2.info()->is_resizable(), framework::LogLevel::ERRORS); + + // Positive case : Set managed pointer + CLTensor t3; + t3.allocator()->init(info); + ARM_COMPUTE_EXPECT(bool(t3.allocator()->import_memory(CLMemory(buf))), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(!t3.info()->is_resizable(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(t3.cl_buffer().get() == buf->cl_data().get(), framework::LogLevel::ERRORS); + t3.allocator()->free(); + ARM_COMPUTE_EXPECT(t3.info()->is_resizable(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(t3.buffer() == nullptr, framework::LogLevel::ERRORS); +} + +TEST_SUITE_END() +TEST_SUITE_END() +TEST_SUITE_END() +} // namespace validation +} // namespace test +} // namespace arm_compute diff --git a/tests/validation/NEON/UNIT/TensorAllocator.cpp b/tests/validation/NEON/UNIT/TensorAllocator.cpp index 4732f3f088..872054f3d1 100644 --- a/tests/validation/NEON/UNIT/TensorAllocator.cpp +++ b/tests/validation/NEON/UNIT/TensorAllocator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017-2018 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -24,6 +24,7 @@ #include "arm_compute/runtime/TensorAllocator.h" #include "arm_compute/runtime/MemoryGroup.h" +#include "arm_compute/runtime/MemoryRegion.h" #include "support/ToolchainSupport.h" #include "tests/Utils.h" #include "tests/framework/Asserts.h" @@ -45,10 +46,7 @@ TEST_CASE(ImportMemory, framework::DatasetMode::ALL) TensorInfo info(TensorShape(24U, 16U, 3U), 1, DataType::F32); // Allocate memory buffer - std::shared_ptr buf(new uint8_t[info.total_size()](), [](uint8_t *ptr) - { - delete[] ptr; - }); + auto buf = std::make_shared(info.total_size()); // Negative case : Import empty memory Tensor t1; @@ -68,7 +66,7 @@ TEST_CASE(ImportMemory, framework::DatasetMode::ALL) t3.allocator()->init(info); ARM_COMPUTE_EXPECT(bool(t3.allocator()->import_memory(Memory(buf.get()))), framework::LogLevel::ERRORS); ARM_COMPUTE_EXPECT(!t3.info()->is_resizable(), framework::LogLevel::ERRORS); - ARM_COMPUTE_EXPECT(t3.buffer() == buf.get(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(t3.buffer() == reinterpret_cast(buf->buffer()), framework::LogLevel::ERRORS); t3.allocator()->free(); ARM_COMPUTE_EXPECT(t3.info()->is_resizable(), framework::LogLevel::ERRORS); ARM_COMPUTE_EXPECT(t3.buffer() == nullptr, framework::LogLevel::ERRORS); @@ -78,7 +76,7 @@ TEST_CASE(ImportMemory, framework::DatasetMode::ALL) t4.allocator()->init(info); ARM_COMPUTE_EXPECT(bool(t4.allocator()->import_memory(Memory(buf))), framework::LogLevel::ERRORS); ARM_COMPUTE_EXPECT(!t4.info()->is_resizable(), framework::LogLevel::ERRORS); - ARM_COMPUTE_EXPECT(t4.buffer() == buf.get(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(t4.buffer() == reinterpret_cast(buf->buffer()), framework::LogLevel::ERRORS); t4.allocator()->free(); ARM_COMPUTE_EXPECT(t4.info()->is_resizable(), framework::LogLevel::ERRORS); ARM_COMPUTE_EXPECT(t4.buffer() == nullptr, framework::LogLevel::ERRORS); -- cgit v1.2.1