From e1fdd2866b0f403b5e80994890d62c2c038c16c9 Mon Sep 17 00:00:00 2001 From: Jim Flynn Date: Tue, 26 Oct 2021 21:26:10 +0100 Subject: IVGCVSW-6470 Create MemoryStrategyBenchmark * Refactor the strategy library to be more generic * Shorten the names of the current strategies * Change validatorStrat to throw exceptions Change-Id: I0d9c9ef609b2d8675e5788610d1accac6767c660 Signed-off-by: Finn Williams Signed-off-by: Jim Flynn --- .../memoryOptimizerStrategyLibrary/CMakeLists.txt | 19 ++ .../MemoryOptimizerStrategyFactory.hpp | 28 ++ .../MemoryOptimizerStrategyLibrary.hpp | 52 ++++ .../strategies/ConstantMemoryStrategy.cpp | 43 ++++ .../strategies/ConstantMemoryStrategy.hpp | 31 +++ .../strategies/StrategyValidator.cpp | 132 ++++++++++ .../strategies/StrategyValidator.hpp | 41 +++ .../test/CMakeLists.txt | 12 + .../test/ConstMemoryStrategyTests.cpp | 77 ++++++ .../test/ValidatorStrategyTests.cpp | 283 +++++++++++++++++++++ 10 files changed, 718 insertions(+) create mode 100644 src/backends/backendsCommon/memoryOptimizerStrategyLibrary/CMakeLists.txt create mode 100644 src/backends/backendsCommon/memoryOptimizerStrategyLibrary/MemoryOptimizerStrategyFactory.hpp create mode 100644 src/backends/backendsCommon/memoryOptimizerStrategyLibrary/MemoryOptimizerStrategyLibrary.hpp create mode 100644 src/backends/backendsCommon/memoryOptimizerStrategyLibrary/strategies/ConstantMemoryStrategy.cpp create mode 100644 src/backends/backendsCommon/memoryOptimizerStrategyLibrary/strategies/ConstantMemoryStrategy.hpp create mode 100644 src/backends/backendsCommon/memoryOptimizerStrategyLibrary/strategies/StrategyValidator.cpp create mode 100644 src/backends/backendsCommon/memoryOptimizerStrategyLibrary/strategies/StrategyValidator.hpp create mode 100644 src/backends/backendsCommon/memoryOptimizerStrategyLibrary/test/CMakeLists.txt create mode 100644 src/backends/backendsCommon/memoryOptimizerStrategyLibrary/test/ConstMemoryStrategyTests.cpp create mode 100644 src/backends/backendsCommon/memoryOptimizerStrategyLibrary/test/ValidatorStrategyTests.cpp (limited to 'src/backends/backendsCommon/memoryOptimizerStrategyLibrary') diff --git a/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/CMakeLists.txt b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/CMakeLists.txt new file mode 100644 index 0000000000..43ec9db670 --- /dev/null +++ b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/CMakeLists.txt @@ -0,0 +1,19 @@ +# +# Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +# SPDX-License-Identifier: MIT +# + +list(APPEND armnnMemoryOptimizationStrategies_sources + MemoryOptimizerStrategyLibrary.hpp + MemoryOptimizerStrategyFactory.hpp + strategies/ConstantMemoryStrategy.hpp + strategies/ConstantMemoryStrategy.cpp + strategies/StrategyValidator.hpp + strategies/StrategyValidator.cpp +) + +if(BUILD_UNIT_TESTS) + add_subdirectory(test) +endif() + +add_library(armnnMemoryOptimizationStrategies OBJECT ${armnnMemoryOptimizationStrategies_sources}) \ No newline at end of file diff --git a/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/MemoryOptimizerStrategyFactory.hpp b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/MemoryOptimizerStrategyFactory.hpp new file mode 100644 index 0000000000..aff0995266 --- /dev/null +++ b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/MemoryOptimizerStrategyFactory.hpp @@ -0,0 +1,28 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include + +#include + +namespace armnn +{ + +class MemoryOptimizerStrategyFactory +{ +public: + MemoryOptimizerStrategyFactory() {} + + template + std::unique_ptr CreateMemoryOptimizerStrategy() + { + return std::make_unique(); + } + +}; + +} // namespace armnn \ No newline at end of file diff --git a/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/MemoryOptimizerStrategyLibrary.hpp b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/MemoryOptimizerStrategyLibrary.hpp new file mode 100644 index 0000000000..5e20a9f218 --- /dev/null +++ b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/MemoryOptimizerStrategyLibrary.hpp @@ -0,0 +1,52 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// +#pragma once + +#include +#include "MemoryOptimizerStrategyFactory.hpp" +#include + +#include "strategies/ConstantMemoryStrategy.hpp" +#include "strategies/StrategyValidator.hpp" + +namespace +{ +// Default Memory Optimizer Strategies +static const std::vector memoryOptimizationStrategies( +{ + "ConstantMemoryStrategy", + "StrategyValidator" +}); + +#define CREATE_MEMORY_OPTIMIZER_STRATEGY(strategyName, memoryOptimizerStrategy) \ +{ \ + MemoryOptimizerStrategyFactory memoryOptimizerStrategyFactory; \ + memoryOptimizerStrategy = memoryOptimizerStrategyFactory.CreateMemoryOptimizerStrategy(); \ +} \ + +} // anonymous namespace +namespace armnn +{ + std::unique_ptr GetMemoryOptimizerStrategy(const std::string& strategyName) + { + auto doesStrategyExist = std::find(memoryOptimizationStrategies.begin(), + memoryOptimizationStrategies.end(), + strategyName) != memoryOptimizationStrategies.end(); + if (doesStrategyExist) + { + std::unique_ptr memoryOptimizerStrategy = nullptr; + CREATE_MEMORY_OPTIMIZER_STRATEGY(armnn::ConstantMemoryStrategy, + memoryOptimizerStrategy); + return memoryOptimizerStrategy; + } + return nullptr; + } + + + const std::vector& GetMemoryOptimizerStrategyNames() + { + return memoryOptimizationStrategies; + } +} // namespace armnn \ No newline at end of file diff --git a/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/strategies/ConstantMemoryStrategy.cpp b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/strategies/ConstantMemoryStrategy.cpp new file mode 100644 index 0000000000..55f7f89f4b --- /dev/null +++ b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/strategies/ConstantMemoryStrategy.cpp @@ -0,0 +1,43 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "ConstantMemoryStrategy.hpp" + +namespace armnn +{ + +std::string ConstantMemoryStrategy::GetName() const +{ + return m_Name; +} + +MemBlockStrategyType ConstantMemoryStrategy::GetMemBlockStrategyType() const +{ + return m_MemBlockStrategyType; +} + +// A IMemoryOptimizerStrategy must ensure that +// 1: All MemBlocks have been assigned to a MemBin +// 2: No MemBlock is assigned to multiple MemBins +// 3: No two Memblocks in a MemBin overlap in both the X and Y axis +std::vector ConstantMemoryStrategy::Optimize(std::vector& memBlocks) +{ + std::vector memBins; + memBins.reserve(memBlocks.size()); + + for (auto& memBlock : memBlocks) + { + MemBin memBin; + memBin.m_MemSize = memBlock.m_MemSize; + memBin.m_MemBlocks.reserve(1); + memBlock.m_Offset = 0; + memBin.m_MemBlocks.push_back(memBlock); + memBins.push_back(memBin); + } + + return memBins; +} + +} // namespace armnn \ No newline at end of file diff --git a/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/strategies/ConstantMemoryStrategy.hpp b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/strategies/ConstantMemoryStrategy.hpp new file mode 100644 index 0000000000..249c133a0f --- /dev/null +++ b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/strategies/ConstantMemoryStrategy.hpp @@ -0,0 +1,31 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// +#pragma once + +#include +#include + +namespace armnn +{ +// ConstLayerMemoryOptimizer: Create a unique MemBin for each MemBlock and assign it an offset of 0 +class ConstantMemoryStrategy : public IMemoryOptimizerStrategy +{ +public: + ConstantMemoryStrategy() + : m_Name(std::string("ConstantMemoryStrategy")) + , m_MemBlockStrategyType(MemBlockStrategyType::SingleAxisPacking) {} + + std::string GetName() const override; + + MemBlockStrategyType GetMemBlockStrategyType() const override; + + std::vector Optimize(std::vector& memBlocks) override; + +private: + std::string m_Name; + MemBlockStrategyType m_MemBlockStrategyType; +}; + +} // namespace armnn \ No newline at end of file diff --git a/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/strategies/StrategyValidator.cpp b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/strategies/StrategyValidator.cpp new file mode 100644 index 0000000000..48cdfb040c --- /dev/null +++ b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/strategies/StrategyValidator.cpp @@ -0,0 +1,132 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include +#include +#include "StrategyValidator.hpp" + +namespace armnn +{ + +std::vector StrategyValidator::Optimize(std::vector& memBlocks) +{ + // Condition #1: All Memblocks have been assigned to a MemBin + + // Condition #2: No Memblock is assigned to multiple MemBins + + // Condition #3: No two Memblocks in a MemBin overlap in both the X and Y axis + // Memblocks in a MemBin can overlap on the X axis for SingleAxisPacking + // Memblocks in a MemBin can overlap on the Y axis or the X for MultiAxisPacking but not both + + std::unordered_map validationMap; + + for (auto memBlock : memBlocks) + { + validationMap[memBlock.m_Index] = false; + } + + auto memBinVect = m_Strategy->Optimize(memBlocks); + + // Compare each of the input memblocks against every assignedBlock in each bin + // if we get through all bins without finding a block return + // if at any stage the block is found twice return + + for (auto memBin : memBinVect) + { + for (auto block : memBin.m_MemBlocks) + { + try + { + if (!validationMap.at(block.m_Index)) + { + validationMap.at(block.m_Index) = true; + } + else + { + throw MemoryValidationException("Condition #2: Memblock is assigned to multiple MemBins"); + } + } + catch (const std::out_of_range&) + { + throw MemoryValidationException("Unknown index "); + } + } + } + + for (auto memBlock : memBlocks) + { + if (!validationMap.at(memBlock.m_Index)) + { + throw MemoryValidationException("Condition #1: Block not found in any bin"); + } + } + + // Check for overlaps once we know blocks are all assigned and no duplicates + for (auto bin : memBinVect) + { + for (unsigned int i = 0; i < bin.m_MemBlocks.size(); ++i) + { + auto assignedBlock = bin.m_MemBlocks[i]; + auto xStart = assignedBlock.m_Offset; + auto xEnd = assignedBlock.m_Offset + assignedBlock.m_MemSize; + + auto yStart = assignedBlock.m_StartOfLife; + auto yEnd = assignedBlock.m_EndOfLife; + auto assignedIndex = assignedBlock.m_Index; + + // Only compare with blocks after the current one as previous have already been checked + for (unsigned int j = i + 1; j < bin.m_MemBlocks.size(); ++j) + { + auto otherAssignedBlock = bin.m_MemBlocks[j]; + auto xStartAssigned = otherAssignedBlock.m_Offset; + auto xEndAssigned = otherAssignedBlock.m_Offset + otherAssignedBlock.m_MemSize; + + auto yStartAssigned = otherAssignedBlock.m_StartOfLife; + auto yEndAssigned = otherAssignedBlock.m_EndOfLife; + auto otherIndex = otherAssignedBlock.m_Index; + + // If overlapping on both X and Y then invalid + // Inside left of rectangle & Inside right of rectangle + if ((((xStart >= xStartAssigned) && (xEnd <= xEndAssigned)) && + // Inside bottom of rectangle & Inside top of rectangle + ((yStart >= yStartAssigned) && (yEnd <= yEndAssigned))) && + // Cant overlap with itself + (assignedIndex != otherIndex)) + { + // Condition #3: two Memblocks overlap on both the X and Y axis + throw MemoryValidationException("Condition #3: two Memblocks overlap on both the X and Y axis"); + } + + switch (m_Strategy->GetMemBlockStrategyType()) + { + case (MemBlockStrategyType::SingleAxisPacking): + { + // Inside bottom of rectangle & Inside top of rectangle + if (((yStart >= yStartAssigned) && (yEnd <= yEndAssigned)) && + // Cant overlap with itself + (assignedIndex != otherIndex)) + { + throw MemoryValidationException("Condition #3: " + "invalid as two Memblocks overlap on the Y axis for SingleAxisPacking"); + + } + break; + } + case (MemBlockStrategyType::MultiAxisPacking): + { + break; + } + default: + throw MemoryValidationException("Unknown MemBlockStrategyType"); + } + } + } + } + + // None of the conditions broken so return true + return memBinVect; +} + +} // namespace armnn \ No newline at end of file diff --git a/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/strategies/StrategyValidator.hpp b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/strategies/StrategyValidator.hpp new file mode 100644 index 0000000000..e1f9111cd3 --- /dev/null +++ b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/strategies/StrategyValidator.hpp @@ -0,0 +1,41 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// +#pragma once + +#include +#include +#include + +namespace armnn +{ + +class StrategyValidator : public IMemoryOptimizerStrategy +{ +public: + + void SetStrategy(std::shared_ptr strategy) + { + m_Strategy = strategy; + m_MemBlockStrategyType = strategy->GetMemBlockStrategyType(); + } + + std::string GetName() const override + { + return "StrategyValidator"; + } + + MemBlockStrategyType GetMemBlockStrategyType() const override + { + return m_MemBlockStrategyType; + } + + std::vector Optimize(std::vector& memBlocks) override; + +private: + std::shared_ptr m_Strategy; + MemBlockStrategyType m_MemBlockStrategyType; +}; + +} // namespace armnn \ No newline at end of file diff --git a/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/test/CMakeLists.txt b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/test/CMakeLists.txt new file mode 100644 index 0000000000..b96782a84d --- /dev/null +++ b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/test/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +# SPDX-License-Identifier: MIT +# + +list(APPEND armnnMemoryOptimizationStrategiesUnitTests_sources + ConstMemoryStrategyTests.cpp + ValidatorStrategyTests.cpp +) + +add_library(armnnMemoryOptimizationStrategiesUnitTests OBJECT ${armnnMemoryOptimizationStrategiesUnitTests_sources}) +target_include_directories(armnnMemoryOptimizationStrategiesUnitTests PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) diff --git a/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/test/ConstMemoryStrategyTests.cpp b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/test/ConstMemoryStrategyTests.cpp new file mode 100644 index 0000000000..64312f362f --- /dev/null +++ b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/test/ConstMemoryStrategyTests.cpp @@ -0,0 +1,77 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include +#include + +#include +#include + +using namespace armnn; + +TEST_SUITE("ConstMemoryStrategyTestSuite") +{ + +TEST_CASE("ConstMemoryStrategyTest") +{ + // create a few memory blocks + MemBlock memBlock0(0, 2, 20, 0, 0); + MemBlock memBlock1(2, 3, 10, 20, 1); + MemBlock memBlock2(3, 5, 15, 30, 2); + MemBlock memBlock3(5, 6, 20, 50, 3); + MemBlock memBlock4(7, 8, 5, 70, 4); + + std::vector memBlocks; + memBlocks.reserve(5); + memBlocks.push_back(memBlock0); + memBlocks.push_back(memBlock1); + memBlocks.push_back(memBlock2); + memBlocks.push_back(memBlock3); + memBlocks.push_back(memBlock4); + + // Optimize the memory blocks with ConstantMemoryStrategy + ConstantMemoryStrategy constLayerMemoryOptimizerStrategy; + CHECK_EQ(constLayerMemoryOptimizerStrategy.GetName(), std::string("ConstantMemoryStrategy")); + CHECK_EQ(constLayerMemoryOptimizerStrategy.GetMemBlockStrategyType(), MemBlockStrategyType::SingleAxisPacking); + auto memBins = constLayerMemoryOptimizerStrategy.Optimize(memBlocks); + CHECK(memBins.size() == 5); + + CHECK(memBins[1].m_MemBlocks.size() == 1); + CHECK(memBins[1].m_MemBlocks[0].m_Offset == 0); + CHECK(memBins[1].m_MemBlocks[0].m_MemSize == 10); + CHECK(memBins[1].m_MemBlocks[0].m_Index == 1); + + CHECK(memBins[4].m_MemBlocks.size() == 1); + CHECK(memBins[4].m_MemBlocks[0].m_Offset == 0); + CHECK(memBins[4].m_MemBlocks[0].m_MemSize == 5); + CHECK(memBins[4].m_MemBlocks[0].m_Index == 4); +} + +TEST_CASE("ConstLayerMemoryOptimizerStrategyValidatorTest") +{ + // create a few memory blocks + MemBlock memBlock0(0, 2, 20, 0, 0); + MemBlock memBlock1(2, 3, 10, 20, 1); + MemBlock memBlock2(3, 5, 15, 30, 2); + MemBlock memBlock3(5, 6, 20, 50, 3); + MemBlock memBlock4(7, 8, 5, 70, 4); + + std::vector memBlocks; + memBlocks.reserve(5); + memBlocks.push_back(memBlock0); + memBlocks.push_back(memBlock1); + memBlocks.push_back(memBlock2); + memBlocks.push_back(memBlock3); + memBlocks.push_back(memBlock4); + + // Optimize the memory blocks with ConstLayerMemoryOptimizerStrategy + auto ptr = std::make_shared(); + StrategyValidator validator; + validator.SetStrategy(ptr); + // Ensure ConstLayerMemoryOptimizerStrategy is valid + CHECK_NOTHROW(validator.Optimize(memBlocks)); +} + +} diff --git a/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/test/ValidatorStrategyTests.cpp b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/test/ValidatorStrategyTests.cpp new file mode 100644 index 0000000000..bc04105f4b --- /dev/null +++ b/src/backends/backendsCommon/memoryOptimizerStrategyLibrary/test/ValidatorStrategyTests.cpp @@ -0,0 +1,283 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include + +#include +#include + +using namespace armnn; + +TEST_SUITE("MemoryOptimizerStrategyValidatorTestSuite") +{ + +// TestMemoryOptimizerStrategy: Create a MemBin and put all blocks in it so the can overlap. +class TestMemoryOptimizerStrategy : public IMemoryOptimizerStrategy +{ +public: + TestMemoryOptimizerStrategy(MemBlockStrategyType type) + : m_Name(std::string("testMemoryOptimizerStrategy")) + , m_MemBlockStrategyType(type) {} + + std::string GetName() const override + { + return m_Name; + } + + MemBlockStrategyType GetMemBlockStrategyType() const override + { + return m_MemBlockStrategyType; + } + + std::vector Optimize(std::vector& memBlocks) override + { + std::vector memBins; + memBins.reserve(memBlocks.size()); + + MemBin memBin; + memBin.m_MemBlocks.reserve(memBlocks.size()); + memBin.m_MemSize = 0; + for (auto& memBlock : memBlocks) + { + + memBin.m_MemSize = memBin.m_MemSize + memBlock.m_MemSize; + memBin.m_MemBlocks.push_back(memBlock); + } + memBins.push_back(memBin); + + return memBins; + } + +private: + std::string m_Name; + MemBlockStrategyType m_MemBlockStrategyType; +}; + +TEST_CASE("MemoryOptimizerStrategyValidatorTestOverlapX") +{ + // create a few memory blocks + MemBlock memBlock0(0, 5, 20, 0, 0); + MemBlock memBlock1(5, 10, 10, 0, 1); + MemBlock memBlock2(10, 15, 15, 0, 2); + MemBlock memBlock3(15, 20, 20, 0, 3); + MemBlock memBlock4(20, 25, 5, 0, 4); + + std::vector memBlocks; + memBlocks.reserve(5); + memBlocks.push_back(memBlock0); + memBlocks.push_back(memBlock1); + memBlocks.push_back(memBlock2); + memBlocks.push_back(memBlock3); + memBlocks.push_back(memBlock4); + + // Optimize the memory blocks with TestMemoryOptimizerStrategySingle + TestMemoryOptimizerStrategy testMemoryOptimizerStrategySingle(MemBlockStrategyType::SingleAxisPacking); + auto ptr = std::make_shared(testMemoryOptimizerStrategySingle); + StrategyValidator validator; + validator.SetStrategy(ptr); + // SingleAxisPacking can overlap on X axis. + CHECK_NOTHROW(validator.Optimize(memBlocks)); + + // Optimize the memory blocks with TestMemoryOptimizerStrategyMulti + TestMemoryOptimizerStrategy testMemoryOptimizerStrategyMulti(MemBlockStrategyType::MultiAxisPacking); + auto ptrMulti = std::make_shared(testMemoryOptimizerStrategyMulti); + StrategyValidator validatorMulti; + validatorMulti.SetStrategy(ptrMulti); + // MultiAxisPacking can overlap on X axis. + CHECK_NOTHROW(validatorMulti.Optimize(memBlocks)); +} + +TEST_CASE("MemoryOptimizerStrategyValidatorTestOverlapXAndY") +{ + // create a few memory blocks + MemBlock memBlock0(0, 5, 20, 0, 0); + MemBlock memBlock1(0, 10, 10, 0, 1); + MemBlock memBlock2(0, 15, 15, 0, 2); + MemBlock memBlock3(0, 20, 20, 0, 3); + MemBlock memBlock4(0, 25, 5, 0, 4); + + std::vector memBlocks; + memBlocks.reserve(5); + memBlocks.push_back(memBlock0); + memBlocks.push_back(memBlock1); + memBlocks.push_back(memBlock2); + memBlocks.push_back(memBlock3); + memBlocks.push_back(memBlock4); + + // Optimize the memory blocks with TestMemoryOptimizerStrategySingle + TestMemoryOptimizerStrategy testMemoryOptimizerStrategySingle(MemBlockStrategyType::SingleAxisPacking); + auto ptr = std::make_shared(testMemoryOptimizerStrategySingle); + StrategyValidator validator; + validator.SetStrategy(ptr); + // SingleAxisPacking cannot overlap on both X and Y axis. + CHECK_THROWS(validator.Optimize(memBlocks)); + + // Optimize the memory blocks with TestMemoryOptimizerStrategyMulti + TestMemoryOptimizerStrategy testMemoryOptimizerStrategyMulti(MemBlockStrategyType::MultiAxisPacking); + auto ptrMulti = std::make_shared(testMemoryOptimizerStrategyMulti); + StrategyValidator validatorMulti; + validatorMulti.SetStrategy(ptrMulti); + // MultiAxisPacking cannot overlap on both X and Y axis. + CHECK_THROWS(validatorMulti.Optimize(memBlocks)); +} + +TEST_CASE("MemoryOptimizerStrategyValidatorTestOverlapY") +{ + // create a few memory blocks + MemBlock memBlock0(0, 2, 20, 0, 0); + MemBlock memBlock1(0, 3, 10, 20, 1); + MemBlock memBlock2(0, 5, 15, 30, 2); + MemBlock memBlock3(0, 6, 20, 50, 3); + MemBlock memBlock4(0, 8, 5, 70, 4); + + std::vector memBlocks; + memBlocks.reserve(5); + memBlocks.push_back(memBlock0); + memBlocks.push_back(memBlock1); + memBlocks.push_back(memBlock2); + memBlocks.push_back(memBlock3); + memBlocks.push_back(memBlock4); + + // Optimize the memory blocks with TestMemoryOptimizerStrategySingle + TestMemoryOptimizerStrategy testMemoryOptimizerStrategySingle(MemBlockStrategyType::SingleAxisPacking); + auto ptr = std::make_shared(testMemoryOptimizerStrategySingle); + StrategyValidator validator; + validator.SetStrategy(ptr); + // SingleAxisPacking cannot overlap on Y axis + CHECK_THROWS(validator.Optimize(memBlocks)); + + // Optimize the memory blocks with TestMemoryOptimizerStrategyMulti + TestMemoryOptimizerStrategy testMemoryOptimizerStrategyMulti(MemBlockStrategyType::MultiAxisPacking); + auto ptrMulti = std::make_shared(testMemoryOptimizerStrategyMulti); + StrategyValidator validatorMulti; + validatorMulti.SetStrategy(ptrMulti); + // MultiAxisPacking can overlap on Y axis + CHECK_NOTHROW(validatorMulti.Optimize(memBlocks)); +} + +// TestMemoryOptimizerStrategyDuplicate: Create a MemBin and put all blocks in it duplicating each so validator +// can check +class TestMemoryOptimizerStrategyDuplicate : public TestMemoryOptimizerStrategy +{ +public: + TestMemoryOptimizerStrategyDuplicate(MemBlockStrategyType type) + : TestMemoryOptimizerStrategy(type) + {} + + std::vector Optimize(std::vector& memBlocks) override + { + std::vector memBins; + memBins.reserve(memBlocks.size()); + + MemBin memBin; + memBin.m_MemBlocks.reserve(memBlocks.size()); + for (auto& memBlock : memBlocks) + { + memBin.m_MemSize = memBin.m_MemSize + memBlock.m_MemSize; + memBin.m_MemBlocks.push_back(memBlock); + // Put block in twice so it gets found twice + memBin.m_MemBlocks.push_back(memBlock); + } + memBins.push_back(memBin); + + return memBins; + } +}; + +TEST_CASE("MemoryOptimizerStrategyValidatorTestDuplicateBlocks") +{ + // create a few memory blocks + MemBlock memBlock0(0, 2, 20, 0, 0); + MemBlock memBlock1(2, 3, 10, 20, 1); + MemBlock memBlock2(3, 5, 15, 30, 2); + MemBlock memBlock3(5, 6, 20, 50, 3); + MemBlock memBlock4(7, 8, 5, 70, 4); + + std::vector memBlocks; + memBlocks.reserve(5); + memBlocks.push_back(memBlock0); + memBlocks.push_back(memBlock1); + memBlocks.push_back(memBlock2); + memBlocks.push_back(memBlock3); + memBlocks.push_back(memBlock4); + + // Optimize the memory blocks with TestMemoryOptimizerStrategySingle + // Duplicate strategy is invalid as same block is found twice + TestMemoryOptimizerStrategyDuplicate testMemoryOptimizerStrategySingle(MemBlockStrategyType::SingleAxisPacking); + auto ptr = std::make_shared(testMemoryOptimizerStrategySingle); + StrategyValidator validator; + validator.SetStrategy(ptr); + CHECK_THROWS(validator.Optimize(memBlocks)); + + // Optimize the memory blocks with TestMemoryOptimizerStrategyMulti + TestMemoryOptimizerStrategyDuplicate testMemoryOptimizerStrategyMulti(MemBlockStrategyType::MultiAxisPacking); + auto ptrMulti = std::make_shared(testMemoryOptimizerStrategyMulti); + StrategyValidator validatorMulti; + validatorMulti.SetStrategy(ptrMulti); + CHECK_THROWS(validatorMulti.Optimize(memBlocks)); +} + +// TestMemoryOptimizerStrategySkip: Create a MemBin and put all blocks in it skipping every other block so validator +// can check +class TestMemoryOptimizerStrategySkip : public TestMemoryOptimizerStrategy +{ +public: + TestMemoryOptimizerStrategySkip(MemBlockStrategyType type) + : TestMemoryOptimizerStrategy(type) + {} + + std::vector Optimize(std::vector& memBlocks) override + { + std::vector memBins; + memBins.reserve(memBlocks.size()); + + MemBin memBin; + memBin.m_MemBlocks.reserve(memBlocks.size()); + for (unsigned int i = 0; i < memBlocks.size()-1; i+=2) + { + auto memBlock = memBlocks[i]; + memBin.m_MemSize = memBin.m_MemSize + memBlock.m_MemSize; + memBin.m_MemBlocks.push_back(memBlock); + } + memBins.push_back(memBin); + + return memBins; + } +}; + +TEST_CASE("MemoryOptimizerStrategyValidatorTestSkipBlocks") +{ + // create a few memory blocks + MemBlock memBlock0(0, 2, 20, 0, 0); + MemBlock memBlock1(2, 3, 10, 20, 1); + MemBlock memBlock2(3, 5, 15, 30, 2); + MemBlock memBlock3(5, 6, 20, 50, 3); + MemBlock memBlock4(7, 8, 5, 70, 4); + + std::vector memBlocks; + memBlocks.reserve(5); + memBlocks.push_back(memBlock0); + memBlocks.push_back(memBlock1); + memBlocks.push_back(memBlock2); + memBlocks.push_back(memBlock3); + memBlocks.push_back(memBlock4); + + // Optimize the memory blocks with TestMemoryOptimizerStrategySingle + // Skip strategy is invalid as every second block is not found + TestMemoryOptimizerStrategySkip testMemoryOptimizerStrategySingle(MemBlockStrategyType::SingleAxisPacking); + auto ptr = std::make_shared(testMemoryOptimizerStrategySingle); + StrategyValidator validator; + validator.SetStrategy(ptr); + CHECK_THROWS(validator.Optimize(memBlocks)); + + // Optimize the memory blocks with TestMemoryOptimizerStrategyMulti + TestMemoryOptimizerStrategySkip testMemoryOptimizerStrategyMulti(MemBlockStrategyType::MultiAxisPacking); + auto ptrMulti = std::make_shared(testMemoryOptimizerStrategyMulti); + StrategyValidator validatorMulti; + validatorMulti.SetStrategy(ptrMulti); + CHECK_THROWS(validatorMulti.Optimize(memBlocks)); +} + +} -- cgit v1.2.1