aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancis Murtagh <francis.murtagh@arm.com>2021-09-28 15:30:31 +0100
committerFrancis Murtagh <francis.murtagh@arm.com>2021-10-06 15:37:37 +0000
commitca49a24a2b19e4d8e45efc53e336223c5895f25a (patch)
tree37e14b5bec459e8a9ceb96557959176ba26fd56e
parenteb5f810ad985a8cca831b46d94ee73db5a305c9f (diff)
downloadarmnn-ca49a24a2b19e4d8e45efc53e336223c5895f25a.tar.gz
IVGCVSW-6338 IMemoryOptimizerStrategy Create a wrapper validator strategy
* Add validator wrapper * Add validation logic: Condition #1: All Memblocks have been assigned to a MemBin Condition #2: No Memblock is assigned to multiple MemBins Condition #3: No two Memblocks overlap in both the X and Y axis Memblocks can overlap on the X axis for SingleAxisPacking Memblocks can overlap on the Y axis or the X for MultiAxisPacking but not both * Add test strategies and tests for overlap, duplicates and unassigned blocks Signed-off-by: Francis Murtagh <francis.murtagh@arm.com> Change-Id: I7a779b35538ecf18a33b62b84512eba69eda1f86
-rw-r--r--include/armnn/Types.hpp4
-rw-r--r--include/armnn/backends/IMemoryOptimizerStrategy.hpp6
-rw-r--r--src/backends/backendsCommon/common.mk6
-rw-r--r--src/backends/backendsCommon/memoryOptimizationStrategies/CMakeLists.txt2
-rw-r--r--src/backends/backendsCommon/memoryOptimizationStrategies/ConstLayerMemoryOptimizerStrategy.cpp2
-rw-r--r--src/backends/backendsCommon/memoryOptimizationStrategies/MemoryOptimizerStrategyValidator.cpp121
-rw-r--r--src/backends/backendsCommon/memoryOptimizationStrategies/MemoryOptimizerStrategyValidator.hpp27
-rw-r--r--src/backends/backendsCommon/memoryOptimizationStrategies/test/CMakeLists.txt1
-rw-r--r--src/backends/backendsCommon/memoryOptimizationStrategies/test/ConstLayerMemoryOptimizerStrategyTests.cpp26
-rw-r--r--src/backends/backendsCommon/memoryOptimizationStrategies/test/MemoryOptimizerStrategyValidatorTests.cpp273
10 files changed, 460 insertions, 8 deletions
diff --git a/include/armnn/Types.hpp b/include/armnn/Types.hpp
index e713b8989e..02f265c6e3 100644
--- a/include/armnn/Types.hpp
+++ b/include/armnn/Types.hpp
@@ -212,12 +212,12 @@ enum class MemorySource : uint32_t
enum class MemBlockStrategyType
{
- // MemBlocks can be packed on the Y axis only.
+ // MemBlocks can be packed on the Y axis only, overlap allowed on X axis.
// In other words MemBlocks with overlapping lifetimes cannot use the same MemBin,
// equivalent to blob or pooling memory management.
SingleAxisPacking = 0,
- // MemBlocks can be packed on the Y and X axis.
+ // MemBlocks can be packed on either Y or X axis but cannot overlap on both.
// In other words MemBlocks with overlapping lifetimes can use the same MemBin,
// equivalent to offset or slab memory management.
MultiAxisPacking = 1
diff --git a/include/armnn/backends/IMemoryOptimizerStrategy.hpp b/include/armnn/backends/IMemoryOptimizerStrategy.hpp
index ec6d838aae..ad5513f8a3 100644
--- a/include/armnn/backends/IMemoryOptimizerStrategy.hpp
+++ b/include/armnn/backends/IMemoryOptimizerStrategy.hpp
@@ -22,8 +22,8 @@ struct MemBlock
const unsigned int m_StartOfLife; // Y start
const unsigned int m_EndOfLife; // Y end
- const size_t m_MemSize; // X start
- size_t m_Offset; // X end
+ const size_t m_MemSize; // Offset + Memsize = X end
+ size_t m_Offset; // X start
const unsigned int m_Index; // Index to keep order
};
@@ -40,7 +40,7 @@ struct MemBin
// 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 the X dimension
+// 3: No two Memblocks in a MemBin overlap in both the X and Y axis
// (a strategy cannot change the y axis or length of a MemBlock)
class IMemoryOptimizerStrategy
{
diff --git a/src/backends/backendsCommon/common.mk b/src/backends/backendsCommon/common.mk
index 2795c9cc2f..910f9a4210 100644
--- a/src/backends/backendsCommon/common.mk
+++ b/src/backends/backendsCommon/common.mk
@@ -25,7 +25,8 @@ COMMON_SOURCES := \
WorkloadData.cpp \
WorkloadFactory.cpp \
WorkloadUtils.cpp \
- memoryOptimizationStrategies/ConstLayerMemoryOptimizerStrategy.cpp
+ memoryOptimizationStrategies/ConstLayerMemoryOptimizerStrategy.cpp \
+ memoryOptimizationStrategies/MemoryOptimizerStrategyValidator.cpp
# COMMON_TEST_SOURCES contains the list of files to be included
# in the Android unit test build (armnn-tests) and it is picked
@@ -101,7 +102,8 @@ COMMON_TEST_SOURCES := \
test/layerTests/SubtractionTestImpl.cpp \
test/layerTests/TransposeConvolution2dTestImpl.cpp \
test/layerTests/UnidirectionalSequenceLstmTestImpl.cpp \
- memoryOptimizationStrategies/test/ConstLayerMemoryOptimizerStrategyTests.cpp
+ memoryOptimizationStrategies/test/ConstLayerMemoryOptimizerStrategyTests.cpp \
+ memoryOptimizationStrategies/test/MemoryOptimizerStrategyValidatorTests.cpp
ifeq ($(ARMNN_REF_ENABLED),1)
COMMON_TEST_SOURCES += \
diff --git a/src/backends/backendsCommon/memoryOptimizationStrategies/CMakeLists.txt b/src/backends/backendsCommon/memoryOptimizationStrategies/CMakeLists.txt
index 6f3708beaa..de83505f7c 100644
--- a/src/backends/backendsCommon/memoryOptimizationStrategies/CMakeLists.txt
+++ b/src/backends/backendsCommon/memoryOptimizationStrategies/CMakeLists.txt
@@ -6,6 +6,8 @@
list(APPEND armnnMemoryOptimizationStrategies_sources
ConstLayerMemoryOptimizerStrategy.hpp
ConstLayerMemoryOptimizerStrategy.cpp
+ MemoryOptimizerStrategyValidator.hpp
+ MemoryOptimizerStrategyValidator.cpp
)
if(BUILD_UNIT_TESTS)
diff --git a/src/backends/backendsCommon/memoryOptimizationStrategies/ConstLayerMemoryOptimizerStrategy.cpp b/src/backends/backendsCommon/memoryOptimizationStrategies/ConstLayerMemoryOptimizerStrategy.cpp
index 8abf32c096..023c6361d0 100644
--- a/src/backends/backendsCommon/memoryOptimizationStrategies/ConstLayerMemoryOptimizerStrategy.cpp
+++ b/src/backends/backendsCommon/memoryOptimizationStrategies/ConstLayerMemoryOptimizerStrategy.cpp
@@ -21,7 +21,7 @@ MemBlockStrategyType ConstLayerMemoryOptimizerStrategy::GetMemBlockStrategyType(
// 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 the X dimension
+// 3: No two Memblocks in a MemBin overlap in both the X and Y axis
std::vector<MemBin> ConstLayerMemoryOptimizerStrategy::Optimize(std::vector<MemBlock>& memBlocks)
{
std::vector<MemBin> memBins;
diff --git a/src/backends/backendsCommon/memoryOptimizationStrategies/MemoryOptimizerStrategyValidator.cpp b/src/backends/backendsCommon/memoryOptimizationStrategies/MemoryOptimizerStrategyValidator.cpp
new file mode 100644
index 0000000000..876ad90cd4
--- /dev/null
+++ b/src/backends/backendsCommon/memoryOptimizationStrategies/MemoryOptimizerStrategyValidator.cpp
@@ -0,0 +1,121 @@
+//
+// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <backendsCommon/memoryOptimizationStrategies/MemoryOptimizerStrategyValidator.hpp>
+
+namespace armnn
+{
+
+bool MemoryOptimizerValidator::Validate(std::vector<MemBlock>& 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
+
+ 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 memBlock : memBlocks)
+ {
+ auto found = false;
+
+ for (auto bin : memBinVect)
+ {
+ for (auto assignedBlock : bin.m_MemBlocks)
+ {
+ if (memBlock.m_Index == assignedBlock.m_Index)
+ {
+ if (found)
+ {
+ // Condition #2: Memblock is assigned to multiple MemBins
+ return false;
+ }
+
+ found = true;
+ }
+ }
+ }
+ // Condition #1: Block not found in any bin so return false as strategy is invalid
+ if (!found)
+ {
+ return false;
+ }
+ }
+
+ // 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
+ return false;
+ }
+
+ 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))
+ {
+ // Condition #3: invalid as two Memblocks overlap on the Y axis for SingleAxisPacking
+ return false;
+ }
+ break;
+ }
+ case (MemBlockStrategyType::MultiAxisPacking):
+ {
+ break;
+ }
+ default:
+ // Unknown MemBlockStrategyType
+ return false;
+ }
+ }
+
+ }
+ }
+
+ // None of the conditions broken so return true
+ return true;
+}
+
+} // namespace armnn \ No newline at end of file
diff --git a/src/backends/backendsCommon/memoryOptimizationStrategies/MemoryOptimizerStrategyValidator.hpp b/src/backends/backendsCommon/memoryOptimizationStrategies/MemoryOptimizerStrategyValidator.hpp
new file mode 100644
index 0000000000..13e90593d8
--- /dev/null
+++ b/src/backends/backendsCommon/memoryOptimizationStrategies/MemoryOptimizerStrategyValidator.hpp
@@ -0,0 +1,27 @@
+//
+// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include <armnn/Types.hpp>
+#include <armnn/backends/IMemoryOptimizerStrategy.hpp>
+
+namespace armnn
+{
+
+class MemoryOptimizerValidator
+{
+public:
+ explicit MemoryOptimizerValidator(std::shared_ptr<IMemoryOptimizerStrategy> strategy)
+ : m_Strategy(strategy)
+ {
+ };
+
+ bool Validate(std::vector<MemBlock>& memBlocks);
+
+private:
+ std::shared_ptr<IMemoryOptimizerStrategy> m_Strategy;
+};
+
+} // namespace armnn \ No newline at end of file
diff --git a/src/backends/backendsCommon/memoryOptimizationStrategies/test/CMakeLists.txt b/src/backends/backendsCommon/memoryOptimizationStrategies/test/CMakeLists.txt
index 5b2489d2e9..1e16f09411 100644
--- a/src/backends/backendsCommon/memoryOptimizationStrategies/test/CMakeLists.txt
+++ b/src/backends/backendsCommon/memoryOptimizationStrategies/test/CMakeLists.txt
@@ -5,6 +5,7 @@
list(APPEND armnnMemoryOptimizationStrategiesUnitTests_sources
ConstLayerMemoryOptimizerStrategyTests.cpp
+ MemoryOptimizerStrategyValidatorTests.cpp
)
add_library(armnnMemoryOptimizationStrategiesUnitTests OBJECT ${armnnMemoryOptimizationStrategiesUnitTests_sources})
diff --git a/src/backends/backendsCommon/memoryOptimizationStrategies/test/ConstLayerMemoryOptimizerStrategyTests.cpp b/src/backends/backendsCommon/memoryOptimizationStrategies/test/ConstLayerMemoryOptimizerStrategyTests.cpp
index 95569dcc0a..cfa2d40e7d 100644
--- a/src/backends/backendsCommon/memoryOptimizationStrategies/test/ConstLayerMemoryOptimizerStrategyTests.cpp
+++ b/src/backends/backendsCommon/memoryOptimizationStrategies/test/ConstLayerMemoryOptimizerStrategyTests.cpp
@@ -4,6 +4,7 @@
//
#include <backendsCommon/memoryOptimizationStrategies/ConstLayerMemoryOptimizerStrategy.hpp>
+#include <backendsCommon/memoryOptimizationStrategies/MemoryOptimizerStrategyValidator.hpp>
#include <doctest/doctest.h>
#include <vector>
@@ -48,4 +49,29 @@ TEST_CASE("ConstLayerMemoryOptimizerStrategyTest")
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<MemBlock> 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
+ ConstLayerMemoryOptimizerStrategy constLayerMemoryOptimizerStrategy;
+ auto ptr = std::make_shared<ConstLayerMemoryOptimizerStrategy>(constLayerMemoryOptimizerStrategy);
+ MemoryOptimizerValidator validator(std::move(ptr));
+ // Ensure ConstLayerMemoryOptimizerStrategy is valid
+ CHECK(validator.Validate(memBlocks));
+}
+
}
diff --git a/src/backends/backendsCommon/memoryOptimizationStrategies/test/MemoryOptimizerStrategyValidatorTests.cpp b/src/backends/backendsCommon/memoryOptimizationStrategies/test/MemoryOptimizerStrategyValidatorTests.cpp
new file mode 100644
index 0000000000..af09e4ed56
--- /dev/null
+++ b/src/backends/backendsCommon/memoryOptimizationStrategies/test/MemoryOptimizerStrategyValidatorTests.cpp
@@ -0,0 +1,273 @@
+//
+// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <backendsCommon/memoryOptimizationStrategies/MemoryOptimizerStrategyValidator.hpp>
+
+#include <doctest/doctest.h>
+#include <vector>
+
+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<MemBin> Optimize(std::vector<MemBlock>& memBlocks) override
+ {
+ std::vector<MemBin> 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<MemBlock> 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<TestMemoryOptimizerStrategy>(testMemoryOptimizerStrategySingle);
+ MemoryOptimizerValidator validator(std::move(ptr));
+ // SingleAxisPacking can overlap on X axis.
+ CHECK(validator.Validate(memBlocks));
+
+ // Optimize the memory blocks with TestMemoryOptimizerStrategyMulti
+ TestMemoryOptimizerStrategy testMemoryOptimizerStrategyMulti(MemBlockStrategyType::MultiAxisPacking);
+ auto ptrMulti = std::make_shared<TestMemoryOptimizerStrategy>(testMemoryOptimizerStrategyMulti);
+ MemoryOptimizerValidator validatorMulti(std::move(ptrMulti));
+ // MultiAxisPacking can overlap on X axis.
+ CHECK(validatorMulti.Validate(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<MemBlock> 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<TestMemoryOptimizerStrategy>(testMemoryOptimizerStrategySingle);
+ MemoryOptimizerValidator validator(std::move(ptr));
+ // SingleAxisPacking cannot overlap on both X and Y axis.
+ CHECK(!validator.Validate(memBlocks));
+
+ // Optimize the memory blocks with TestMemoryOptimizerStrategyMulti
+ TestMemoryOptimizerStrategy testMemoryOptimizerStrategyMulti(MemBlockStrategyType::MultiAxisPacking);
+ auto ptrMulti = std::make_shared<TestMemoryOptimizerStrategy>(testMemoryOptimizerStrategyMulti);
+ MemoryOptimizerValidator validatorMulti(std::move(ptrMulti));
+ // MultiAxisPacking cannot overlap on both X and Y axis.
+ CHECK(!validatorMulti.Validate(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<MemBlock> 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<TestMemoryOptimizerStrategy>(testMemoryOptimizerStrategySingle);
+ MemoryOptimizerValidator validator(std::move(ptr));
+ // SingleAxisPacking cannot overlap on Y axis
+ CHECK(!validator.Validate(memBlocks));
+
+ // Optimize the memory blocks with TestMemoryOptimizerStrategyMulti
+ TestMemoryOptimizerStrategy testMemoryOptimizerStrategyMulti(MemBlockStrategyType::MultiAxisPacking);
+ auto ptrMulti = std::make_shared<TestMemoryOptimizerStrategy>(testMemoryOptimizerStrategyMulti);
+ MemoryOptimizerValidator validatorMulti(std::move(ptrMulti));
+ // MultiAxisPacking can overlap on Y axis
+ CHECK(validatorMulti.Validate(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<MemBin> Optimize(std::vector<MemBlock>& memBlocks) override
+ {
+ std::vector<MemBin> 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<MemBlock> 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<TestMemoryOptimizerStrategyDuplicate>(testMemoryOptimizerStrategySingle);
+ MemoryOptimizerValidator validator(std::move(ptr));
+ CHECK(!validator.Validate(memBlocks));
+
+ // Optimize the memory blocks with TestMemoryOptimizerStrategyMulti
+ TestMemoryOptimizerStrategyDuplicate testMemoryOptimizerStrategyMulti(MemBlockStrategyType::MultiAxisPacking);
+ auto ptrMulti = std::make_shared<TestMemoryOptimizerStrategyDuplicate>(testMemoryOptimizerStrategyMulti);
+ MemoryOptimizerValidator validatorMulti(std::move(ptrMulti));
+ CHECK(!validatorMulti.Validate(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<MemBin> Optimize(std::vector<MemBlock>& memBlocks) override
+ {
+ std::vector<MemBin> 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<MemBlock> 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<TestMemoryOptimizerStrategySkip>(testMemoryOptimizerStrategySingle);
+ MemoryOptimizerValidator validator(std::move(ptr));
+ CHECK(!validator.Validate(memBlocks));
+
+ // Optimize the memory blocks with TestMemoryOptimizerStrategyMulti
+ TestMemoryOptimizerStrategySkip testMemoryOptimizerStrategyMulti(MemBlockStrategyType::MultiAxisPacking);
+ auto ptrMulti = std::make_shared<TestMemoryOptimizerStrategySkip>(testMemoryOptimizerStrategyMulti);
+ MemoryOptimizerValidator validatorMulti(std::move(ptrMulti));
+ CHECK(!validatorMulti.Validate(memBlocks));
+}
+
+}