From bf3541450c03b29ff1b99593eedeeb40177e0e82 Mon Sep 17 00:00:00 2001 From: Francis Murtagh Date: Fri, 12 Aug 2022 13:54:17 +0100 Subject: IVGCVSW-7159 Implement simple TOSA Reference Backend skeleton * Added files based on RefBackend * Added PreCompiled Workload skeleton * Increment ABI version of armnnTestUtils for CreateInput which had been left as pure virtual, added base implementation for it. * Add IsTosaLayerSupported() for Addition Change-Id: I4c963adf3f50593d17ecdf21554502a64ad3bd76 --- include/armnn/backends/ILayerSupport.hpp | 2 +- include/armnn/backends/WorkloadFactory.hpp | 8 +- include/armnnTestUtils/Version.hpp | 2 +- src/backends/backendsCommon/WorkloadFactory.cpp | 7 + .../reference/workloads/RefWorkloadUtils.hpp | 5 +- src/backends/tosaCommon/CMakeLists.txt | 1 + src/backends/tosaCommon/TosaLayerSupportRules.hpp | 40 +++++ src/backends/tosaReference/CMakeLists.txt | 43 +++++ src/backends/tosaReference/TosaRefBackend.cpp | 107 +++++++++++++ src/backends/tosaReference/TosaRefBackend.hpp | 56 +++++++ src/backends/tosaReference/TosaRefBackendId.hpp | 12 ++ src/backends/tosaReference/TosaRefLayerSupport.cpp | 142 +++++++++++++++++ src/backends/tosaReference/TosaRefLayerSupport.hpp | 23 +++ .../tosaReference/TosaRefMemoryManager.cpp | 101 ++++++++++++ .../tosaReference/TosaRefMemoryManager.hpp | 59 +++++++ .../tosaReference/TosaRefRegistryInitializer.cpp | 25 +++ src/backends/tosaReference/TosaRefTensorHandle.cpp | 175 +++++++++++++++++++++ src/backends/tosaReference/TosaRefTensorHandle.hpp | 82 ++++++++++ .../tosaReference/TosaRefTensorHandleFactory.cpp | 91 +++++++++++ .../tosaReference/TosaRefTensorHandleFactory.hpp | 61 +++++++ .../tosaReference/TosaRefWorkloadFactory.cpp | 126 +++++++++++++++ .../tosaReference/TosaRefWorkloadFactory.hpp | 68 ++++++++ src/backends/tosaReference/backend.cmake | 14 ++ src/backends/tosaReference/backend.mk | 56 +++++++ src/backends/tosaReference/test/CMakeLists.txt | 16 ++ .../test/TosaRefLayerSupportTests.cpp | 65 ++++++++ .../tosaReference/test/TosaRefLayerTests.cpp | 13 ++ .../test/TosaRefWorkloadFactoryHelper.hpp | 46 ++++++ .../tosaReference/workloads/CMakeLists.txt | 18 +++ .../workloads/TosaRefBaseWorkload.hpp | 39 +++++ .../workloads/TosaRefPreCompiledWorkload.cpp | 28 ++++ .../workloads/TosaRefPreCompiledWorkload.hpp | 43 +++++ .../tosaReference/workloads/TosaRefWorkloads.hpp | 8 + 33 files changed, 1575 insertions(+), 7 deletions(-) create mode 100644 src/backends/tosaCommon/TosaLayerSupportRules.hpp create mode 100644 src/backends/tosaReference/CMakeLists.txt create mode 100644 src/backends/tosaReference/TosaRefBackend.cpp create mode 100644 src/backends/tosaReference/TosaRefBackend.hpp create mode 100644 src/backends/tosaReference/TosaRefBackendId.hpp create mode 100644 src/backends/tosaReference/TosaRefLayerSupport.cpp create mode 100644 src/backends/tosaReference/TosaRefLayerSupport.hpp create mode 100644 src/backends/tosaReference/TosaRefMemoryManager.cpp create mode 100644 src/backends/tosaReference/TosaRefMemoryManager.hpp create mode 100644 src/backends/tosaReference/TosaRefRegistryInitializer.cpp create mode 100644 src/backends/tosaReference/TosaRefTensorHandle.cpp create mode 100644 src/backends/tosaReference/TosaRefTensorHandle.hpp create mode 100644 src/backends/tosaReference/TosaRefTensorHandleFactory.cpp create mode 100644 src/backends/tosaReference/TosaRefTensorHandleFactory.hpp create mode 100644 src/backends/tosaReference/TosaRefWorkloadFactory.cpp create mode 100644 src/backends/tosaReference/TosaRefWorkloadFactory.hpp create mode 100644 src/backends/tosaReference/backend.cmake create mode 100644 src/backends/tosaReference/backend.mk create mode 100644 src/backends/tosaReference/test/CMakeLists.txt create mode 100644 src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp create mode 100644 src/backends/tosaReference/test/TosaRefLayerTests.cpp create mode 100644 src/backends/tosaReference/test/TosaRefWorkloadFactoryHelper.hpp create mode 100644 src/backends/tosaReference/workloads/CMakeLists.txt create mode 100644 src/backends/tosaReference/workloads/TosaRefBaseWorkload.hpp create mode 100644 src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.cpp create mode 100644 src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.hpp create mode 100644 src/backends/tosaReference/workloads/TosaRefWorkloads.hpp diff --git a/include/armnn/backends/ILayerSupport.hpp b/include/armnn/backends/ILayerSupport.hpp index 519119bba5..b7f5f0497d 100644 --- a/include/armnn/backends/ILayerSupport.hpp +++ b/include/armnn/backends/ILayerSupport.hpp @@ -188,7 +188,7 @@ public: const TensorInfo& detectionScores, const TensorInfo& numDetections, const DetectionPostProcessDescriptor& descriptor, - Optional reasonIfUnsupported = EmptyOptional()) const =0; + Optional reasonIfUnsupported = EmptyOptional()) const; ARMNN_DEPRECATED_MSG_REMOVAL_DATE("This method is deprecated. " "Use ABI Stable IsLayerSupported accepting LayerType argument instead.", "23.08") diff --git a/include/armnn/backends/WorkloadFactory.hpp b/include/armnn/backends/WorkloadFactory.hpp index 85e0312502..4ccf1e2c7d 100644 --- a/include/armnn/backends/WorkloadFactory.hpp +++ b/include/armnn/backends/WorkloadFactory.hpp @@ -56,9 +56,6 @@ public: unsigned int const* subTensorOrigin ) const = 0; - virtual std::unique_ptr CreateInput(const InputQueueDescriptor& descriptor, - const WorkloadInfo& info) const = 0; - ARMNN_DEPRECATED_MSG("Use ITensorHandleFactory::CreateTensorHandle instead") virtual std::unique_ptr CreateTensorHandle(const TensorInfo& tensorInfo, const bool IsMemoryManaged = true) const = 0; @@ -72,6 +69,11 @@ public: const QueueDescriptor& descriptor, const WorkloadInfo& info) const; + ARMNN_DEPRECATED_MSG_REMOVAL_DATE("Use ABI stable " + "CreateWorkload(LayerType, const QueueDescriptor&, const WorkloadInfo& info) instead.", "23.08") + virtual std::unique_ptr CreateInput(const InputQueueDescriptor& descriptor, + const WorkloadInfo& info) const; + ARMNN_DEPRECATED_MSG_REMOVAL_DATE("Use ABI stable " "CreateWorkload(LayerType, const QueueDescriptor&, const WorkloadInfo& info) instead.", "23.08") virtual std::unique_ptr CreateActivation(const ActivationQueueDescriptor& descriptor, diff --git a/include/armnnTestUtils/Version.hpp b/include/armnnTestUtils/Version.hpp index 39009d5621..d7a8cd6164 100644 --- a/include/armnnTestUtils/Version.hpp +++ b/include/armnnTestUtils/Version.hpp @@ -10,7 +10,7 @@ #define STRINGIFY_MACRO(s) #s // ArmnnTestUtils version components -#define ARMNN_TEST_UTILS_MAJOR_VERSION 1 +#define ARMNN_TEST_UTILS_MAJOR_VERSION 2 #define ARMNN_TEST_UTILS_MINOR_VERSION 0 #define ARMNN_TEST_UTILS_PATCH_VERSION 0 diff --git a/src/backends/backendsCommon/WorkloadFactory.cpp b/src/backends/backendsCommon/WorkloadFactory.cpp index 70006e4f79..665ab3f86c 100644 --- a/src/backends/backendsCommon/WorkloadFactory.cpp +++ b/src/backends/backendsCommon/WorkloadFactory.cpp @@ -2348,4 +2348,11 @@ std::unique_ptr IWorkloadFactory::CreateUnidirectionalSequenceLstm( return std::unique_ptr(); } +std::unique_ptr IWorkloadFactory::CreateInput( + const InputQueueDescriptor& /*descriptor*/, + const WorkloadInfo& /*info*/) const +{ + return std::unique_ptr(); +} + } // namepsace armnn diff --git a/src/backends/reference/workloads/RefWorkloadUtils.hpp b/src/backends/reference/workloads/RefWorkloadUtils.hpp index e50847fee5..7c35966f0f 100644 --- a/src/backends/reference/workloads/RefWorkloadUtils.hpp +++ b/src/backends/reference/workloads/RefWorkloadUtils.hpp @@ -23,11 +23,12 @@ namespace armnn /// float32 helpers //////////////////////////////////////////// +template inline const TensorInfo& GetTensorInfo(const ITensorHandle* tensorHandle) { // We know that reference workloads use RefTensorHandles for inputs and outputs - const RefTensorHandle* refTensorHandle = - PolymorphicDowncast(tensorHandle); + const TensorHandleType* refTensorHandle = + PolymorphicDowncast(tensorHandle); return refTensorHandle->GetTensorInfo(); } diff --git a/src/backends/tosaCommon/CMakeLists.txt b/src/backends/tosaCommon/CMakeLists.txt index 9653859767..61434edc96 100644 --- a/src/backends/tosaCommon/CMakeLists.txt +++ b/src/backends/tosaCommon/CMakeLists.txt @@ -8,6 +8,7 @@ include_directories(SYSTEM ${TOSA_SERIALIZATION_LIB_INCLUDE}) list(APPEND armnnTosaBackend_sources TosaMappings.hpp + TosaLayerSupportRules.hpp ) add_subdirectory(operatorMappings) diff --git a/src/backends/tosaCommon/TosaLayerSupportRules.hpp b/src/backends/tosaCommon/TosaLayerSupportRules.hpp new file mode 100644 index 0000000000..2a2b08da99 --- /dev/null +++ b/src/backends/tosaCommon/TosaLayerSupportRules.hpp @@ -0,0 +1,40 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +// List of Layer Support Rules common to TOSA backends only, for use with CheckSupportRule() + +struct TosaOperatorAttributeOfAny : public Rule +{ + template + explicit TosaOperatorAttributeOfAny(TosaSerializationOperator* op, const Container& c) + { + m_Res = std::any_of(c.begin(), c.end(), [&op](Attribute attribute) + { + return attribute == op->GetAttributeType(); + }); + } +}; + +struct TosaTypeAnyOf : public Rule +{ + template + TosaTypeAnyOf(TosaSerializationTensor* tensor, const Container& c) + { + m_Res = std::any_of(c.begin(), c.end(), [&tensor](DType dt) + { + return dt == tensor->GetDtype(); + }); + } +}; + +struct TosaTensorNumDimensionsWithinBounds : public Rule +{ + explicit TosaTensorNumDimensionsWithinBounds(TosaSerializationTensor* tensor) + { + m_Res = (tensor->GetShape().size() <= MaxNumOfTensorDimensions) || (!tensor->GetShape().empty()); + } +}; diff --git a/src/backends/tosaReference/CMakeLists.txt b/src/backends/tosaReference/CMakeLists.txt new file mode 100644 index 0000000000..d1f9040393 --- /dev/null +++ b/src/backends/tosaReference/CMakeLists.txt @@ -0,0 +1,43 @@ +# +# Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +# SPDX-License-Identifier: MIT +# + +include_directories(SYSTEM ${FLATBUFFERS_INCLUDE_PATH}) +include_directories(SYSTEM ${TOSA_SERIALIZATION_LIB_INCLUDE}) + +if(ARMNNTOSAREF) + list(APPEND armnnTosaRefBackend_sources + TosaRefBackend.cpp + TosaRefBackend.hpp + TosaRefBackendId.hpp + TosaRefTensorHandle.hpp + TosaRefTensorHandle.cpp + TosaRefLayerSupport.cpp + TosaRefLayerSupport.hpp + TosaRefMemoryManager.hpp + TosaRefMemoryManager.cpp + TosaRefRegistryInitializer.cpp + TosaRefWorkloadFactory.cpp + TosaRefWorkloadFactory.hpp + TosaRefTensorHandleFactory.cpp + TosaRefTensorHandleFactory.hpp + ) + + add_subdirectory(workloads) + + if(BUILD_UNIT_TESTS) + add_subdirectory(test) + endif() + +else() + list(APPEND armnnTosaRefBackend_sources + TosaRefBackendId.hpp + ) +endif() + +add_library(armnnTosaRefBackend OBJECT ${armnnTosaRefBackend_sources}) +target_include_directories(armnnTosaRefBackend PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(armnnTosaRefBackend PRIVATE ${PROJECT_SOURCE_DIR}/src/armnnUtils) +target_include_directories(armnnTosaRefBackend PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) +target_include_directories(armnnTosaRefBackend PRIVATE ${PROJECT_SOURCE_DIR}/src/backends/tosaCommon) diff --git a/src/backends/tosaReference/TosaRefBackend.cpp b/src/backends/tosaReference/TosaRefBackend.cpp new file mode 100644 index 0000000000..093802958b --- /dev/null +++ b/src/backends/tosaReference/TosaRefBackend.cpp @@ -0,0 +1,107 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "TosaRefBackend.hpp" +#include "TosaRefBackendId.hpp" +#include "TosaRefWorkloadFactory.hpp" +#include "TosaRefLayerSupport.hpp" +#include "TosaRefTensorHandleFactory.hpp" + +#include +#include +#include +#include +#include +#include + +#include + +namespace armnn +{ + +const BackendId& TosaRefBackend::GetIdStatic() +{ + static const BackendId s_Id{TosaRefBackendId()}; + return s_Id; +} + +IBackendInternal::IWorkloadFactoryPtr TosaRefBackend::CreateWorkloadFactory( + const IBackendInternal::IMemoryManagerSharedPtr& memoryManager) const +{ + return std::make_unique(PolymorphicPointerDowncast(memoryManager)); +} + +IBackendInternal::IWorkloadFactoryPtr TosaRefBackend::CreateWorkloadFactory( + class TensorHandleFactoryRegistry& tensorHandleFactoryRegistry) const +{ + auto memoryManager = std::make_shared(); + + tensorHandleFactoryRegistry.RegisterMemoryManager(memoryManager); + + auto factory = std::make_unique(memoryManager); + // Register copy and import factory pair + tensorHandleFactoryRegistry.RegisterCopyAndImportFactoryPair(factory->GetId(), factory->GetId()); + // Register the factory + tensorHandleFactoryRegistry.RegisterFactory(std::move(factory)); + + return std::make_unique(PolymorphicPointerDowncast(memoryManager)); +} + +IBackendInternal::IBackendContextPtr TosaRefBackend::CreateBackendContext(const IRuntime::CreationOptions&) const +{ + return IBackendContextPtr{}; +} + +IBackendInternal::IBackendProfilingContextPtr TosaRefBackend::CreateBackendProfilingContext( + const IRuntime::CreationOptions&, IBackendProfilingPtr&) +{ + return IBackendProfilingContextPtr{}; +} + +IBackendInternal::IMemoryManagerUniquePtr TosaRefBackend::CreateMemoryManager() const +{ + return std::make_unique(); +} + +IBackendInternal::ILayerSupportSharedPtr TosaRefBackend::GetLayerSupport() const +{ + static ILayerSupportSharedPtr layerSupport{new TosaRefLayerSupport}; + return layerSupport; +} + +OptimizationViews TosaRefBackend::OptimizeSubgraphView(const SubgraphView& subgraph, + const ModelOptions& modelOptions) const +{ + OptimizationViews optimizationViews(modelOptions); + optimizationViews.AddUntouchedSubgraph(SubgraphView(subgraph)); + + return optimizationViews; +} + +std::vector TosaRefBackend::GetHandleFactoryPreferences() const +{ + return std::vector { TosaRefTensorHandleFactory::GetIdStatic() }; +} + +void TosaRefBackend::RegisterTensorHandleFactories(class TensorHandleFactoryRegistry& registry) +{ + auto memoryManager = std::make_shared(); + + registry.RegisterMemoryManager(memoryManager); + + auto factory = std::make_unique(memoryManager); + + // Register copy and import factory pair + registry.RegisterCopyAndImportFactoryPair(factory->GetId(), factory->GetId()); + // Register the factory + registry.RegisterFactory(std::move(factory)); +} + +std::unique_ptr TosaRefBackend::GetDefaultAllocator() const +{ + return std::make_unique(); +} + +} // namespace armnn diff --git a/src/backends/tosaReference/TosaRefBackend.hpp b/src/backends/tosaReference/TosaRefBackend.hpp new file mode 100644 index 0000000000..9ff06269ee --- /dev/null +++ b/src/backends/tosaReference/TosaRefBackend.hpp @@ -0,0 +1,56 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// +#pragma once + +#include + +namespace armnn +{ + +class TosaRefBackend : public IBackendInternal +{ +public: + TosaRefBackend() = default; + ~TosaRefBackend() = default; + + static const BackendId& GetIdStatic(); + const BackendId& GetId() const override + { + return GetIdStatic(); + } + + IBackendInternal::IMemoryManagerUniquePtr CreateMemoryManager() const override; + + IBackendInternal::IWorkloadFactoryPtr CreateWorkloadFactory( + const IBackendInternal::IMemoryManagerSharedPtr& memoryManager = nullptr) const override; + + IBackendInternal::IWorkloadFactoryPtr CreateWorkloadFactory( + class TensorHandleFactoryRegistry& tensorHandleFactoryRegistry) const override; + + IBackendInternal::IBackendContextPtr CreateBackendContext(const IRuntime::CreationOptions&) const override; + + IBackendInternal::IBackendProfilingContextPtr + CreateBackendProfilingContext(const IRuntime::CreationOptions& creationOptions, + IBackendProfilingPtr& backendProfiling) override; + + IBackendInternal::ILayerSupportSharedPtr GetLayerSupport() const override; + + OptimizationViews OptimizeSubgraphView(const SubgraphView& subgraph, + const ModelOptions& modelOptions) const override; + + std::vector GetHandleFactoryPreferences() const override; + + void RegisterTensorHandleFactories(class TensorHandleFactoryRegistry& registry) override; + + std::unique_ptr GetDefaultAllocator() const override; + +private: + // Private members + +protected: + // Protected members +}; + +} // namespace armnn diff --git a/src/backends/tosaReference/TosaRefBackendId.hpp b/src/backends/tosaReference/TosaRefBackendId.hpp new file mode 100644 index 0000000000..470fb79c4a --- /dev/null +++ b/src/backends/tosaReference/TosaRefBackendId.hpp @@ -0,0 +1,12 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// +#pragma once + +namespace armnn +{ + +constexpr const char * TosaRefBackendId() { return "TosaRef"; } + +} // namespace armnn diff --git a/src/backends/tosaReference/TosaRefLayerSupport.cpp b/src/backends/tosaReference/TosaRefLayerSupport.cpp new file mode 100644 index 0000000000..80e982f1c4 --- /dev/null +++ b/src/backends/tosaReference/TosaRefLayerSupport.cpp @@ -0,0 +1,142 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "TosaRefLayerSupport.hpp" +#include + +#include +#include +#include +#include + +#include +#include + +namespace armnn +{ + +static bool IsTosaLayerSupported(TosaSerializationOperator* op, + const std::vector& inputs, + const std::vector& outputs, + Optional reasonIfUnsupported) +{ + switch(op->GetOp()) + { + case tosa::Op_ADD: + { + bool supported = true; + + std::array supportedAttributes = + { + Attribute_NONE + }; + + // Check Attribute from operator (GetAttribute) + supported &= CheckSupportRule(TosaOperatorAttributeOfAny(op, supportedAttributes), reasonIfUnsupported, + std::string("TOSA Reference addition: operator has an unsupported attribute.").c_str()); + + std::array supportedTypes = + { + DType_BOOL, + DType_UINT8, + DType_INT4, + DType_INT8, + DType_INT16, + DType_INT32, + DType_FLOAT, + DType_UINT16 + }; + + for (auto tensor : inputs) + { + // Check Dtype from tensor (GetDtype) + supported &= CheckSupportRule(TosaTypeAnyOf(tensor, supportedTypes), + reasonIfUnsupported, + std::string("TOSA Reference addition: " + tensor->GetName() + + " is not a supported type.").c_str()); + + // Check Shape from tensor (GetShape) + supported &= CheckSupportRule(TosaTensorNumDimensionsWithinBounds(tensor), + reasonIfUnsupported, + std::string("Tosa Reference addition: " + tensor->GetName() + " Shape.Size()" + " outside bounds of between Zero and MaxNumOfTensorDimensions.").c_str()); + } + + // Check Dtype from tensor (GetDtype) + supported &= CheckSupportRule(TosaTypeAnyOf(outputs[0], supportedTypes), + reasonIfUnsupported, + std::string("TOSA Reference addition: " + outputs[0]->GetName() + + " is not a supported type.").c_str()); + + // Check Shape from tensor (GetShape) + supported &= CheckSupportRule(TosaTensorNumDimensionsWithinBounds(outputs[0]), + reasonIfUnsupported, + std::string("Tosa Reference addition: " + outputs[0]->GetName() + " Shape.Size()" + " outside bounds of between Zero and MaxNumOfTensorDimensions.").c_str()); + + return supported; + } + default: + SetValueChecked(reasonIfUnsupported, "Operation is currently unsupported by the TOSA Reference Backend."); + return false; + } +} + +bool TosaRefLayerSupport::IsLayerSupported(const LayerType& type, + const std::vector& infos, + const BaseDescriptor& descriptor, + const Optional& lstmParamsInfo, + const Optional& quantizedLstmInputParamsInfo, + Optional reasonIfUnsupported) const +{ + IgnoreUnused(lstmParamsInfo); + IgnoreUnused(quantizedLstmInputParamsInfo); + + // Setup Inputs + const auto input0 = infos[0]; + const TensorInfo* ptr0 = &input0; + const auto input1 = infos[1]; + const TensorInfo* ptr1 = &input1; + std::vector inputInfos = {ptr0, ptr1}; + + // Setup Outputs + const auto output = infos[2]; + const TensorInfo* ptr2 = &output; + std::vector outputInfos = {ptr2}; + + auto mappings = GetTosaMapping(type, inputInfos, outputInfos, descriptor); + + // Loop through block and get each tensor and operator + for (long unsigned int i = 0; i < mappings->GetOperators().size(); ++i) + { + // While looping over operators check for op_UNKNOWN which is unsupported + if (mappings->GetOperators()[i]->GetOp() == tosa::Op_UNKNOWN) { return false;} + + // Loop over operators and get GetInput/OutputTensorNames, loop over resulting names and + // use GetTensorByName to pass pointers to tensors on to the IsTosaLayerSupported() + std::vector inputTensorsVect; + for (const auto& name : mappings->GetOperators()[i]->GetInputTensorNames()) + { + inputTensorsVect.push_back(mappings->GetTensorByName(name)); + } + + std::vector outputTensorsVect; + for (const auto& name : mappings->GetOperators()[i]->GetOutputTensorNames()) + { + outputTensorsVect.push_back(mappings->GetTensorByName(name)); + } + + if (!IsTosaLayerSupported(mappings->GetOperators()[i], + inputTensorsVect, + outputTensorsVect, + reasonIfUnsupported)) + { + return false; + } + } + return true; +} + +} // namespace armnn diff --git a/src/backends/tosaReference/TosaRefLayerSupport.hpp b/src/backends/tosaReference/TosaRefLayerSupport.hpp new file mode 100644 index 0000000000..f2d3f551d5 --- /dev/null +++ b/src/backends/tosaReference/TosaRefLayerSupport.hpp @@ -0,0 +1,23 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// +#pragma once + +#include +#include + +namespace armnn { + +class TosaRefLayerSupport : public ILayerSupport { +public: + bool IsLayerSupported(const LayerType& type, + const std::vector& infos, + const BaseDescriptor& descriptor, + const Optional& lstmParamsInfo, + const Optional&, + Optional reasonIfUnsupported) const override; + +}; + +}// namespace armnn diff --git a/src/backends/tosaReference/TosaRefMemoryManager.cpp b/src/backends/tosaReference/TosaRefMemoryManager.cpp new file mode 100644 index 0000000000..745e6bec35 --- /dev/null +++ b/src/backends/tosaReference/TosaRefMemoryManager.cpp @@ -0,0 +1,101 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// +#include "TosaRefMemoryManager.hpp" + +#include + +#include + +namespace armnn +{ + +TosaRefMemoryManager::TosaRefMemoryManager() +{} + +TosaRefMemoryManager::~TosaRefMemoryManager() +{} + +TosaRefMemoryManager::Pool* TosaRefMemoryManager::Manage(unsigned int numBytes) +{ + if (!m_FreePools.empty()) + { + Pool* res = m_FreePools.back(); + m_FreePools.pop_back(); + res->Reserve(numBytes); + return res; + } + else + { + m_Pools.push_front(Pool(numBytes)); + return &m_Pools.front(); + } +} + +void TosaRefMemoryManager::Allocate(TosaRefMemoryManager::Pool* pool) +{ + ARMNN_ASSERT(pool); + m_FreePools.push_back(pool); +} + +void* TosaRefMemoryManager::GetPointer(TosaRefMemoryManager::Pool* pool) +{ + return pool->GetPointer(); +} + +void TosaRefMemoryManager::Acquire() +{ + for (Pool &pool: m_Pools) + { + pool.Acquire(); + } +} + +void TosaRefMemoryManager::Release() +{ + for (Pool &pool: m_Pools) + { + pool.Release(); + } +} + +TosaRefMemoryManager::Pool::Pool(unsigned int numBytes) + : m_Size(numBytes), + m_Pointer(nullptr) +{} + +TosaRefMemoryManager::Pool::~Pool() +{ + if (m_Pointer) + { + Release(); + } +} + +void* TosaRefMemoryManager::Pool::GetPointer() +{ + ARMNN_ASSERT_MSG(m_Pointer, "TosaRefMemoryManager::Pool::GetPointer() called when memory not acquired"); + return m_Pointer; +} + +void TosaRefMemoryManager::Pool::Reserve(unsigned int numBytes) +{ + ARMNN_ASSERT_MSG(!m_Pointer, "TosaRefMemoryManager::Pool::Reserve() cannot be called after memory acquired"); + m_Size = std::max(m_Size, numBytes); +} + +void TosaRefMemoryManager::Pool::Acquire() +{ + ARMNN_ASSERT_MSG(!m_Pointer, "TosaRefMemoryManager::Pool::Acquire() called when memory already acquired"); + m_Pointer = ::operator new(size_t(m_Size)); +} + +void TosaRefMemoryManager::Pool::Release() +{ + ARMNN_ASSERT_MSG(m_Pointer, "TosaRefMemoryManager::Pool::Release() called when memory not acquired"); + ::operator delete(m_Pointer); + m_Pointer = nullptr; +} + +} diff --git a/src/backends/tosaReference/TosaRefMemoryManager.hpp b/src/backends/tosaReference/TosaRefMemoryManager.hpp new file mode 100644 index 0000000000..05a6ec0f87 --- /dev/null +++ b/src/backends/tosaReference/TosaRefMemoryManager.hpp @@ -0,0 +1,59 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// +#pragma once + +#include + +#include +#include + +namespace armnn +{ + +// An implementation of IMemoryManager to be used with RefTensorHandle +class TosaRefMemoryManager : public IMemoryManager +{ +public: + TosaRefMemoryManager(); + virtual ~TosaRefMemoryManager(); + + class Pool; + + Pool* Manage(unsigned int numBytes); + + void Allocate(Pool *pool); + + void* GetPointer(Pool *pool); + + void Acquire() override; + void Release() override; + + class Pool + { + public: + Pool(unsigned int numBytes); + ~Pool(); + + void Acquire(); + void Release(); + + void* GetPointer(); + + void Reserve(unsigned int numBytes); + + private: + unsigned int m_Size; + void* m_Pointer; + }; + +private: + TosaRefMemoryManager(const TosaRefMemoryManager&) = delete; // Noncopyable + TosaRefMemoryManager& operator=(const TosaRefMemoryManager&) = delete; // Noncopyable + + std::forward_list m_Pools; + std::vector m_FreePools; +}; + +} diff --git a/src/backends/tosaReference/TosaRefRegistryInitializer.cpp b/src/backends/tosaReference/TosaRefRegistryInitializer.cpp new file mode 100644 index 0000000000..71052f7b24 --- /dev/null +++ b/src/backends/tosaReference/TosaRefRegistryInitializer.cpp @@ -0,0 +1,25 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "TosaRefBackend.hpp" + +#include + +namespace +{ + +using namespace armnn; + +static BackendRegistry::StaticRegistryInitializer g_RegisterHelper +{ + BackendRegistryInstance(), + TosaRefBackend::GetIdStatic(), + []() + { + return IBackendInternalUniquePtr(new TosaRefBackend); + } +}; + +} // Anonymous namespace diff --git a/src/backends/tosaReference/TosaRefTensorHandle.cpp b/src/backends/tosaReference/TosaRefTensorHandle.cpp new file mode 100644 index 0000000000..38d02f1bb6 --- /dev/null +++ b/src/backends/tosaReference/TosaRefTensorHandle.cpp @@ -0,0 +1,175 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// +#include "TosaRefTensorHandle.hpp" + +namespace armnn +{ + +TosaRefTensorHandle::TosaRefTensorHandle(const TensorInfo& tensorInfo, + std::shared_ptr& memoryManager) + : m_TensorInfo(tensorInfo) + , m_MemoryManager(memoryManager) + , m_Pool(nullptr) + , m_UnmanagedMemory(nullptr) + , m_ImportFlags(static_cast(MemorySource::Undefined)) + , m_Imported(false) + , m_IsImportEnabled(false) +{} + +TosaRefTensorHandle::TosaRefTensorHandle(const TensorInfo& tensorInfo, + MemorySourceFlags importFlags) + : m_TensorInfo(tensorInfo) + , m_Pool(nullptr) + , m_UnmanagedMemory(nullptr) + , m_ImportFlags(importFlags) + , m_Imported(false) + , m_IsImportEnabled(true) +{} + +TosaRefTensorHandle::~TosaRefTensorHandle() +{ + if (!m_Pool) + { + // unmanaged + if (!m_Imported) + { + ::operator delete(m_UnmanagedMemory); + } + } +} + +void TosaRefTensorHandle::Manage() +{ + if (!m_IsImportEnabled) + { + ARMNN_ASSERT_MSG(!m_Pool, "TosaRefTensorHandle::Manage() called twice"); + ARMNN_ASSERT_MSG(!m_UnmanagedMemory, "TosaRefTensorHandle::Manage() called after Allocate()"); + + m_Pool = m_MemoryManager->Manage(m_TensorInfo.GetNumBytes()); + } +} + +void TosaRefTensorHandle::Allocate() +{ + // If import is enabled, do not allocate the tensor + if (!m_IsImportEnabled) + { + + if (!m_UnmanagedMemory) + { + if (!m_Pool) + { + // unmanaged + m_UnmanagedMemory = ::operator new(m_TensorInfo.GetNumBytes()); + } + else + { + m_MemoryManager->Allocate(m_Pool); + } + } + else + { + throw InvalidArgumentException("TosaRefTensorHandle::Allocate Trying to allocate a TosaRefTensorHandle" + "that already has allocated memory."); + } + } +} + +const void* TosaRefTensorHandle::Map(bool /*unused*/) const +{ + return GetPointer(); +} + +void* TosaRefTensorHandle::GetPointer() const +{ + if (m_UnmanagedMemory) + { + return m_UnmanagedMemory; + } + else if (m_Pool) + { + return m_MemoryManager->GetPointer(m_Pool); + } + else + { + throw NullPointerException("TosaRefTensorHandle::GetPointer called on unmanaged, unallocated tensor handle"); + } +} + +void TosaRefTensorHandle::CopyOutTo(void* dest) const +{ + const void *src = GetPointer(); + ARMNN_ASSERT(src); + memcpy(dest, src, m_TensorInfo.GetNumBytes()); +} + +void TosaRefTensorHandle::CopyInFrom(const void* src) +{ + void *dest = GetPointer(); + ARMNN_ASSERT(dest); + memcpy(dest, src, m_TensorInfo.GetNumBytes()); +} + +bool TosaRefTensorHandle::Import(void* memory, MemorySource source) +{ + if (m_ImportFlags & static_cast(source)) + { + if (m_IsImportEnabled && source == MemorySource::Malloc) + { + // Check memory alignment + if(!CanBeImported(memory, source)) + { + if (m_Imported) + { + m_Imported = false; + m_UnmanagedMemory = nullptr; + } + return false; + } + + // m_UnmanagedMemory not yet allocated. + if (!m_Imported && !m_UnmanagedMemory) + { + m_UnmanagedMemory = memory; + m_Imported = true; + return true; + } + + // m_UnmanagedMemory initially allocated with Allocate(). + if (!m_Imported && m_UnmanagedMemory) + { + return false; + } + + // m_UnmanagedMemory previously imported. + if (m_Imported) + { + m_UnmanagedMemory = memory; + return true; + } + } + } + + return false; +} + +bool TosaRefTensorHandle::CanBeImported(void* memory, MemorySource source) +{ + if (m_ImportFlags & static_cast(source)) + { + if (m_IsImportEnabled && source == MemorySource::Malloc) + { + uintptr_t alignment = GetDataTypeSize(m_TensorInfo.GetDataType()); + if (reinterpret_cast(memory) % alignment) + { + return false; + } + return true; + } + } + return false; +} + +} diff --git a/src/backends/tosaReference/TosaRefTensorHandle.hpp b/src/backends/tosaReference/TosaRefTensorHandle.hpp new file mode 100644 index 0000000000..431d56bd37 --- /dev/null +++ b/src/backends/tosaReference/TosaRefTensorHandle.hpp @@ -0,0 +1,82 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// +#pragma once + +#include + +#include "TosaRefMemoryManager.hpp" + +namespace armnn +{ + +// An implementation of ITensorHandle with simple "bump the pointer" memory-management behaviour +class TosaRefTensorHandle : public ITensorHandle +{ +public: + TosaRefTensorHandle(const TensorInfo& tensorInfo, std::shared_ptr &memoryManager); + + TosaRefTensorHandle(const TensorInfo& tensorInfo, MemorySourceFlags importFlags); + + ~TosaRefTensorHandle(); + + virtual void Manage() override; + + virtual void Allocate() override; + + virtual ITensorHandle* GetParent() const override + { + return nullptr; + } + + virtual const void* Map(bool /* blocking = true */) const override; + using ITensorHandle::Map; + + virtual void Unmap() const override + {} + + TensorShape GetStrides() const override + { + return GetUnpaddedTensorStrides(m_TensorInfo); + } + + TensorShape GetShape() const override + { + return m_TensorInfo.GetShape(); + } + + const TensorInfo& GetTensorInfo() const + { + return m_TensorInfo; + } + + virtual MemorySourceFlags GetImportFlags() const override + { + return m_ImportFlags; + } + + virtual bool Import(void* memory, MemorySource source) override; + virtual bool CanBeImported(void* memory, MemorySource source) override; + +private: + // Only used for testing + void CopyOutTo(void*) const override; + void CopyInFrom(const void*) override; + + void* GetPointer() const; + + TosaRefTensorHandle(const TosaRefTensorHandle& other) = delete; // noncopyable + TosaRefTensorHandle& operator=(const TosaRefTensorHandle& other) = delete; //noncopyable + + TensorInfo m_TensorInfo; + + std::shared_ptr m_MemoryManager; + TosaRefMemoryManager::Pool* m_Pool; + mutable void* m_UnmanagedMemory; + MemorySourceFlags m_ImportFlags; + bool m_Imported; + bool m_IsImportEnabled; +}; + +} diff --git a/src/backends/tosaReference/TosaRefTensorHandleFactory.cpp b/src/backends/tosaReference/TosaRefTensorHandleFactory.cpp new file mode 100644 index 0000000000..62ada6fdf8 --- /dev/null +++ b/src/backends/tosaReference/TosaRefTensorHandleFactory.cpp @@ -0,0 +1,91 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "TosaRefTensorHandleFactory.hpp" +#include "TosaRefTensorHandle.hpp" + +#include + +namespace armnn +{ + +using FactoryId = ITensorHandleFactory::FactoryId; + +const FactoryId& TosaRefTensorHandleFactory::GetIdStatic() +{ + static const FactoryId s_Id(TosaRefTensorHandleFactoryId()); + return s_Id; +} + +std::unique_ptr TosaRefTensorHandleFactory::CreateSubTensorHandle(ITensorHandle& parent, + const TensorShape& subTensorShape, + const unsigned int* subTensorOrigin) + const +{ + IgnoreUnused(parent, subTensorShape, subTensorOrigin); + return nullptr; +} + +std::unique_ptr TosaRefTensorHandleFactory::CreateTensorHandle(const TensorInfo& tensorInfo) const +{ + return std::make_unique(tensorInfo, m_MemoryManager); +} + +std::unique_ptr TosaRefTensorHandleFactory::CreateTensorHandle(const TensorInfo& tensorInfo, + DataLayout dataLayout) const +{ + IgnoreUnused(dataLayout); + return std::make_unique(tensorInfo, m_MemoryManager); +} + +std::unique_ptr TosaRefTensorHandleFactory::CreateTensorHandle(const TensorInfo& tensorInfo, + const bool IsMemoryManaged) const +{ + if (IsMemoryManaged) + { + return std::make_unique(tensorInfo, m_MemoryManager); + } + else + { + return std::make_unique(tensorInfo, m_ImportFlags); + } +} + +std::unique_ptr TosaRefTensorHandleFactory::CreateTensorHandle(const TensorInfo& tensorInfo, + DataLayout dataLayout, + const bool IsMemoryManaged) const +{ + IgnoreUnused(dataLayout); + if (IsMemoryManaged) + { + return std::make_unique(tensorInfo, m_MemoryManager); + } + else + { + return std::make_unique(tensorInfo, m_ImportFlags); + } +} + +const FactoryId& TosaRefTensorHandleFactory::GetId() const +{ + return GetIdStatic(); +} + +bool TosaRefTensorHandleFactory::SupportsSubTensors() const +{ + return false; +} + +MemorySourceFlags TosaRefTensorHandleFactory::GetExportFlags() const +{ + return m_ExportFlags; +} + +MemorySourceFlags TosaRefTensorHandleFactory::GetImportFlags() const +{ + return m_ImportFlags; +} + +} // namespace armnn \ No newline at end of file diff --git a/src/backends/tosaReference/TosaRefTensorHandleFactory.hpp b/src/backends/tosaReference/TosaRefTensorHandleFactory.hpp new file mode 100644 index 0000000000..17dd1d4d06 --- /dev/null +++ b/src/backends/tosaReference/TosaRefTensorHandleFactory.hpp @@ -0,0 +1,61 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include "TosaRefMemoryManager.hpp" + +#include + +namespace armnn +{ + +constexpr const char * TosaRefTensorHandleFactoryId() { return "Arm/TosaRef/TensorHandleFactory"; } + +class TosaRefTensorHandleFactory : public ITensorHandleFactory +{ + +public: + TosaRefTensorHandleFactory(std::shared_ptr mgr) + : m_MemoryManager(mgr) + , m_ImportFlags(static_cast(MemorySource::Malloc)) + , m_ExportFlags(static_cast(MemorySource::Malloc)) + {} + + std::unique_ptr CreateSubTensorHandle(ITensorHandle& parent, + TensorShape const& subTensorShape, + unsigned int const* subTensorOrigin) const override; + + std::unique_ptr CreateTensorHandle(const TensorInfo& tensorInfo) const override; + + std::unique_ptr CreateTensorHandle(const TensorInfo& tensorInfo, + DataLayout dataLayout) const override; + + std::unique_ptr CreateTensorHandle(const TensorInfo& tensorInfo, + const bool IsMemoryManaged) const override; + + std::unique_ptr CreateTensorHandle(const TensorInfo& tensorInfo, + DataLayout dataLayout, + const bool IsMemoryManaged) const override; + + static const FactoryId& GetIdStatic(); + + const FactoryId& GetId() const override; + + bool SupportsSubTensors() const override; + + MemorySourceFlags GetExportFlags() const override; + + MemorySourceFlags GetImportFlags() const override; + +private: + mutable std::shared_ptr m_MemoryManager; + MemorySourceFlags m_ImportFlags; + MemorySourceFlags m_ExportFlags; + +}; + +} // namespace armnn + diff --git a/src/backends/tosaReference/TosaRefWorkloadFactory.cpp b/src/backends/tosaReference/TosaRefWorkloadFactory.cpp new file mode 100644 index 0000000000..e6b5f9e934 --- /dev/null +++ b/src/backends/tosaReference/TosaRefWorkloadFactory.cpp @@ -0,0 +1,126 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// +#include +#include +#include +#include +#include +#include "TosaRefWorkloadFactory.hpp" +#include "TosaRefBackendId.hpp" +#include "workloads/TosaRefWorkloads.hpp" +#include "TosaRefTensorHandle.hpp" +#include "TosaRefWorkloadFactory.hpp" + + +namespace armnn +{ + +namespace +{ +static const BackendId s_Id{TosaRefBackendId()}; +} +template +std::unique_ptr TosaRefWorkloadFactory::MakeWorkload(const QueueDescriptorType& descriptor, + const WorkloadInfo& info) const +{ + return MakeWorkloadHelper + (descriptor, info); +} + +template +bool IsDataType(const WorkloadInfo& info) +{ + auto checkType = [](const TensorInfo& tensorInfo) {return tensorInfo.GetDataType() == ArmnnType;}; + auto it = std::find_if(std::begin(info.m_InputTensorInfos), std::end(info.m_InputTensorInfos), checkType); + if (it != std::end(info.m_InputTensorInfos)) + { + return true; + } + it = std::find_if(std::begin(info.m_OutputTensorInfos), std::end(info.m_OutputTensorInfos), checkType); + if (it != std::end(info.m_OutputTensorInfos)) + { + return true; + } + return false; +} + +TosaRefWorkloadFactory::TosaRefWorkloadFactory(const std::shared_ptr& memoryManager) + : m_MemoryManager(memoryManager) +{ +} + +TosaRefWorkloadFactory::TosaRefWorkloadFactory() + : m_MemoryManager(new TosaRefMemoryManager()) +{ +} + +const BackendId& TosaRefWorkloadFactory::GetBackendId() const +{ + return s_Id; +} + +bool TosaRefWorkloadFactory::IsLayerSupported(const Layer& layer, + Optional dataType, + std::string& outReasonIfUnsupported) +{ + return IWorkloadFactory::IsLayerSupported(s_Id, layer, dataType, outReasonIfUnsupported); +} + +bool TosaRefWorkloadFactory::IsLayerSupported(const IConnectableLayer& layer, + Optional dataType, + std::string& outReasonIfUnsupported, + const ModelOptions& modelOptions) +{ + return IWorkloadFactory::IsLayerSupported(s_Id, layer, dataType, outReasonIfUnsupported, modelOptions); +} + +std::unique_ptr TosaRefWorkloadFactory::CreateTensorHandle(const TensorInfo& tensorInfo, + const bool isMemoryManaged) const +{ + if (isMemoryManaged) + { + return std::make_unique(tensorInfo, m_MemoryManager); + } + else + { + return std::make_unique(tensorInfo, static_cast(MemorySource::Malloc)); + } +} + +std::unique_ptr TosaRefWorkloadFactory::CreateTensorHandle(const TensorInfo& tensorInfo, + DataLayout dataLayout, + const bool isMemoryManaged) const +{ + // For TosaRef it is okay to make the TensorHandle memory managed as it can also store a pointer + // to unmanaged memory. This also ensures memory alignment. + IgnoreUnused(isMemoryManaged, dataLayout); + + if (isMemoryManaged) + { + return std::make_unique(tensorInfo, m_MemoryManager); + } + else + { + return std::make_unique(tensorInfo, static_cast(MemorySource::Malloc)); + } +} + +std::unique_ptr TosaRefWorkloadFactory::CreateWorkload(LayerType type, + const QueueDescriptor& descriptor, + const WorkloadInfo& info) const +{ + switch(type) + { + case LayerType::PreCompiled: + { + auto precompiledQueueDescriptor = PolymorphicDowncast(&descriptor); + return std::make_unique(*precompiledQueueDescriptor, info); + } + default: + return nullptr; + } +} + +} // namespace armnn diff --git a/src/backends/tosaReference/TosaRefWorkloadFactory.hpp b/src/backends/tosaReference/TosaRefWorkloadFactory.hpp new file mode 100644 index 0000000000..1a5c1f2ef5 --- /dev/null +++ b/src/backends/tosaReference/TosaRefWorkloadFactory.hpp @@ -0,0 +1,68 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// +#pragma once + +#include "TosaRefMemoryManager.hpp" + +#include +#include +#include + + +namespace armnn +{ + +// Reference workload factory. +class TosaRefWorkloadFactory : public IWorkloadFactory +{ +public: + explicit TosaRefWorkloadFactory(const std::shared_ptr& memoryManager); + TosaRefWorkloadFactory(); + + ~TosaRefWorkloadFactory() {} + + const BackendId& GetBackendId() const override; + + static bool IsLayerSupported(const Layer& layer, + Optional dataType, + std::string& outReasonIfUnsupported); + + static bool IsLayerSupported(const IConnectableLayer& layer, + Optional dataType, + std::string& outReasonIfUnsupported, + const ModelOptions& modelOptions); + + bool SupportsSubTensors() const override { return false; } + + ARMNN_DEPRECATED_MSG("Use ITensorHandleFactory::CreateSubTensorHandle instead") + std::unique_ptr CreateSubTensorHandle(ITensorHandle& parent, + TensorShape const& subTensorShape, + unsigned int const* subTensorOrigin) const override + { + IgnoreUnused(parent, subTensorShape, subTensorOrigin); + return nullptr; + } + + ARMNN_DEPRECATED_MSG("Use ITensorHandleFactory::CreateTensorHandle instead") + std::unique_ptr CreateTensorHandle(const TensorInfo& tensorInfo, + const bool IsMemoryManaged = true) const override; + + ARMNN_DEPRECATED_MSG("Use ITensorHandleFactory::CreateTensorHandle instead") + std::unique_ptr CreateTensorHandle(const TensorInfo& tensorInfo, + DataLayout dataLayout, + const bool IsMemoryManaged = true) const override; + + std::unique_ptr CreateWorkload(LayerType type, + const QueueDescriptor& descriptor, + const WorkloadInfo& info) const override; + +private: + template + std::unique_ptr MakeWorkload(const QueueDescriptorType& descriptor, const WorkloadInfo& info) const; + + mutable std::shared_ptr m_MemoryManager; +}; + +} // namespace armnn diff --git a/src/backends/tosaReference/backend.cmake b/src/backends/tosaReference/backend.cmake new file mode 100644 index 0000000000..2867b209a4 --- /dev/null +++ b/src/backends/tosaReference/backend.cmake @@ -0,0 +1,14 @@ +# +# Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +# SPDX-License-Identifier: MIT +# + +add_subdirectory(${PROJECT_SOURCE_DIR}/src/backends/tosaReference) +list(APPEND armnnLibraries armnnTosaRefBackend) + +if(ARMNNTOSAREF) + list(APPEND armnnLibraries armnnTosaRefBackendWorkloads) + list(APPEND armnnUnitTestLibraries armnnTosaRefBackendUnitTests) +else() + message(STATUS "TOSA Reference backend is disabled") +endif() diff --git a/src/backends/tosaReference/backend.mk b/src/backends/tosaReference/backend.mk new file mode 100644 index 0000000000..d552a6a39a --- /dev/null +++ b/src/backends/tosaReference/backend.mk @@ -0,0 +1,56 @@ +# +# Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +# SPDX-License-Identifier: MIT +# + +# BACKEND_SOURCES contains the list of files to be included +# in the Android build and it is picked up by the Android.mk +# file in the root of ArmNN + +# The variable to enable/disable the TOSA Reference backend +# (ARMNN_TOSA_REF_ENABLED is declared in android-nn-driver/Android.mk) +ifeq ($(ARMNN_TOSA_REF_ENABLED),1) + +# ARMNN_TOSA_REF_ENABLED == 1 +# Include the source files for the TOSA reference backend + +BACKEND_SOURCES := \ + TosaRefBackend.cpp \ + TosaRefLayerSupport.cpp \ + TosaRefMemoryManager.cpp \ + TosaRefRegistryInitializer.cpp \ + TosaRefTensorHandle.cpp \ + TosaRefTensorHandleFactory.cpp \ + TosaRefWorkloadFactory.cpp \ + workloads/TosaRefPreCompiledWorkload.cpp +else + +# ARMNN_TOSA_REF_ENABLED == 0 +# No source file will be compiled for the reference backend + +BACKEND_SOURCES := + +endif + +# BACKEND_TEST_SOURCES contains the list of files to be included +# in the Android unit test build (armnn-tests) and it is picked +# up by the Android.mk file in the root of ArmNN + +# The variable to enable/disable the TOSA Reference backend +# (ARMNN_TOSA_REF_ENABLED is declared in android-nn-driver/Android.mk) +ifeq ($(ARMNN_TOSA_REF_ENABLED),1) + +# ARMNN_TOSA_REF_ENABLED == 1 +# Include the source files for the TOSA Reference backend tests + +BACKEND_TEST_SOURCES := \ + test/TosaRefLayerSupportTests.cpp \ + test/TosaRefLayerTests.cpp +else + +# ARMNN_TOSA_REF_ENABLED == 0 +# No source file will be compiled for the TOSA reference backend tests + +BACKEND_TEST_SOURCES := + +endif diff --git a/src/backends/tosaReference/test/CMakeLists.txt b/src/backends/tosaReference/test/CMakeLists.txt new file mode 100644 index 0000000000..8366901605 --- /dev/null +++ b/src/backends/tosaReference/test/CMakeLists.txt @@ -0,0 +1,16 @@ +# +# Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +# SPDX-License-Identifier: MIT +# + +list(APPEND armnnTosaRefBackendUnitTests_sources + TosaRefLayerTests.cpp + TosaRefLayerSupportTests.cpp +) + +add_library(armnnTosaRefBackendUnitTests OBJECT ${armnnTosaRefBackendUnitTests_sources}) +target_include_directories(armnnTosaRefBackendUnitTests PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(armnnTosaRefBackendUnitTests PRIVATE ${PROJECT_SOURCE_DIR}/src/armnnUtils) +target_include_directories(armnnTosaRefBackendUnitTests PRIVATE ${PROJECT_SOURCE_DIR}/src/armnnTestUtils) +target_include_directories(armnnTosaRefBackendUnitTests PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) +target_include_directories(armnnTosaRefBackendUnitTests PRIVATE ${PROJECT_SOURCE_DIR}/third-party/doctest) diff --git a/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp b/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp new file mode 100644 index 0000000000..99f7fd2705 --- /dev/null +++ b/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp @@ -0,0 +1,65 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + + +#include +#include +#include + +#include + +#include + +TEST_SUITE("TosaRefLayerSupported") +{ + +TEST_CASE("IsLayerSupportedTosaReferenceAddition") +{ + armnn::TensorShape shape0 = {1,1,3,4}; + armnn::TensorShape shape1 = {4}; + armnn::TensorShape outShape = {1,1,3,4}; + armnn::TensorInfo in0(shape0, armnn::DataType::Float32); + armnn::TensorInfo in1(shape1, armnn::DataType::Float32); + armnn::TensorInfo out(outShape, armnn::DataType::Float32); + + armnn::BaseDescriptor desc; + armnn::TosaRefLayerSupport supportChecker; + std::string reasonIfNotSupported; + auto supported = supportChecker.IsLayerSupported(armnn::LayerType::Addition, + {in0, in1, out}, + desc, + armnn::EmptyOptional(), + armnn::EmptyOptional(), + reasonIfNotSupported); + + CHECK(supported); +} + +TEST_CASE("IsLayerSupportedTosaReferenceAdditionUnsupported") +{ + armnn::TensorShape shape0 = {1,1,3,4}; + armnn::TensorShape shape1 = {4}; + armnn::TensorShape outShape = {1,1,3,4}; + armnn::TensorInfo in0(shape0, armnn::DataType::Signed64); + armnn::TensorInfo in1(shape1, armnn::DataType::Signed64); + armnn::TensorInfo out(outShape, armnn::DataType::Signed64); + + armnn::BaseDescriptor desc; + armnn::TosaRefLayerSupport supportChecker; + std::string reasonIfNotSupported; + auto supported = supportChecker.IsLayerSupported(armnn::LayerType::Addition, + {in0, in1, out}, + desc, + armnn::EmptyOptional(), + armnn::EmptyOptional(), + reasonIfNotSupported); + + CHECK(!supported); + REQUIRE(reasonIfNotSupported.find("TOSA Reference addition: Op_ADD_input0_") != std::string::npos); + REQUIRE(reasonIfNotSupported.find("TOSA Reference addition: Op_ADD_input1_") != std::string::npos); + REQUIRE(reasonIfNotSupported.find("TOSA Reference addition: Op_ADD_output0_") != std::string::npos); +} + +} diff --git a/src/backends/tosaReference/test/TosaRefLayerTests.cpp b/src/backends/tosaReference/test/TosaRefLayerTests.cpp new file mode 100644 index 0000000000..fc0a557fa5 --- /dev/null +++ b/src/backends/tosaReference/test/TosaRefLayerTests.cpp @@ -0,0 +1,13 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "TosaRefWorkloadFactoryHelper.hpp" + +#include + +#include + +#include + diff --git a/src/backends/tosaReference/test/TosaRefWorkloadFactoryHelper.hpp b/src/backends/tosaReference/test/TosaRefWorkloadFactoryHelper.hpp new file mode 100644 index 0000000000..560192a3a8 --- /dev/null +++ b/src/backends/tosaReference/test/TosaRefWorkloadFactoryHelper.hpp @@ -0,0 +1,46 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include + +#include + +#include +#include +#include "tosaReference/TosaRefTensorHandleFactory.hpp" + +namespace +{ + +template<> +struct WorkloadFactoryHelper +{ + static armnn::IBackendInternal::IMemoryManagerSharedPtr GetMemoryManager() + { + armnn::TosaRefBackend backend; + return backend.CreateMemoryManager(); + } + + static armnn::TosaRefWorkloadFactory GetFactory( + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager = nullptr) + { + IgnoreUnused(memoryManager); + return armnn::TosaRefWorkloadFactory(); + } + + static armnn::TosaRefTensorHandleFactory GetTensorHandleFactory( + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager = nullptr) + { + + return armnn::TosaRefTensorHandleFactory( + armnn::PolymorphicPointerDowncast(memoryManager)); + } +}; + +using TosaRefWorkloadFactoryHelper = WorkloadFactoryHelper; + +} // anonymous namespace diff --git a/src/backends/tosaReference/workloads/CMakeLists.txt b/src/backends/tosaReference/workloads/CMakeLists.txt new file mode 100644 index 0000000000..7b60c841cf --- /dev/null +++ b/src/backends/tosaReference/workloads/CMakeLists.txt @@ -0,0 +1,18 @@ +# +# Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +# SPDX-License-Identifier: MIT +# + +list(APPEND armnnTosaRefBackendWorkloads_sources + TosaRefBaseWorkload.hpp + TosaRefPreCompiledWorkload.cpp + TosaRefPreCompiledWorkload.hpp +) + +add_library(armnnTosaRefBackendWorkloads OBJECT ${armnnTosaRefBackendWorkloads_sources}) +target_include_directories(armnnTosaRefBackendWorkloads PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(armnnTosaRefBackendWorkloads PRIVATE ${PROJECT_SOURCE_DIR}/src/armnnUtils) +target_include_directories(armnnTosaRefBackendWorkloads PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) +target_include_directories(armnnTosaRefBackendWorkloads PRIVATE ${PROJECT_SOURCE_DIR}/src/profiling) +target_include_directories(armnnTosaRefBackendWorkloads PRIVATE ${PROJECT_SOURCE_DIR}/profiling/common/include) +target_include_directories(armnnTosaRefBackendWorkloads PRIVATE ${PROJECT_SOURCE_DIR}/profiling/client/include) diff --git a/src/backends/tosaReference/workloads/TosaRefBaseWorkload.hpp b/src/backends/tosaReference/workloads/TosaRefBaseWorkload.hpp new file mode 100644 index 0000000000..df82abb02e --- /dev/null +++ b/src/backends/tosaReference/workloads/TosaRefBaseWorkload.hpp @@ -0,0 +1,39 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include + +namespace armnn +{ + +template +class TosaRefBaseWorkload : public BaseWorkload +{ +public: + TosaRefBaseWorkload(const QueueDescriptor& descriptor, const WorkloadInfo& info) + : BaseWorkload(descriptor, info) + {} + + virtual bool SupportsTensorHandleReplacement() const override + { + return true; + } + + // Replace input tensor handle with the given TensorHandle + void ReplaceInputTensorHandle(ITensorHandle* tensorHandle, unsigned int slot) override + { + this->m_Data.m_Inputs[slot] = tensorHandle; + } + + // Replace output tensor handle with the given TensorHandle + void ReplaceOutputTensorHandle(ITensorHandle* tensorHandle, unsigned int slot) override + { + this->m_Data.m_Outputs[slot] = tensorHandle; + } +}; + +} //namespace armnn \ No newline at end of file diff --git a/src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.cpp b/src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.cpp new file mode 100644 index 0000000000..c4af4d40b1 --- /dev/null +++ b/src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.cpp @@ -0,0 +1,28 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "TosaRefPreCompiledWorkload.hpp" + +namespace armnn +{ + +TosaRefPreCompiledWorkload::TosaRefPreCompiledWorkload(const PreCompiledQueueDescriptor& descriptor, + const WorkloadInfo& info) + : BaseWorkload(descriptor, info) +{ + // Do nothing for now +} + +void TosaRefPreCompiledWorkload::Execute() const +{ + // Do nothing for now +} + +bool TosaRefPreCompiledWorkloadValidate(std::string*) +{ + return true; +} + +} //namespace armnn diff --git a/src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.hpp b/src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.hpp new file mode 100644 index 0000000000..30972693de --- /dev/null +++ b/src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.hpp @@ -0,0 +1,43 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include "armnn/backends/Workload.hpp" + +#include +#include +#include + +namespace armnn +{ + +bool TosaRefPreCompiledWorkloadValidate(std::string* reasonIfUnsupported); + +class TosaRefPreCompiledWorkload : public BaseWorkload +{ +public: + TosaRefPreCompiledWorkload(const PreCompiledQueueDescriptor& descriptor, + const WorkloadInfo& info); + void Execute() const override; + +private: + bool SupportsTensorHandleReplacement() const override + { + return true; + } + + void ReplaceInputTensorHandle(ITensorHandle* tensorHandle, unsigned int slot) override + { + this->m_Data.m_Inputs[slot] = tensorHandle; + } + + void ReplaceOutputTensorHandle(ITensorHandle* tensorHandle, unsigned int slot) override + { + this->m_Data.m_Outputs[slot] = tensorHandle; + } +}; + +} //namespace armnn diff --git a/src/backends/tosaReference/workloads/TosaRefWorkloads.hpp b/src/backends/tosaReference/workloads/TosaRefWorkloads.hpp new file mode 100644 index 0000000000..e7b439926b --- /dev/null +++ b/src/backends/tosaReference/workloads/TosaRefWorkloads.hpp @@ -0,0 +1,8 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include "TosaRefPreCompiledWorkload.hpp" -- cgit v1.2.1