blob: 2438019878646751ac3aba470dd0ba218f90112a [file] [log] [blame]
//
// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
// SPDX-License-Identifier: MIT
//
#include <backendsCommon/memoryOptimizerStrategyLibrary/strategies/StrategyValidator.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(6, 10, 10, 0, 1);
MemBlock memBlock2(11, 15, 15, 0, 2);
MemBlock memBlock3(16, 20, 20, 0, 3);
MemBlock memBlock4(21, 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);
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<TestMemoryOptimizerStrategy>(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<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);
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<TestMemoryOptimizerStrategy>(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, 21, 1);
MemBlock memBlock2(0, 5, 15, 37, 2);
MemBlock memBlock3(0, 6, 20, 58, 3);
MemBlock memBlock4(0, 8, 5, 79, 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);
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<TestMemoryOptimizerStrategy>(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<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);
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<TestMemoryOptimizerStrategyDuplicate>(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<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);
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<TestMemoryOptimizerStrategySkip>(testMemoryOptimizerStrategyMulti);
StrategyValidator validatorMulti;
validatorMulti.SetStrategy(ptrMulti);
CHECK_THROWS(validatorMulti.Optimize(memBlocks));
}
}