aboutsummaryrefslogtreecommitdiff
path: root/src/backends/aclCommon/memory
diff options
context:
space:
mode:
Diffstat (limited to 'src/backends/aclCommon/memory')
-rw-r--r--src/backends/aclCommon/memory/BaseMemoryManager.cpp125
-rw-r--r--src/backends/aclCommon/memory/BaseMemoryManager.hpp104
-rw-r--r--src/backends/aclCommon/memory/BlobLifetimeManager.cpp79
-rw-r--r--src/backends/aclCommon/memory/BlobLifetimeManager.hpp35
-rw-r--r--src/backends/aclCommon/memory/BlobMemoryPool.cpp88
-rw-r--r--src/backends/aclCommon/memory/BlobMemoryPool.hpp55
-rw-r--r--src/backends/aclCommon/memory/IMemoryPool.hpp22
-rw-r--r--src/backends/aclCommon/memory/IPoolManager.hpp21
-rw-r--r--src/backends/aclCommon/memory/OffsetLifetimeManager.cpp62
-rw-r--r--src/backends/aclCommon/memory/OffsetLifetimeManager.hpp37
-rw-r--r--src/backends/aclCommon/memory/OffsetMemoryPool.cpp84
-rw-r--r--src/backends/aclCommon/memory/OffsetMemoryPool.hpp54
-rw-r--r--src/backends/aclCommon/memory/PoolManager.cpp105
-rw-r--r--src/backends/aclCommon/memory/PoolManager.hpp57
14 files changed, 928 insertions, 0 deletions
diff --git a/src/backends/aclCommon/memory/BaseMemoryManager.cpp b/src/backends/aclCommon/memory/BaseMemoryManager.cpp
new file mode 100644
index 0000000000..532692b1ce
--- /dev/null
+++ b/src/backends/aclCommon/memory/BaseMemoryManager.cpp
@@ -0,0 +1,125 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#include "BaseMemoryManager.hpp"
+
+#if defined(ARMCOMPUTENEON_ENABLED) || defined(ARMCOMPUTECL_ENABLED)
+#include "BlobLifetimeManager.hpp"
+#include "PoolManager.hpp"
+#include "OffsetLifetimeManager.hpp"
+#endif
+
+#include <boost/polymorphic_cast.hpp>
+
+namespace armnn
+{
+
+#if defined(ARMCOMPUTENEON_ENABLED) || defined(ARMCOMPUTECL_ENABLED)
+BaseMemoryManager::BaseMemoryManager(std::unique_ptr<arm_compute::IAllocator> alloc,
+ MemoryAffinity memoryAffinity)
+{
+ // (Re)create the memory manager components.
+ m_Allocator = std::move(alloc);
+
+ m_IntraLayerMemoryMgr = CreateArmComputeMemoryManager(memoryAffinity);
+ m_InterLayerMemoryMgr = CreateArmComputeMemoryManager(memoryAffinity);
+}
+
+std::shared_ptr<arm_compute::MemoryManagerOnDemand>
+BaseMemoryManager::CreateArmComputeMemoryManager(MemoryAffinity memoryAffinity)
+{
+ std::shared_ptr<arm_compute::ILifetimeManager> lifetimeManager = nullptr;
+
+ if (memoryAffinity == MemoryAffinity::Buffer)
+ {
+ lifetimeManager = std::make_shared<BlobLifetimeManager>();
+ }
+ else
+ {
+ lifetimeManager = std::make_shared<OffsetLifetimeManager>();
+ }
+
+ auto poolManager = std::make_shared<PoolManager>();
+ auto memoryManager = std::make_shared<arm_compute::MemoryManagerOnDemand>(lifetimeManager, poolManager);
+
+ // Set allocator that the memory manager will use
+ memoryManager->set_allocator(m_Allocator.get());
+
+ return memoryManager;
+}
+
+void BaseMemoryManager::FinalizeMemoryManager(arm_compute::MemoryManagerOnDemand& memoryManager)
+{
+ // Number of pools that the manager will create. This specifies how many layers you want to run in parallel
+ memoryManager.set_num_pools(1);
+
+ // Finalize the memory manager. (Validity checks, memory allocations, etc)
+ memoryManager.finalize();
+}
+
+void BaseMemoryManager::Finalize()
+{
+ BOOST_ASSERT(m_IntraLayerMemoryMgr);
+ FinalizeMemoryManager(*m_IntraLayerMemoryMgr.get());
+
+ BOOST_ASSERT(m_InterLayerMemoryMgr);
+ FinalizeMemoryManager(*m_InterLayerMemoryMgr.get());
+}
+
+void BaseMemoryManager::Acquire()
+{
+ // Allocate memory pools for intra-layer memory manager
+ BOOST_ASSERT(m_IntraLayerMemoryMgr);
+ IPoolManager* poolManager = boost::polymorphic_downcast<IPoolManager*>(m_IntraLayerMemoryMgr->pool_manager());
+ BOOST_ASSERT(poolManager);
+ poolManager->AllocatePools();
+
+ // Allocate memory pools for inter-layer memory manager
+ BOOST_ASSERT(m_InterLayerMemoryMgr);
+ poolManager = boost::polymorphic_downcast<IPoolManager*>(m_InterLayerMemoryMgr->pool_manager());
+ BOOST_ASSERT(poolManager);
+ poolManager->AllocatePools();
+
+ // Acquire inter-layer memory group. NOTE: This has to come after allocating the pools
+ BOOST_ASSERT(m_InterLayerMemoryGroup);
+ m_InterLayerMemoryGroup->acquire();
+}
+
+void BaseMemoryManager::Release()
+{
+ // Release inter-layer memory group. NOTE: This has to come before releasing the pools
+ BOOST_ASSERT(m_InterLayerMemoryGroup);
+ m_InterLayerMemoryGroup->release();
+
+ // Release memory pools managed by intra-layer memory manager
+ BOOST_ASSERT(m_IntraLayerMemoryMgr);
+ IPoolManager* poolManager = boost::polymorphic_downcast<IPoolManager*>(m_IntraLayerMemoryMgr->pool_manager());
+ BOOST_ASSERT(poolManager);
+ poolManager->ReleasePools();
+
+ // Release memory pools managed by inter-layer memory manager
+ BOOST_ASSERT(m_InterLayerMemoryMgr);
+ poolManager = boost::polymorphic_downcast<IPoolManager*>(m_InterLayerMemoryMgr->pool_manager());
+ BOOST_ASSERT(poolManager);
+ poolManager->ReleasePools();
+}
+#endif
+
+#ifdef ARMCOMPUTENEON_ENABLED
+std::shared_ptr<arm_compute::IMemoryGroup>
+NeonMemoryManager::CreateMemoryGroup(const std::shared_ptr<arm_compute::MemoryManagerOnDemand>& memoryManager)
+{
+ return std::make_shared<arm_compute::MemoryGroup>(memoryManager);
+}
+#endif
+
+#ifdef ARMCOMPUTECL_ENABLED
+std::shared_ptr<arm_compute::IMemoryGroup>
+ClMemoryManager::CreateMemoryGroup(const std::shared_ptr<arm_compute::MemoryManagerOnDemand>& memoryManager)
+{
+ return std::make_shared<arm_compute::CLMemoryGroup>(memoryManager);
+}
+#endif
+
+}
diff --git a/src/backends/aclCommon/memory/BaseMemoryManager.hpp b/src/backends/aclCommon/memory/BaseMemoryManager.hpp
new file mode 100644
index 0000000000..2afc1cb130
--- /dev/null
+++ b/src/backends/aclCommon/memory/BaseMemoryManager.hpp
@@ -0,0 +1,104 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include <backends/WorkloadFactory.hpp>
+
+#ifdef ARMCOMPUTENEON_ENABLED
+#include <arm_compute/runtime/MemoryGroup.h>
+#endif
+
+#ifdef ARMCOMPUTECL_ENABLED
+#include <arm_compute/runtime/CL/CLMemoryGroup.h>
+#endif
+
+#if defined(ARMCOMPUTENEON_ENABLED) || defined(ARMCOMPUTECL_ENABLED)
+#include <arm_compute/runtime/IAllocator.h>
+#include <arm_compute/runtime/IMemoryGroup.h>
+#include <arm_compute/runtime/MemoryManagerOnDemand.h>
+#endif
+
+namespace armnn
+{
+
+class BaseMemoryManager
+{
+public:
+ enum class MemoryAffinity
+ {
+ Buffer,
+ Offset
+ };
+
+ BaseMemoryManager() { }
+ virtual ~BaseMemoryManager() { }
+
+#if defined(ARMCOMPUTENEON_ENABLED) || defined(ARMCOMPUTECL_ENABLED)
+
+ BaseMemoryManager(std::unique_ptr<arm_compute::IAllocator> alloc, MemoryAffinity memoryAffinity);
+
+ std::shared_ptr<arm_compute::MemoryManagerOnDemand>& GetIntraLayerManager() { return m_IntraLayerMemoryMgr; }
+ std::shared_ptr<arm_compute::MemoryManagerOnDemand>& GetInterLayerManager() { return m_InterLayerMemoryMgr; }
+ std::shared_ptr<arm_compute::IMemoryGroup>& GetInterLayerMemoryGroup() { return m_InterLayerMemoryGroup; }
+
+ void Finalize();
+ void Acquire();
+ void Release();
+
+protected:
+
+ std::unique_ptr<arm_compute::IAllocator> m_Allocator;
+ std::shared_ptr<arm_compute::MemoryManagerOnDemand> m_IntraLayerMemoryMgr;
+ std::shared_ptr<arm_compute::MemoryManagerOnDemand> m_InterLayerMemoryMgr;
+ std::shared_ptr<arm_compute::IMemoryGroup> m_InterLayerMemoryGroup;
+
+ std::shared_ptr<arm_compute::MemoryManagerOnDemand> CreateArmComputeMemoryManager(MemoryAffinity memoryAffinity);
+
+ virtual std::shared_ptr<arm_compute::IMemoryGroup>
+ CreateMemoryGroup(const std::shared_ptr<arm_compute::MemoryManagerOnDemand>& memoryManager) = 0;
+
+ void FinalizeMemoryManager(arm_compute::MemoryManagerOnDemand& memoryManager);
+#endif
+};
+
+class NeonMemoryManager : public BaseMemoryManager
+{
+public:
+ NeonMemoryManager() {}
+ virtual ~NeonMemoryManager() {}
+
+#ifdef ARMCOMPUTENEON_ENABLED
+ NeonMemoryManager(std::unique_ptr<arm_compute::IAllocator> alloc, MemoryAffinity memoryAffinity)
+ : BaseMemoryManager(std::move(alloc), memoryAffinity)
+ {
+ m_InterLayerMemoryGroup = CreateMemoryGroup(m_InterLayerMemoryMgr);
+ }
+
+protected:
+ virtual std::shared_ptr<arm_compute::IMemoryGroup>
+ CreateMemoryGroup(const std::shared_ptr<arm_compute::MemoryManagerOnDemand>& memoryManager) override;
+#endif
+};
+
+class ClMemoryManager : public BaseMemoryManager
+{
+public:
+ ClMemoryManager() {}
+ virtual ~ClMemoryManager() {}
+
+#ifdef ARMCOMPUTECL_ENABLED
+ ClMemoryManager(std::unique_ptr<arm_compute::IAllocator> alloc)
+ : BaseMemoryManager(std::move(alloc), MemoryAffinity::Buffer)
+ {
+ m_InterLayerMemoryGroup = CreateMemoryGroup(m_InterLayerMemoryMgr);
+ }
+
+protected:
+ virtual std::shared_ptr<arm_compute::IMemoryGroup>
+ CreateMemoryGroup(const std::shared_ptr<arm_compute::MemoryManagerOnDemand>& memoryManager) override;
+#endif
+};
+
+} //namespace armnn
diff --git a/src/backends/aclCommon/memory/BlobLifetimeManager.cpp b/src/backends/aclCommon/memory/BlobLifetimeManager.cpp
new file mode 100644
index 0000000000..41100e945f
--- /dev/null
+++ b/src/backends/aclCommon/memory/BlobLifetimeManager.cpp
@@ -0,0 +1,79 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#include "BlobLifetimeManager.hpp"
+#include "BlobMemoryPool.hpp"
+
+#include <arm_compute/runtime/IMemoryGroup.h>
+
+#include "boost/assert.hpp"
+
+#include <algorithm>
+
+namespace armnn
+{
+
+BlobLifetimeManager::BlobLifetimeManager()
+ : m_BlobSizes()
+{
+}
+
+arm_compute::MappingType BlobLifetimeManager::mapping_type() const
+{
+ return arm_compute::MappingType::BLOBS;
+}
+
+void BlobLifetimeManager::update_blobs_and_mappings()
+{
+ using namespace arm_compute;
+
+ BOOST_ASSERT(are_all_finalized());
+ BOOST_ASSERT(_active_group);
+
+ // Sort free blobs requirements in descending order.
+ _free_blobs.sort([](const Blob & ba, const Blob & bb)
+ {
+ return ba.max_size > bb.max_size;
+ });
+ std::vector<size_t> groupSizes;
+ std::transform(std::begin(_free_blobs), std::end(_free_blobs), std::back_inserter(groupSizes), [](const Blob & b)
+ {
+ return b.max_size;
+ });
+
+ // Update blob sizes
+ size_t max_size = std::max(m_BlobSizes.size(), groupSizes.size());
+ m_BlobSizes.resize(max_size, 0);
+ groupSizes.resize(max_size, 0);
+ std::transform(std::begin(m_BlobSizes), std::end(m_BlobSizes), std::begin(groupSizes),
+ std::begin(m_BlobSizes), [](size_t lhs, size_t rhs)
+ {
+ return std::max(lhs, rhs);
+ });
+
+ // Calculate group mappings
+ auto& groupMappings = _active_group->mappings();
+ unsigned int blobIdx = 0;
+
+ for(auto& freeBlob : _free_blobs)
+ {
+ for(auto& boundElementId : freeBlob.bound_elements)
+ {
+ BOOST_ASSERT(_active_elements.find(boundElementId) != std::end(_active_elements));
+
+ Element& boundElement = _active_elements[boundElementId];
+ groupMappings[boundElement.handle] = blobIdx;
+ }
+
+ ++blobIdx;
+ }
+}
+
+std::unique_ptr<arm_compute::IMemoryPool> BlobLifetimeManager::create_pool(arm_compute::IAllocator* allocator)
+{
+ BOOST_ASSERT(allocator);
+ return std::make_unique<BlobMemoryPool>(allocator, m_BlobSizes);
+}
+
+} // namespace armnn \ No newline at end of file
diff --git a/src/backends/aclCommon/memory/BlobLifetimeManager.hpp b/src/backends/aclCommon/memory/BlobLifetimeManager.hpp
new file mode 100644
index 0000000000..d777ba59ee
--- /dev/null
+++ b/src/backends/aclCommon/memory/BlobLifetimeManager.hpp
@@ -0,0 +1,35 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include <arm_compute/runtime/ISimpleLifetimeManager.h>
+
+namespace armnn
+{
+
+class BlobLifetimeManager : public arm_compute::ISimpleLifetimeManager
+{
+public:
+ BlobLifetimeManager();
+
+ BlobLifetimeManager(const BlobLifetimeManager&) = delete;
+
+ BlobLifetimeManager& operator=(const BlobLifetimeManager&) = delete;
+
+ BlobLifetimeManager(BlobLifetimeManager&&) = default;
+
+ BlobLifetimeManager& operator=(BlobLifetimeManager&&) = default;
+
+ std::unique_ptr<arm_compute::IMemoryPool> create_pool(arm_compute::IAllocator* allocator) override;
+
+ arm_compute::MappingType mapping_type() const override;
+
+private:
+ void update_blobs_and_mappings() override;
+
+ std::vector<size_t> m_BlobSizes;
+};
+
+} // namespace armnn \ No newline at end of file
diff --git a/src/backends/aclCommon/memory/BlobMemoryPool.cpp b/src/backends/aclCommon/memory/BlobMemoryPool.cpp
new file mode 100644
index 0000000000..8b0a957bb0
--- /dev/null
+++ b/src/backends/aclCommon/memory/BlobMemoryPool.cpp
@@ -0,0 +1,88 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#include "BlobMemoryPool.hpp"
+
+#include <boost/assert.hpp>
+
+namespace armnn
+{
+
+BlobMemoryPool::BlobMemoryPool(arm_compute::IAllocator* allocator, std::vector<size_t> blobSizes)
+ : m_Allocator(allocator)
+ , m_Blobs()
+ , m_BlobSizes(std::move(blobSizes))
+ , m_MemoryAllocated(false)
+{
+ AllocatePool();
+}
+
+BlobMemoryPool::~BlobMemoryPool()
+{
+ ReleasePool();
+}
+
+void BlobMemoryPool::acquire(arm_compute::MemoryMappings& handles)
+{
+ // Set memory to handlers
+ for (auto& handle : handles)
+ {
+ BOOST_ASSERT(handle.first);
+ *handle.first = m_Blobs[handle.second];
+ }
+}
+
+void BlobMemoryPool::release(arm_compute::MemoryMappings &handles)
+{
+ for (auto& handle : handles)
+ {
+ BOOST_ASSERT(handle.first);
+ *handle.first = nullptr;
+ }
+}
+
+arm_compute::MappingType BlobMemoryPool::mapping_type() const
+{
+ return arm_compute::MappingType::BLOBS;
+}
+
+std::unique_ptr<arm_compute::IMemoryPool> BlobMemoryPool::duplicate()
+{
+ BOOST_ASSERT(m_Allocator);
+ return std::make_unique<BlobMemoryPool>(m_Allocator, m_BlobSizes);
+}
+
+void BlobMemoryPool::AllocatePool()
+{
+ if (!m_MemoryAllocated)
+ {
+ BOOST_ASSERT(m_Allocator);
+
+ for (const auto& blobSize : m_BlobSizes)
+ {
+ m_Blobs.push_back(m_Allocator->allocate(blobSize, 0));
+ }
+
+ m_MemoryAllocated = true;
+ }
+}
+
+void BlobMemoryPool::ReleasePool()
+{
+ if (m_MemoryAllocated)
+ {
+ BOOST_ASSERT(m_Allocator);
+
+ for (auto& blob : m_Blobs)
+ {
+ m_Allocator->free(blob);
+ }
+
+ m_Blobs.clear();
+
+ m_MemoryAllocated = false;
+ }
+}
+
+} // namespace armnn \ No newline at end of file
diff --git a/src/backends/aclCommon/memory/BlobMemoryPool.hpp b/src/backends/aclCommon/memory/BlobMemoryPool.hpp
new file mode 100644
index 0000000000..4d42e6ee7a
--- /dev/null
+++ b/src/backends/aclCommon/memory/BlobMemoryPool.hpp
@@ -0,0 +1,55 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include "IMemoryPool.hpp"
+
+#include <arm_compute/runtime/IAllocator.h>
+#include <arm_compute/runtime/Types.h>
+
+namespace armnn
+{
+
+/** Blob memory pool */
+class BlobMemoryPool : public IMemoryPool
+{
+public:
+ BlobMemoryPool(arm_compute::IAllocator* allocator, std::vector<size_t> blobSizes);
+
+ ~BlobMemoryPool();
+
+ BlobMemoryPool(const BlobMemoryPool&) = delete;
+
+ BlobMemoryPool& operator=(const BlobMemoryPool&) = delete;
+
+ BlobMemoryPool(BlobMemoryPool&&) = default;
+
+ BlobMemoryPool& operator=(BlobMemoryPool&&) = default;
+
+ void acquire(arm_compute::MemoryMappings &handles) override;
+ void release(arm_compute::MemoryMappings &handles) override;
+
+ arm_compute::MappingType mapping_type() const override;
+
+ std::unique_ptr<arm_compute::IMemoryPool> duplicate() override;
+
+ void AllocatePool() override;
+ void ReleasePool() override;
+
+private:
+ /// Allocator to use for internal allocation
+ arm_compute::IAllocator* m_Allocator;
+
+ /// Vector holding all the memory blobs
+ std::vector<void*> m_Blobs;
+
+ /// Sizes of each memory blob
+ std::vector<size_t> m_BlobSizes;
+
+ /// Flag indicating whether memory has been allocated for the pool
+ bool m_MemoryAllocated;
+};
+
+} // namespace armnn \ No newline at end of file
diff --git a/src/backends/aclCommon/memory/IMemoryPool.hpp b/src/backends/aclCommon/memory/IMemoryPool.hpp
new file mode 100644
index 0000000000..99130699e0
--- /dev/null
+++ b/src/backends/aclCommon/memory/IMemoryPool.hpp
@@ -0,0 +1,22 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include <arm_compute/runtime/IMemoryPool.h>
+
+namespace armnn
+{
+
+class IMemoryPool : public arm_compute::IMemoryPool
+{
+public:
+ /// Allocates memory for the entire pool
+ virtual void AllocatePool() = 0;
+
+ /// Releases all memory associated with the pool
+ virtual void ReleasePool() = 0;
+};
+
+} // namespace armnn \ No newline at end of file
diff --git a/src/backends/aclCommon/memory/IPoolManager.hpp b/src/backends/aclCommon/memory/IPoolManager.hpp
new file mode 100644
index 0000000000..be15fdd57e
--- /dev/null
+++ b/src/backends/aclCommon/memory/IPoolManager.hpp
@@ -0,0 +1,21 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include <arm_compute/runtime/IPoolManager.h>
+
+namespace armnn
+{
+
+class IPoolManager : public arm_compute::IPoolManager {
+public:
+ // Allocates all pools within the pool manager
+ virtual void AllocatePools() = 0;
+
+ // Releases all pools within the pool manager
+ virtual void ReleasePools() = 0;
+};
+
+} // namespace armnn \ No newline at end of file
diff --git a/src/backends/aclCommon/memory/OffsetLifetimeManager.cpp b/src/backends/aclCommon/memory/OffsetLifetimeManager.cpp
new file mode 100644
index 0000000000..d0174f893c
--- /dev/null
+++ b/src/backends/aclCommon/memory/OffsetLifetimeManager.cpp
@@ -0,0 +1,62 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#include "OffsetLifetimeManager.hpp"
+#include "OffsetMemoryPool.hpp"
+
+#include <arm_compute/runtime/IMemoryGroup.h>
+
+#include <numeric>
+
+#include <boost/assert.hpp>
+
+namespace armnn
+{
+
+OffsetLifetimeManager::OffsetLifetimeManager()
+ : m_BlobSize(0)
+{
+}
+
+std::unique_ptr<arm_compute::IMemoryPool> OffsetLifetimeManager::create_pool(arm_compute::IAllocator* allocator)
+{
+ BOOST_ASSERT(allocator);
+ return std::make_unique<OffsetMemoryPool>(allocator, m_BlobSize);
+}
+
+arm_compute::MappingType OffsetLifetimeManager::mapping_type() const
+{
+ return arm_compute::MappingType::OFFSETS;
+}
+
+void OffsetLifetimeManager::update_blobs_and_mappings()
+{
+ BOOST_ASSERT(are_all_finalized());
+ BOOST_ASSERT(_active_group);
+
+ // Update blob size
+ size_t maxGroupSize = std::accumulate(std::begin(_free_blobs), std::end(_free_blobs),
+ static_cast<size_t>(0), [](size_t s, const Blob& b)
+ {
+ return s + b.max_size;
+ });
+ m_BlobSize = std::max(m_BlobSize, maxGroupSize);
+
+ // Calculate group mappings
+ auto& groupMappings = _active_group->mappings();
+ size_t offset = 0;
+ for(auto& freeBlob : _free_blobs)
+ {
+ for(auto& boundElementId : freeBlob.bound_elements)
+ {
+ BOOST_ASSERT(_active_elements.find(boundElementId) != std::end(_active_elements));
+ Element& boundElement = _active_elements[boundElementId];
+ groupMappings[boundElement.handle] = offset;
+ }
+ offset += freeBlob.max_size;
+ BOOST_ASSERT(offset <= m_BlobSize);
+ }
+}
+
+} // namespace armnn \ No newline at end of file
diff --git a/src/backends/aclCommon/memory/OffsetLifetimeManager.hpp b/src/backends/aclCommon/memory/OffsetLifetimeManager.hpp
new file mode 100644
index 0000000000..1283193052
--- /dev/null
+++ b/src/backends/aclCommon/memory/OffsetLifetimeManager.hpp
@@ -0,0 +1,37 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include <arm_compute/runtime/ISimpleLifetimeManager.h>
+
+namespace armnn
+{
+
+class OffsetLifetimeManager : public arm_compute::ISimpleLifetimeManager
+{
+public:
+ OffsetLifetimeManager();
+
+ OffsetLifetimeManager(const OffsetLifetimeManager&) = delete;
+
+ OffsetLifetimeManager& operator=(const OffsetLifetimeManager&) = delete;
+
+ OffsetLifetimeManager(OffsetLifetimeManager&&) = default;
+
+ OffsetLifetimeManager& operator=(OffsetLifetimeManager&&) = default;
+
+ std::unique_ptr<arm_compute::IMemoryPool> create_pool(arm_compute::IAllocator* allocator) override;
+
+ arm_compute::MappingType mapping_type() const override;
+
+private:
+ void update_blobs_and_mappings() override;
+
+private:
+ /// Memory blob size
+ size_t m_BlobSize;
+};
+
+} // namespace armnn \ No newline at end of file
diff --git a/src/backends/aclCommon/memory/OffsetMemoryPool.cpp b/src/backends/aclCommon/memory/OffsetMemoryPool.cpp
new file mode 100644
index 0000000000..48bea5e845
--- /dev/null
+++ b/src/backends/aclCommon/memory/OffsetMemoryPool.cpp
@@ -0,0 +1,84 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#include "OffsetMemoryPool.hpp"
+
+#include <boost/assert.hpp>
+
+#include <algorithm>
+
+namespace armnn
+{
+
+OffsetMemoryPool::OffsetMemoryPool(arm_compute::IAllocator* allocator, size_t blobSize)
+ : m_Allocator(allocator)
+ , m_Blob()
+ , m_BlobSize(blobSize)
+ , m_MemoryAllocated(false)
+{
+ AllocatePool();
+}
+
+OffsetMemoryPool::~OffsetMemoryPool()
+{
+ ReleasePool();
+}
+
+void OffsetMemoryPool::acquire(arm_compute::MemoryMappings& handles)
+{
+ BOOST_ASSERT(m_Blob);
+
+ // Set memory to handlers
+ for(auto& handle : handles)
+ {
+ BOOST_ASSERT(handle.first);
+ *handle.first = reinterpret_cast<uint8_t*>(m_Blob) + handle.second;
+ }
+}
+
+void OffsetMemoryPool::release(arm_compute::MemoryMappings &handles)
+{
+ for(auto& handle : handles)
+ {
+ BOOST_ASSERT(handle.first);
+ *handle.first = nullptr;
+ }
+}
+
+arm_compute::MappingType OffsetMemoryPool::mapping_type() const
+{
+ return arm_compute::MappingType::OFFSETS;
+}
+
+std::unique_ptr<arm_compute::IMemoryPool> OffsetMemoryPool::duplicate()
+{
+ BOOST_ASSERT(m_Allocator);
+ return std::make_unique<OffsetMemoryPool>(m_Allocator, m_BlobSize);
+}
+
+void OffsetMemoryPool::AllocatePool()
+{
+ if (!m_MemoryAllocated)
+ {
+ BOOST_ASSERT(m_Allocator);
+ m_Blob = m_Allocator->allocate(m_BlobSize, 0);
+
+ m_MemoryAllocated = true;
+ }
+}
+
+void OffsetMemoryPool::ReleasePool()
+{
+ if (m_MemoryAllocated)
+ {
+ BOOST_ASSERT(m_Allocator);
+
+ m_Allocator->free(m_Blob);
+ m_Blob = nullptr;
+
+ m_MemoryAllocated = false;
+ }
+}
+
+} // namespace armnn \ No newline at end of file
diff --git a/src/backends/aclCommon/memory/OffsetMemoryPool.hpp b/src/backends/aclCommon/memory/OffsetMemoryPool.hpp
new file mode 100644
index 0000000000..25cf8cd638
--- /dev/null
+++ b/src/backends/aclCommon/memory/OffsetMemoryPool.hpp
@@ -0,0 +1,54 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include "IMemoryPool.hpp"
+
+#include <arm_compute/runtime/IAllocator.h>
+#include <arm_compute/runtime/Types.h>
+
+namespace armnn
+{
+
+class OffsetMemoryPool : public IMemoryPool
+{
+public:
+ OffsetMemoryPool(arm_compute::IAllocator* allocator, size_t blobSize);
+
+ ~OffsetMemoryPool();
+
+ OffsetMemoryPool(const OffsetMemoryPool&) = delete;
+
+ OffsetMemoryPool& operator=(const OffsetMemoryPool&) = delete;
+
+ OffsetMemoryPool(OffsetMemoryPool&&) = default;
+
+ OffsetMemoryPool& operator=(OffsetMemoryPool &&) = default;
+
+ void acquire(arm_compute::MemoryMappings& handles) override;
+ void release(arm_compute::MemoryMappings& handles) override;
+
+ arm_compute::MappingType mapping_type() const override;
+
+ std::unique_ptr<arm_compute::IMemoryPool> duplicate() override;
+
+ void AllocatePool() override;
+ void ReleasePool() override;
+
+private:
+ /// Allocator to use for internal allocation
+ arm_compute::IAllocator* m_Allocator;
+
+ /// Memory blob
+ void* m_Blob;
+
+ /// Size of the allocated memory blob
+ size_t m_BlobSize;
+
+ /// Flag indicating whether memory has been allocated for the pool
+ bool m_MemoryAllocated;
+};
+
+} // namespace armnn \ No newline at end of file
diff --git a/src/backends/aclCommon/memory/PoolManager.cpp b/src/backends/aclCommon/memory/PoolManager.cpp
new file mode 100644
index 0000000000..363b4590b3
--- /dev/null
+++ b/src/backends/aclCommon/memory/PoolManager.cpp
@@ -0,0 +1,105 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#include "IMemoryPool.hpp"
+#include "PoolManager.hpp"
+
+#include <boost/assert.hpp>
+#include <boost/polymorphic_cast.hpp>
+
+#include <algorithm>
+
+namespace armnn
+{
+
+PoolManager::PoolManager()
+ : m_FreePools()
+ , m_OccupiedPools()
+ , m_Semaphore()
+ , m_Mutex()
+{}
+
+arm_compute::IMemoryPool *PoolManager::lock_pool()
+{
+ BOOST_ASSERT_MSG(!(m_FreePools.empty() && m_OccupiedPools.empty()), "Haven't setup any pools");
+
+ m_Semaphore->wait();
+ std::lock_guard<arm_compute::Mutex> lock(m_Mutex);
+
+ BOOST_ASSERT_MSG(!m_FreePools.empty(), "Empty pool must exist as semaphore has been signalled");
+ m_OccupiedPools.splice(std::begin(m_OccupiedPools), m_FreePools, std::begin(m_FreePools));
+
+ return m_OccupiedPools.front().get();
+}
+
+void PoolManager::unlock_pool(arm_compute::IMemoryPool *pool)
+{
+ BOOST_ASSERT_MSG(!(m_FreePools.empty() && m_OccupiedPools.empty()), "Haven't setup any pools!");
+
+ std::lock_guard<arm_compute::Mutex> lock(m_Mutex);
+
+ auto it = std::find_if(
+ std::begin(m_OccupiedPools),
+ std::end(m_OccupiedPools),
+ [pool](const std::unique_ptr<arm_compute::IMemoryPool> &poolIterator)
+ {
+ return poolIterator.get() == pool;
+ }
+ );
+
+ BOOST_ASSERT_MSG(it != std::end(m_OccupiedPools), "Pool to be unlocked couldn't be found");
+ m_FreePools.splice(std::begin(m_FreePools), m_OccupiedPools, it);
+ m_Semaphore->signal();
+}
+
+void PoolManager::register_pool(std::unique_ptr<arm_compute::IMemoryPool> pool)
+{
+ std::lock_guard<arm_compute::Mutex> lock(m_Mutex);
+ BOOST_ASSERT_MSG(m_OccupiedPools.empty(), "All pools should be free in order to register a new one");
+
+ // Set pool
+ m_FreePools.push_front(std::move(pool));
+
+ // Update semaphore
+ m_Semaphore = std::make_unique<arm_compute::Semaphore>(m_FreePools.size());
+}
+
+size_t PoolManager::num_pools() const
+{
+ std::lock_guard<arm_compute::Mutex> lock(m_Mutex);
+
+ return m_FreePools.size() + m_OccupiedPools.size();
+}
+
+void PoolManager::AllocatePools()
+{
+ std::lock_guard<arm_compute::Mutex> lock(m_Mutex);
+
+ for (auto& pool : m_FreePools)
+ {
+ boost::polymorphic_downcast<IMemoryPool*>(pool.get())->AllocatePool();
+ }
+
+ for (auto& pool : m_OccupiedPools)
+ {
+ boost::polymorphic_downcast<IMemoryPool*>(pool.get())->AllocatePool();
+ }
+}
+
+void PoolManager::ReleasePools()
+{
+ std::lock_guard<arm_compute::Mutex> lock(m_Mutex);
+
+ for (auto& pool : m_FreePools)
+ {
+ boost::polymorphic_downcast<IMemoryPool*>(pool.get())->ReleasePool();
+ }
+
+ for (auto& pool : m_OccupiedPools)
+ {
+ boost::polymorphic_downcast<IMemoryPool*>(pool.get())->ReleasePool();
+ }
+}
+
+} //namespace armnn \ No newline at end of file
diff --git a/src/backends/aclCommon/memory/PoolManager.hpp b/src/backends/aclCommon/memory/PoolManager.hpp
new file mode 100644
index 0000000000..39bc665415
--- /dev/null
+++ b/src/backends/aclCommon/memory/PoolManager.hpp
@@ -0,0 +1,57 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include "IPoolManager.hpp"
+
+#include <arm_compute/runtime/IMemoryPool.h>
+#include <arm_compute/core/Error.h>
+
+#include <support/Mutex.h>
+#include <support/Semaphore.h>
+
+#include <cstddef>
+#include <list>
+#include <memory>
+
+namespace armnn
+{
+
+class PoolManager : public IPoolManager
+{
+public:
+ PoolManager();
+
+ PoolManager(const PoolManager &) = delete;
+
+ PoolManager &operator=(const PoolManager &) = delete;
+
+ PoolManager(PoolManager &&) = default;
+
+ PoolManager &operator=(PoolManager &&) = default;
+
+ arm_compute::IMemoryPool *lock_pool() override;
+ void unlock_pool(arm_compute::IMemoryPool *pool) override;
+ void register_pool(std::unique_ptr<arm_compute::IMemoryPool> pool) override;
+ size_t num_pools() const override;
+
+ void AllocatePools() override;
+ void ReleasePools() override;
+
+private:
+ /// List of free pools
+ std::list<std::unique_ptr<arm_compute::IMemoryPool>> m_FreePools;
+
+ /// List of occupied pools
+ std::list<std::unique_ptr<arm_compute::IMemoryPool>> m_OccupiedPools;
+
+ /// Semaphore to control the queues
+ std::unique_ptr<arm_compute::Semaphore> m_Semaphore;
+
+ /// Mutex to control access to the queues
+ mutable arm_compute::Mutex m_Mutex;
+};
+
+} // namespace armnn \ No newline at end of file