From 15fcc7ed3163c9d4b1856955271854198c3c2696 Mon Sep 17 00:00:00 2001 From: Jan Eilers Date: Wed, 14 Jul 2021 13:50:15 +0100 Subject: IVGCVSW-6073 Add protected mode to ArmNN CreationOptions * Adds logic to the Runtime to activate protected mode * Adds ProtectedContentAllocation backend capability to ClBackend It's not fully activated yet because the CustomAllocator is missing. Will print an error message and won't register the backend but won't fail. * Extends IBackendInternal with an UseCustomAllocator function. * Adds related unit tests Signed-off-by: Jan Eilers Change-Id: I64f465c5800eb104aa90db1bbf772a4148b5072f --- include/armnn/IRuntime.hpp | 7 + include/armnn/backends/IBackendInternal.hpp | 27 +- src/armnn/Runtime.cpp | 27 ++ src/armnn/test/OptimizerTests.cpp | 346 ++++++++++++++++----- .../backendsCommon/test/DynamicBackendTests.hpp | 2 +- src/backends/cl/ClBackend.hpp | 17 +- 6 files changed, 351 insertions(+), 75 deletions(-) diff --git a/include/armnn/IRuntime.hpp b/include/armnn/IRuntime.hpp index bee61d21a9..fcb8c05e30 100644 --- a/include/armnn/IRuntime.hpp +++ b/include/armnn/IRuntime.hpp @@ -90,6 +90,7 @@ public: , m_EnableGpuProfiling(false) , m_DynamicBackendsPath("") , m_CustomAllocator(nullptr) + , m_ProtectedMode(false) {} /// If set, uses the GpuAcc tuned parameters from the given object when executing GPU workloads. @@ -108,6 +109,12 @@ public: /// Only supported for GpuAcc ICustomAllocator* m_CustomAllocator; + /// Setting this flag will allow the user to create the Runtime in protected mode. + /// It will run all the inferences on protected memory and will make sure that + /// INetworkProperties::m_ImportEnabled set to true with MemorySource::DmaBufProtected option + /// This will use Protected Memory Allocator associated with the backend + bool m_ProtectedMode; + struct ExternalProfilingOptions { ExternalProfilingOptions() diff --git a/include/armnn/backends/IBackendInternal.hpp b/include/armnn/backends/IBackendInternal.hpp index b8edfe1f71..3b4ef95703 100644 --- a/include/armnn/backends/IBackendInternal.hpp +++ b/include/armnn/backends/IBackendInternal.hpp @@ -56,6 +56,13 @@ struct BackendVersion (this->m_Major == other.m_Major && this->m_Minor <= other.m_Minor); } + + bool operator>=(const BackendVersion& other) const + { + return this->m_Major > other.m_Major || + (this->m_Major == other.m_Major && + this->m_Minor >= other.m_Minor); + } }; inline std::ostream& operator<<(std::ostream& os, const BackendVersion& backendVersion) @@ -176,7 +183,7 @@ public: MemorySourceFlags outputFlags); /// Returns the version of the Backend API - static constexpr BackendVersion GetApiVersion() { return BackendVersion(1, 0); } + static constexpr BackendVersion GetApiVersion() { return BackendVersion(1, 1); } /// Returns a BackendCapability if the backend lists the capability /// The BackendCapability must then be inspected to check whether or not that BackendCapability is supported @@ -189,6 +196,24 @@ public: /// Returns true if backend support the capability false otherwise ARMNN_DEPRECATED_MSG("This function has been deprecated in favour of GetCapability") virtual bool HasCapability(BackendCapability /*capabilityClass*/) const { return false; } + + /// Signals the backend to use a custom memory allocator provided by the user + /// + /// \param errMsg - Optional string variable to return error messages + /// \return - Returns true if switching to custom allocator was successful + virtual bool UseCustomMemoryAllocator(armnn::Optional errMsg) + { + if (errMsg) + { + std::stringstream message; + message << "The backend " << GetId() << " doesn't support using a custom allocator. This error might" + " be related with the protected mode if the backend doesn't" + " fully support it."; + + errMsg.value() = message.str(); + } + return false; + } }; using IBackendInternalUniquePtr = std::unique_ptr; diff --git a/src/armnn/Runtime.cpp b/src/armnn/Runtime.cpp index f16d186191..c2b748653d 100644 --- a/src/armnn/Runtime.cpp +++ b/src/armnn/Runtime.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -282,6 +283,32 @@ RuntimeImpl::RuntimeImpl(const IRuntime::CreationOptions& options) auto backend = factoryFun(); ARMNN_ASSERT(backend.get() != nullptr); + // If the runtime is created in protected mode only add backends that support this mode + if (options.m_ProtectedMode) + { + // check if backend supports ProtectedMode + using BackendCapability = BackendOptions::BackendOption; + BackendCapability protectedContentCapability {"ProtectedContentAllocation", true}; + if (!HasCapability(protectedContentCapability, id)) + { + // Protected Content Allocation is not supported by the backend + // backend should not be registered + ARMNN_LOG(warning) << "Backend " + << id + << " is not registered as does not support protected content allocation \n"; + continue; + } + std::string err; + if (!backend->UseCustomMemoryAllocator(err)) + { + ARMNN_LOG(error) << "The backend " + << id + << " reported an error when entering protected mode. Backend won't be used." + << " ErrorMsg: " << err; + continue; + } + } + auto context = backend->CreateBackendContext(options); // backends are allowed to return nullptrs if they diff --git a/src/armnn/test/OptimizerTests.cpp b/src/armnn/test/OptimizerTests.cpp index d4e2d499d5..19bd58193a 100644 --- a/src/armnn/test/OptimizerTests.cpp +++ b/src/armnn/test/OptimizerTests.cpp @@ -139,6 +139,153 @@ void CreateLSTMLayerHelper(Graph &graph, bool CifgEnabled) Connect(layer, output, lstmTensorInfo3, 3, 0); } + +class MockLayerSupport : public LayerSupportBase +{ +public: + bool IsInputSupported(const TensorInfo& /*input*/, + Optional /*reasonIfUnsupported = EmptyOptional()*/) const override + { + return true; + } + + bool IsOutputSupported(const TensorInfo& /*input*/, + Optional /*reasonIfUnsupported = EmptyOptional()*/) const override + { + return true; + } + + bool IsActivationSupported(const TensorInfo& /*input0*/, + const TensorInfo& /*output*/, + const ActivationDescriptor& /*descriptor*/, + Optional /*reasonIfUnsupported = EmptyOptional()*/) const override + { + return true; + } +}; + +template +class MockBackend : public IBackendInternal +{ +public: + MockBackend() : + m_BackendCapabilities(NamePolicy::GetIdStatic(), {{"NullCapability", false}}), + m_CustomAllocator(false) {}; + MockBackend(const BackendCapabilities& capabilities) : + m_BackendCapabilities(capabilities), + m_CustomAllocator(false) {}; + ~MockBackend() = default; + + static const BackendId& GetIdStatic() + { + return NamePolicy::GetIdStatic(); + } + const BackendId& GetId() const override + { + return GetIdStatic(); + } + + IBackendInternal::IMemoryManagerUniquePtr CreateMemoryManager() const override + { + return nullptr; + }; + + IBackendInternal::IWorkloadFactoryPtr + CreateWorkloadFactory(const IBackendInternal::IMemoryManagerSharedPtr&) const override + { + return nullptr; + } + + IBackendInternal::IBackendContextPtr CreateBackendContext(const IRuntime::CreationOptions&) const override + { + return nullptr; + } + + IBackendInternal::Optimizations GetOptimizations() const override + { + return {}; + } + IBackendInternal::ILayerSupportSharedPtr GetLayerSupport() const override + { + return std::make_shared(); + } + + OptimizationViews OptimizeSubgraphView(const SubgraphView&) const override + { + return {}; + }; + + BackendCapabilities GetCapabilities() const override + { + return m_BackendCapabilities; + }; + + virtual bool UseCustomMemoryAllocator(armnn::Optional errMsg) override + { + IgnoreUnused(errMsg); + m_CustomAllocator = true; + return m_CustomAllocator; + } + + BackendCapabilities m_BackendCapabilities; + bool m_CustomAllocator; +}; + +template +class NoProtectedModeMockBackend : public IBackendInternal +{ +public: + NoProtectedModeMockBackend() : m_BackendCapabilities(NamePolicy::GetIdStatic(), {{"NullCapability", false}}) {}; + NoProtectedModeMockBackend(const BackendCapabilities& capabilities) : m_BackendCapabilities(capabilities) {}; + ~NoProtectedModeMockBackend() = default; + + static const BackendId& GetIdStatic() + { + return NamePolicy::GetIdStatic(); + } + const BackendId& GetId() const override + { + return GetIdStatic(); + } + + IBackendInternal::IMemoryManagerUniquePtr CreateMemoryManager() const override + { + return nullptr; + }; + + IBackendInternal::IWorkloadFactoryPtr + CreateWorkloadFactory(const IBackendInternal::IMemoryManagerSharedPtr&) const override + { + return nullptr; + } + + IBackendInternal::IBackendContextPtr CreateBackendContext(const IRuntime::CreationOptions&) const override + { + return nullptr; + } + + IBackendInternal::Optimizations GetOptimizations() const override + { + return {}; + } + IBackendInternal::ILayerSupportSharedPtr GetLayerSupport() const override + { + return std::make_shared(); + } + + OptimizationViews OptimizeSubgraphView(const SubgraphView&) const override + { + return {}; + }; + + BackendCapabilities GetCapabilities() const override + { + return m_BackendCapabilities; + }; + + BackendCapabilities m_BackendCapabilities; +}; + } // namespace TEST_SUITE("Optimizer") @@ -543,77 +690,6 @@ TEST_CASE("DetectionPostProcessValidateTensorShapes") CHECK_NOTHROW(graph.InferTensorInfos()); } -class MockLayerSupport : public LayerSupportBase -{ -public: - bool IsInputSupported(const TensorInfo& /*input*/, - Optional /*reasonIfUnsupported = EmptyOptional()*/) const override - { - return true; - } - - bool IsOutputSupported(const TensorInfo& /*input*/, - Optional /*reasonIfUnsupported = EmptyOptional()*/) const override - { - return true; - } - - bool IsActivationSupported(const TensorInfo& /*input0*/, - const TensorInfo& /*output*/, - const ActivationDescriptor& /*descriptor*/, - Optional /*reasonIfUnsupported = EmptyOptional()*/) const override - { - return true; - } -}; - -template -class MockBackend : public IBackendInternal -{ -public: - MockBackend() = default; - ~MockBackend() = default; - - static const BackendId& GetIdStatic() - { - return NamePolicy::GetIdStatic(); - } - const BackendId& GetId() const override - { - return GetIdStatic(); - } - - IBackendInternal::IMemoryManagerUniquePtr CreateMemoryManager() const override - { - return nullptr; - }; - - IBackendInternal::IWorkloadFactoryPtr - CreateWorkloadFactory(const IBackendInternal::IMemoryManagerSharedPtr&) const override - { - return nullptr; - } - - IBackendInternal::IBackendContextPtr CreateBackendContext(const IRuntime::CreationOptions&) const override - { - return nullptr; - } - - IBackendInternal::Optimizations GetOptimizations() const override - { - return {}; - } - IBackendInternal::ILayerSupportSharedPtr GetLayerSupport() const override - { - return std::make_shared(); - } - - OptimizationViews OptimizeSubgraphView(const SubgraphView&) const override - { - return {}; - }; -}; - TEST_CASE("BackendCapabilityTest") { BackendId backendId = "MockBackend"; @@ -848,4 +924,132 @@ TEST_CASE("OptimizeForExclusiveConnectionsWithoutFuseTest") &IsLayerOfType, &IsLayerOfType)); } +} // Optimizer TestSuite + +TEST_SUITE("Runtime") +{ +// This test really belongs into RuntimeTests.cpp but it requires all sort of MockBackends which are +// already defined here +TEST_CASE("RuntimeProtectedModeOption") +{ + using namespace armnn; + + struct MockPolicy + { + static const BackendId& GetIdStatic() + { + static BackendId id = "MockBackend"; + return id; + } + }; + + struct ProtectedPolicy + { + static const BackendId& GetIdStatic() + { + static BackendId id = "MockBackendProtectedContent"; + return id; + } + }; + + struct SillyPolicy + { + static const BackendId& GetIdStatic() + { + static BackendId id = "SillyMockBackend"; + return id; + } + }; + + BackendCapabilities mockBackendCapabilities("MockBackend", + { + {"ProtectedContentAllocation", false} + }); + BackendCapabilities mockProtectedBackendCapabilities("MockBackendProtectedContent", + { + {"ProtectedContentAllocation", true} + }); + + auto& backendRegistry = BackendRegistryInstance(); + + // clean up from previous test runs + std::vector mockBackends = {"MockBackend", "MockBackendProtectedContent", "SillyMockBackend"}; + for (auto& backend : mockBackends) + { + backendRegistry.Deregister(backend); + } + + // Create a bunch of MockBackends with different capabilities + // 1. Doesn't support protected mode even though it knows about this capability + backendRegistry.Register("MockBackend", [mockBackendCapabilities]() + { + return std::make_unique>(mockBackendCapabilities); + }); + // 2. Supports protected mode and has it implemented correctly + backendRegistry.Register("MockBackendProtectedContent", [mockProtectedBackendCapabilities]() + { + return std::make_unique>(mockProtectedBackendCapabilities); + }); + // 3. Claims to support protected mode but doesn't have the UseCustomMemoryAllocator function implemented + backendRegistry.Register("SillyMockBackend", [mockProtectedBackendCapabilities]() + { + return std::make_unique>(mockProtectedBackendCapabilities); + }); + + // Creates a runtime that is not in protected mode + { + IRuntime::CreationOptions creationOptions; + creationOptions.m_ProtectedMode = false; + + IRuntimePtr run = IRuntime::Create(creationOptions); + + const armnn::BackendIdSet supportedDevices = run->GetDeviceSpec().GetSupportedBackends(); + // Both MockBackends that are registered should show up in the runtimes supported backends list + for (auto& backend : mockBackends) + { + CHECK(std::find(supportedDevices.cbegin(), supportedDevices.cend(), backend) != supportedDevices.cend()); + } + } + + // If the runtime is in protected mode only backends that support protected content should be added + { + IRuntime::CreationOptions creationOptions; + creationOptions.m_ProtectedMode = true; + + IRuntimePtr run = IRuntime::Create(creationOptions); + + const armnn::BackendIdSet supportedDevices = run->GetDeviceSpec().GetSupportedBackends(); + // Only the MockBackends that claims support for protected content should show up in the + // runtimes supported backends list + CHECK(std::find(supportedDevices.cbegin(), + supportedDevices.cend(), + "MockBackendProtectedContent") != supportedDevices.cend()); + CHECK(std::find(supportedDevices.cbegin(), + supportedDevices.cend(), + "MockBackend") == supportedDevices.cend()); + CHECK(std::find(supportedDevices.cbegin(), + supportedDevices.cend(), + "SillyMockBackend") == supportedDevices.cend()); + } + + // If the runtime is in protected mode only backends that support protected content should be added + { + IRuntime::CreationOptions creationOptions; + creationOptions.m_ProtectedMode = true; + + IRuntimePtr run = IRuntime::Create(creationOptions); + + const armnn::BackendIdSet supportedDevices = run->GetDeviceSpec().GetSupportedBackends(); + // Only the MockBackend that claims support for protected content should show up in the + // runtimes supported backends list + CHECK(std::find(supportedDevices.cbegin(), + supportedDevices.cend(), + "MockBackendProtectedContent") != supportedDevices.cend()); + + CHECK(std::find(supportedDevices.cbegin(), + supportedDevices.cend(), + "MockBackend") == supportedDevices.cend()); + } + +} } diff --git a/src/backends/backendsCommon/test/DynamicBackendTests.hpp b/src/backends/backendsCommon/test/DynamicBackendTests.hpp index cfcdf8e59c..f49c36e5b1 100644 --- a/src/backends/backendsCommon/test/DynamicBackendTests.hpp +++ b/src/backends/backendsCommon/test/DynamicBackendTests.hpp @@ -560,7 +560,7 @@ void CreateDynamicBackendObjectInvalidInterface6TestImpl() BackendVersion dynamicBackendVersion; CHECK_NOTHROW(dynamicBackendVersion = dynamicBackend->GetBackendVersion()); - CHECK((dynamicBackendVersion == BackendVersion({ 1, 0 }))); + CHECK((dynamicBackendVersion >= BackendVersion({ 1, 0 }))); IBackendInternalUniquePtr dynamicBackendInstance1; CHECK_THROWS_AS(dynamicBackendInstance1 = dynamicBackend->GetBackend(), RuntimeException); diff --git a/src/backends/cl/ClBackend.hpp b/src/backends/cl/ClBackend.hpp index db03cfeff0..c742c0b204 100644 --- a/src/backends/cl/ClBackend.hpp +++ b/src/backends/cl/ClBackend.hpp @@ -13,13 +13,14 @@ namespace armnn const BackendCapabilities gpuAccCapabilities("GpuAcc", { {"NonConstWeights", false}, - {"AsyncExecution", false} + {"AsyncExecution", false}, + {"ProtectedContentAllocation", true} }); class ClBackend : public IBackendInternal { public: - ClBackend() = default; + ClBackend() : m_EnableCustomAllocator(false) {}; ~ClBackend() = default; static const BackendId& GetIdStatic(); @@ -70,6 +71,18 @@ public: { return gpuAccCapabilities; }; + + virtual bool UseCustomMemoryAllocator(armnn::Optional errMsg) override + { + IgnoreUnused(errMsg); + + // Set flag to signal the backend to use a custom memory allocator + m_EnableCustomAllocator = true; + + return m_EnableCustomAllocator; + } + + bool m_EnableCustomAllocator; }; } // namespace armnn -- cgit v1.2.1