1 // 2 // Copyright © 2021 Arm Ltd and Contributors. All rights reserved. 3 // SPDX-License-Identifier: MIT 4 // 5 6 #include <backendsCommon/memoryOptimizerStrategyLibrary/strategies/StrategyValidator.hpp> 7 8 #include <doctest/doctest.h> 9 #include <vector> 10 11 using namespace armnn; 12 13 TEST_SUITE("MemoryOptimizerStrategyValidatorTestSuite") 14 { 15 16 // TestMemoryOptimizerStrategy: Create a MemBin and put all blocks in it so the can overlap. 17 class TestMemoryOptimizerStrategy : public IMemoryOptimizerStrategy 18 { 19 public: TestMemoryOptimizerStrategy(MemBlockStrategyType type)20 TestMemoryOptimizerStrategy(MemBlockStrategyType type) 21 : m_Name(std::string("testMemoryOptimizerStrategy")) 22 , m_MemBlockStrategyType(type) {} 23 GetName() const24 std::string GetName() const override 25 { 26 return m_Name; 27 } 28 GetMemBlockStrategyType() const29 MemBlockStrategyType GetMemBlockStrategyType() const override 30 { 31 return m_MemBlockStrategyType; 32 } 33 Optimize(std::vector<MemBlock> & memBlocks)34 std::vector<MemBin> Optimize(std::vector<MemBlock>& memBlocks) override 35 { 36 std::vector<MemBin> memBins; 37 memBins.reserve(memBlocks.size()); 38 39 MemBin memBin; 40 memBin.m_MemBlocks.reserve(memBlocks.size()); 41 memBin.m_MemSize = 0; 42 for (auto& memBlock : memBlocks) 43 { 44 45 memBin.m_MemSize = memBin.m_MemSize + memBlock.m_MemSize; 46 memBin.m_MemBlocks.push_back(memBlock); 47 } 48 memBins.push_back(memBin); 49 50 return memBins; 51 } 52 53 private: 54 std::string m_Name; 55 MemBlockStrategyType m_MemBlockStrategyType; 56 }; 57 58 TEST_CASE("MemoryOptimizerStrategyValidatorTestOverlapX") 59 { 60 // create a few memory blocks 61 MemBlock memBlock0(0, 5, 20, 0, 0); 62 MemBlock memBlock1(6, 10, 10, 0, 1); 63 MemBlock memBlock2(11, 15, 15, 0, 2); 64 MemBlock memBlock3(16, 20, 20, 0, 3); 65 MemBlock memBlock4(21, 25, 5, 0, 4); 66 67 std::vector<MemBlock> memBlocks; 68 memBlocks.reserve(5); 69 memBlocks.push_back(memBlock0); 70 memBlocks.push_back(memBlock1); 71 memBlocks.push_back(memBlock2); 72 memBlocks.push_back(memBlock3); 73 memBlocks.push_back(memBlock4); 74 75 // Optimize the memory blocks with TestMemoryOptimizerStrategySingle 76 TestMemoryOptimizerStrategy testMemoryOptimizerStrategySingle(MemBlockStrategyType::SingleAxisPacking); 77 auto ptr = std::make_shared<TestMemoryOptimizerStrategy>(testMemoryOptimizerStrategySingle); 78 StrategyValidator validator; 79 validator.SetStrategy(ptr); 80 // SingleAxisPacking can overlap on X axis. 81 CHECK_NOTHROW(validator.Optimize(memBlocks)); 82 83 // Optimize the memory blocks with TestMemoryOptimizerStrategyMulti 84 TestMemoryOptimizerStrategy testMemoryOptimizerStrategyMulti(MemBlockStrategyType::MultiAxisPacking); 85 auto ptrMulti = std::make_shared<TestMemoryOptimizerStrategy>(testMemoryOptimizerStrategyMulti); 86 StrategyValidator validatorMulti; 87 validatorMulti.SetStrategy(ptrMulti); 88 // MultiAxisPacking can overlap on X axis. 89 CHECK_NOTHROW(validatorMulti.Optimize(memBlocks)); 90 } 91 92 TEST_CASE("MemoryOptimizerStrategyValidatorTestOverlapXAndY") 93 { 94 // create a few memory blocks 95 MemBlock memBlock0(0, 5, 20, 0, 0); 96 MemBlock memBlock1(0, 10, 10, 0, 1); 97 MemBlock memBlock2(0, 15, 15, 0, 2); 98 MemBlock memBlock3(0, 20, 20, 0, 3); 99 MemBlock memBlock4(0, 25, 5, 0, 4); 100 101 std::vector<MemBlock> memBlocks; 102 memBlocks.reserve(5); 103 memBlocks.push_back(memBlock0); 104 memBlocks.push_back(memBlock1); 105 memBlocks.push_back(memBlock2); 106 memBlocks.push_back(memBlock3); 107 memBlocks.push_back(memBlock4); 108 109 // Optimize the memory blocks with TestMemoryOptimizerStrategySingle 110 TestMemoryOptimizerStrategy testMemoryOptimizerStrategySingle(MemBlockStrategyType::SingleAxisPacking); 111 auto ptr = std::make_shared<TestMemoryOptimizerStrategy>(testMemoryOptimizerStrategySingle); 112 StrategyValidator validator; 113 validator.SetStrategy(ptr); 114 // SingleAxisPacking cannot overlap on both X and Y axis. 115 CHECK_THROWS(validator.Optimize(memBlocks)); 116 117 // Optimize the memory blocks with TestMemoryOptimizerStrategyMulti 118 TestMemoryOptimizerStrategy testMemoryOptimizerStrategyMulti(MemBlockStrategyType::MultiAxisPacking); 119 auto ptrMulti = std::make_shared<TestMemoryOptimizerStrategy>(testMemoryOptimizerStrategyMulti); 120 StrategyValidator validatorMulti; 121 validatorMulti.SetStrategy(ptrMulti); 122 // MultiAxisPacking cannot overlap on both X and Y axis. 123 CHECK_THROWS(validatorMulti.Optimize(memBlocks)); 124 } 125 126 TEST_CASE("MemoryOptimizerStrategyValidatorTestOverlapY") 127 { 128 // create a few memory blocks 129 MemBlock memBlock0(0, 2, 20, 0, 0); 130 MemBlock memBlock1(0, 3, 10, 21, 1); 131 MemBlock memBlock2(0, 5, 15, 37, 2); 132 MemBlock memBlock3(0, 6, 20, 58, 3); 133 MemBlock memBlock4(0, 8, 5, 79, 4); 134 135 std::vector<MemBlock> memBlocks; 136 memBlocks.reserve(5); 137 memBlocks.push_back(memBlock0); 138 memBlocks.push_back(memBlock1); 139 memBlocks.push_back(memBlock2); 140 memBlocks.push_back(memBlock3); 141 memBlocks.push_back(memBlock4); 142 143 // Optimize the memory blocks with TestMemoryOptimizerStrategySingle 144 TestMemoryOptimizerStrategy testMemoryOptimizerStrategySingle(MemBlockStrategyType::SingleAxisPacking); 145 auto ptr = std::make_shared<TestMemoryOptimizerStrategy>(testMemoryOptimizerStrategySingle); 146 StrategyValidator validator; 147 validator.SetStrategy(ptr); 148 // SingleAxisPacking cannot overlap on Y axis 149 CHECK_THROWS(validator.Optimize(memBlocks)); 150 151 // Optimize the memory blocks with TestMemoryOptimizerStrategyMulti 152 TestMemoryOptimizerStrategy testMemoryOptimizerStrategyMulti(MemBlockStrategyType::MultiAxisPacking); 153 auto ptrMulti = std::make_shared<TestMemoryOptimizerStrategy>(testMemoryOptimizerStrategyMulti); 154 StrategyValidator validatorMulti; 155 validatorMulti.SetStrategy(ptrMulti); 156 // MultiAxisPacking can overlap on Y axis 157 CHECK_NOTHROW(validatorMulti.Optimize(memBlocks)); 158 } 159 160 // TestMemoryOptimizerStrategyDuplicate: Create a MemBin and put all blocks in it duplicating each so validator 161 // can check 162 class TestMemoryOptimizerStrategyDuplicate : public TestMemoryOptimizerStrategy 163 { 164 public: TestMemoryOptimizerStrategyDuplicate(MemBlockStrategyType type)165 TestMemoryOptimizerStrategyDuplicate(MemBlockStrategyType type) 166 : TestMemoryOptimizerStrategy(type) 167 {} 168 Optimize(std::vector<MemBlock> & memBlocks)169 std::vector<MemBin> Optimize(std::vector<MemBlock>& memBlocks) override 170 { 171 std::vector<MemBin> memBins; 172 memBins.reserve(memBlocks.size()); 173 174 MemBin memBin; 175 memBin.m_MemBlocks.reserve(memBlocks.size()); 176 for (auto& memBlock : memBlocks) 177 { 178 memBin.m_MemSize = memBin.m_MemSize + memBlock.m_MemSize; 179 memBin.m_MemBlocks.push_back(memBlock); 180 // Put block in twice so it gets found twice 181 memBin.m_MemBlocks.push_back(memBlock); 182 } 183 memBins.push_back(memBin); 184 185 return memBins; 186 } 187 }; 188 189 TEST_CASE("MemoryOptimizerStrategyValidatorTestDuplicateBlocks") 190 { 191 // create a few memory blocks 192 MemBlock memBlock0(0, 2, 20, 0, 0); 193 MemBlock memBlock1(2, 3, 10, 20, 1); 194 MemBlock memBlock2(3, 5, 15, 30, 2); 195 MemBlock memBlock3(5, 6, 20, 50, 3); 196 MemBlock memBlock4(7, 8, 5, 70, 4); 197 198 std::vector<MemBlock> memBlocks; 199 memBlocks.reserve(5); 200 memBlocks.push_back(memBlock0); 201 memBlocks.push_back(memBlock1); 202 memBlocks.push_back(memBlock2); 203 memBlocks.push_back(memBlock3); 204 memBlocks.push_back(memBlock4); 205 206 // Optimize the memory blocks with TestMemoryOptimizerStrategySingle 207 // Duplicate strategy is invalid as same block is found twice 208 TestMemoryOptimizerStrategyDuplicate testMemoryOptimizerStrategySingle(MemBlockStrategyType::SingleAxisPacking); 209 auto ptr = std::make_shared<TestMemoryOptimizerStrategyDuplicate>(testMemoryOptimizerStrategySingle); 210 StrategyValidator validator; 211 validator.SetStrategy(ptr); 212 CHECK_THROWS(validator.Optimize(memBlocks)); 213 214 // Optimize the memory blocks with TestMemoryOptimizerStrategyMulti 215 TestMemoryOptimizerStrategyDuplicate testMemoryOptimizerStrategyMulti(MemBlockStrategyType::MultiAxisPacking); 216 auto ptrMulti = std::make_shared<TestMemoryOptimizerStrategyDuplicate>(testMemoryOptimizerStrategyMulti); 217 StrategyValidator validatorMulti; 218 validatorMulti.SetStrategy(ptrMulti); 219 CHECK_THROWS(validatorMulti.Optimize(memBlocks)); 220 } 221 222 // TestMemoryOptimizerStrategySkip: Create a MemBin and put all blocks in it skipping every other block so validator 223 // can check 224 class TestMemoryOptimizerStrategySkip : public TestMemoryOptimizerStrategy 225 { 226 public: TestMemoryOptimizerStrategySkip(MemBlockStrategyType type)227 TestMemoryOptimizerStrategySkip(MemBlockStrategyType type) 228 : TestMemoryOptimizerStrategy(type) 229 {} 230 Optimize(std::vector<MemBlock> & memBlocks)231 std::vector<MemBin> Optimize(std::vector<MemBlock>& memBlocks) override 232 { 233 std::vector<MemBin> memBins; 234 memBins.reserve(memBlocks.size()); 235 236 MemBin memBin; 237 memBin.m_MemBlocks.reserve(memBlocks.size()); 238 for (unsigned int i = 0; i < memBlocks.size()-1; i+=2) 239 { 240 auto memBlock = memBlocks[i]; 241 memBin.m_MemSize = memBin.m_MemSize + memBlock.m_MemSize; 242 memBin.m_MemBlocks.push_back(memBlock); 243 } 244 memBins.push_back(memBin); 245 246 return memBins; 247 } 248 }; 249 250 TEST_CASE("MemoryOptimizerStrategyValidatorTestSkipBlocks") 251 { 252 // create a few memory blocks 253 MemBlock memBlock0(0, 2, 20, 0, 0); 254 MemBlock memBlock1(2, 3, 10, 20, 1); 255 MemBlock memBlock2(3, 5, 15, 30, 2); 256 MemBlock memBlock3(5, 6, 20, 50, 3); 257 MemBlock memBlock4(7, 8, 5, 70, 4); 258 259 std::vector<MemBlock> memBlocks; 260 memBlocks.reserve(5); 261 memBlocks.push_back(memBlock0); 262 memBlocks.push_back(memBlock1); 263 memBlocks.push_back(memBlock2); 264 memBlocks.push_back(memBlock3); 265 memBlocks.push_back(memBlock4); 266 267 // Optimize the memory blocks with TestMemoryOptimizerStrategySingle 268 // Skip strategy is invalid as every second block is not found 269 TestMemoryOptimizerStrategySkip testMemoryOptimizerStrategySingle(MemBlockStrategyType::SingleAxisPacking); 270 auto ptr = std::make_shared<TestMemoryOptimizerStrategySkip>(testMemoryOptimizerStrategySingle); 271 StrategyValidator validator; 272 validator.SetStrategy(ptr); 273 CHECK_THROWS(validator.Optimize(memBlocks)); 274 275 // Optimize the memory blocks with TestMemoryOptimizerStrategyMulti 276 TestMemoryOptimizerStrategySkip testMemoryOptimizerStrategyMulti(MemBlockStrategyType::MultiAxisPacking); 277 auto ptrMulti = std::make_shared<TestMemoryOptimizerStrategySkip>(testMemoryOptimizerStrategyMulti); 278 StrategyValidator validatorMulti; 279 validatorMulti.SetStrategy(ptrMulti); 280 CHECK_THROWS(validatorMulti.Optimize(memBlocks)); 281 } 282 283 } 284