From ca5883951ab51191eb19502459f0936fc96e14f1 Mon Sep 17 00:00:00 2001 From: Teresa Charlin Date: Fri, 1 Oct 2021 11:29:08 +0100 Subject: IVGCVSW-6301 Create the MemoryManager class Signed-off-by: Teresa Charlin Signed-off-by: Finn Williams Change-Id: Ia41b5252d695daabd5afaf1b2267444d24be173a --- src/backends/backendsCommon/CMakeLists.txt | 8 +- src/backends/backendsCommon/MemoryManager.cpp | 53 ++++++++++ src/backends/backendsCommon/MemoryManager.hpp | 60 ++++++++++++ src/backends/backendsCommon/test/CMakeLists.txt | 3 +- .../backendsCommon/test/MemoryManagerTests.cpp | 107 +++++++++++++++++++++ 5 files changed, 227 insertions(+), 4 deletions(-) create mode 100644 src/backends/backendsCommon/MemoryManager.cpp create mode 100644 src/backends/backendsCommon/MemoryManager.hpp create mode 100644 src/backends/backendsCommon/test/MemoryManagerTests.cpp (limited to 'src') diff --git a/src/backends/backendsCommon/CMakeLists.txt b/src/backends/backendsCommon/CMakeLists.txt index a18ee330d4..90fb376dae 100644 --- a/src/backends/backendsCommon/CMakeLists.txt +++ b/src/backends/backendsCommon/CMakeLists.txt @@ -1,11 +1,9 @@ # -# Copyright © 2017 Arm Ltd. All rights reserved. +# Copyright © 2017 Arm Ltd and Contributors. All rights reserved. # SPDX-License-Identifier: MIT # list(APPEND armnnBackendsCommon_sources - TensorHandle.cpp - TensorHandle.hpp DynamicBackend.cpp DynamicBackend.hpp DynamicBackendUtils.cpp @@ -29,10 +27,14 @@ list(APPEND armnnBackendsCommon_sources MemoryOptimizerStrategyFactory.hpp MemoryOptimizerStrategyLibrary.cpp MemoryOptimizerStrategyLibrary.hpp + MemoryManager.cpp + MemoryManager.hpp MemSyncWorkload.cpp MemSyncWorkload.hpp OptimizationViews.cpp OptimizationViews.hpp + TensorHandle.cpp + TensorHandle.hpp TensorHandleFactoryRegistry.cpp TensorHandleFactoryRegistry.hpp UnmapWorkload.cpp diff --git a/src/backends/backendsCommon/MemoryManager.cpp b/src/backends/backendsCommon/MemoryManager.cpp new file mode 100644 index 0000000000..1c109c3c91 --- /dev/null +++ b/src/backends/backendsCommon/MemoryManager.cpp @@ -0,0 +1,53 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "MemoryManager.hpp" + +#include + +namespace armnn +{ + +void MemoryManager::StoreMemToAllocate(std::vector bufferStorageVector, + ICustomAllocator* customAllocator, + const size_t typeAlignment) +{ + IgnoreUnused(typeAlignment); + m_AllocatorBufferStoragePairVector.emplace_back(std::make_pair>( + Allocator{customAllocator}, + std::move(bufferStorageVector))); +} + +void MemoryManager::Allocate() +{ + for (auto& m_AllocatorBufferStoragePair : m_AllocatorBufferStoragePairVector) + { + auto& allocator = m_AllocatorBufferStoragePair.first; + for (auto&& bufferStorage : m_AllocatorBufferStoragePair.second) + { + bufferStorage.m_Buffer = allocator.m_CustomAllocator->allocate(bufferStorage.m_BufferSize, 0); + + for (auto tensorMemory : bufferStorage.m_TensorMemoryVector) + { + tensorMemory->m_Data = allocator.m_CustomAllocator->GetMemoryRegionAtOffset(bufferStorage.m_Buffer, + tensorMemory->m_Offset); + } + } + } +} + +void MemoryManager::Deallocate() +{ + for (auto& m_AllocatorBufferStoragePair : m_AllocatorBufferStoragePairVector) + { + auto& allocator = m_AllocatorBufferStoragePair.first; + for (auto&& bufferStorage : m_AllocatorBufferStoragePair.second) + { + allocator.m_CustomAllocator->free(bufferStorage.m_Buffer); + } + } +} + +} // namespace armnn \ No newline at end of file diff --git a/src/backends/backendsCommon/MemoryManager.hpp b/src/backends/backendsCommon/MemoryManager.hpp new file mode 100644 index 0000000000..cbd6fcf9bc --- /dev/null +++ b/src/backends/backendsCommon/MemoryManager.hpp @@ -0,0 +1,60 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include + +namespace armnn +{ +struct Allocator +{ + /// Pointer to @ICustomAllocator. + ICustomAllocator* m_CustomAllocator{}; + /// Value which the size of each buffer (actual data size + padding) has to be a multiple of. + size_t m_Alignment = 0 ; +}; + +struct TensorMemory +{ + /// Number of bytes the value is away from the @BufferStorage.m_Buffer. + size_t m_Offset{}; + /// Pointer to the tensor value. + void* m_Data = nullptr; + /// Identifier to be used by the @LoadedNetwork to order the tensors. + unsigned int m_OutputSlotId{}; +}; + +struct BufferStorage +{ + /// Vector of pointer to @TensorMemory. + std::vector m_TensorMemoryVector; + /// Total size of the buffer. + size_t m_BufferSize; + /// Pointer to the first element of the buffer. + void* m_Buffer = nullptr; +}; + +class MemoryManager +{ +public: + /// Initialization method to store in @m_AllocatorBufferStoragePairVector all information needed. + /// @param[in] bufferStorageVector - Vector of @BufferStorage. + /// @param[in] customAllocator - Pointer to @ICustomAllocator. + /// @param[in] typeAlignment - Optional parameter. Value of which the size of each value has to be multiple of. + void StoreMemToAllocate(std::vector bufferStorageVector, + ICustomAllocator* customAllocator, + size_t typeAlignment = 0); + + /// Allocate the amount of memory indicated by @m_BufferSize, and + /// point each @m_Data to each correspondent Tensor so that they are @m_Offset bytes separated. + void Allocate(); + + /// Deallocate memory + void Deallocate(); + +private: + std::vector>> m_AllocatorBufferStoragePairVector; +}; + +} // namespace armnn diff --git a/src/backends/backendsCommon/test/CMakeLists.txt b/src/backends/backendsCommon/test/CMakeLists.txt index b90407fd7c..9272ae749c 100644 --- a/src/backends/backendsCommon/test/CMakeLists.txt +++ b/src/backends/backendsCommon/test/CMakeLists.txt @@ -13,6 +13,7 @@ list(APPEND armnnBackendsCommonUnitTests_sources ChannelShuffleEndToEndTestImpl.hpp ComparisonEndToEndTestImpl.hpp CompatibilityTests.cpp + ConcatEndToEndTestImpl.hpp Convolution3dEndToEndTestImpl.hpp CustomMemoryOptimizerStrategyTests.cpp DefaultAsyncExecuteTest.cpp @@ -35,7 +36,7 @@ list(APPEND armnnBackendsCommonUnitTests_sources LayerTests.hpp LogSoftmaxEndToEndTestImpl.cpp LogSoftmaxEndToEndTestImpl.hpp - ConcatEndToEndTestImpl.hpp + MemoryManagerTests.cpp MockBackend.cpp MockBackend.hpp MockBackendId.hpp diff --git a/src/backends/backendsCommon/test/MemoryManagerTests.cpp b/src/backends/backendsCommon/test/MemoryManagerTests.cpp new file mode 100644 index 0000000000..b5f2db4009 --- /dev/null +++ b/src/backends/backendsCommon/test/MemoryManagerTests.cpp @@ -0,0 +1,107 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include +#include + +#include +#include + +namespace armnn +{ +/// @brief Class that implements a sample custom allocator. +class SampleCustomAllocator : public armnn::ICustomAllocator +{ +public: + SampleCustomAllocator() = default; + + void* allocate(size_t size, size_t alignment) override + { + IgnoreUnused(alignment); + CHECK(size == m_Values.size()); + m_CounterAllocate+=1; + return m_Values.data(); + } + + void free(void* ptr) override + { + CHECK(ptr == m_Values.data()); + m_CounterFree+=1; + } + + armnn::MemorySource GetMemorySourceType() override + { + return armnn::MemorySource::Malloc; + } + + virtual void* GetMemoryRegionAtOffset(void* buffer, size_t offset, size_t alignment = 0 ) override + { + IgnoreUnused(alignment); + return (static_cast(buffer) + offset); + } + + /// Holds the data in the tensors. Create for testing purposes. + std::vector m_Values; + /// Counts the number of times the function allocate is called. + unsigned long m_CounterAllocate= 0; + /// Counts the number of times the function free is called. + unsigned long m_CounterFree = 0; +}; + +TEST_SUITE("MemoryManagerTests") +{ +/// Unit test Storing, Allocating and Deallocating with a custom allocator. +TEST_CASE("MemoryManagerTest") +{ + using namespace armnn; + + // Create mock up bufferStorageVector with 2 BufferStorage with the same TensorMemory + size_t numTensors = 5; + std::vector tensorMemoryPointerVector(numTensors); + std::vector tensorMemoryVector; + tensorMemoryVector.reserve(numTensors); + + std::vector offsets(numTensors); + std::iota(std::begin(offsets), std::end(offsets), 0); + + for (uint idx = 0; idx < tensorMemoryPointerVector.size(); ++idx) + { + tensorMemoryVector.emplace_back(TensorMemory{offsets[idx], nullptr, 0}); + tensorMemoryPointerVector[idx] = &tensorMemoryVector[idx]; + } + + std::vector bufferStorageVector; + bufferStorageVector.emplace_back(BufferStorage{tensorMemoryPointerVector, numTensors}); + bufferStorageVector.emplace_back(BufferStorage{tensorMemoryPointerVector, numTensors}); + + // Create an instance of the SampleCustomAllocator + SampleCustomAllocator customAllocator = SampleCustomAllocator(); + customAllocator.m_Values = {10, 11, 12, 13, 14}; + // Check that the test was set up correctly + CHECK(customAllocator.m_Values.size() == numTensors); + + // Utilise 3 functions in the MemoryManager. Check the counters and the pointer to the values are correct. + MemoryManager memoryManager; + memoryManager.StoreMemToAllocate(bufferStorageVector, &customAllocator); + + memoryManager.Allocate(); + CHECK(customAllocator.m_CounterAllocate == bufferStorageVector.size()); + for (const auto& bufferStorage : bufferStorageVector) + { + uint idx = 0; + for (auto tensorMemory : bufferStorage.m_TensorMemoryVector) + { + auto value = reinterpret_cast(tensorMemory->m_Data); + CHECK(customAllocator.m_Values[idx] == *value); + idx += 1; + } + } + + memoryManager.Deallocate(); + CHECK(customAllocator.m_CounterFree == bufferStorageVector.size()); +} +} + +} // namespace armnn \ No newline at end of file -- cgit v1.2.1