From 8636bc705cc33fd869f64ebf24b14836d5a40b29 Mon Sep 17 00:00:00 2001 From: Finn Williams Date: Sat, 2 Oct 2021 15:06:39 +0100 Subject: IVGCVSW-6313 Support pre-importing outputs * Add ClearImportedInputs/Outputs function to IRuntime * Add UnImport function to ITensorHandle * Remove mutex from IWorkingMemHandle Change-Id: I34c9b6e1618755e10f3b4597afa1d9a9ea97e5fe Signed-off-by: Finn Williams --- src/armnn/test/RuntimeTests.cpp | 246 +++++++++++++++++++++++++++++++++------- 1 file changed, 203 insertions(+), 43 deletions(-) (limited to 'src/armnn/test') diff --git a/src/armnn/test/RuntimeTests.cpp b/src/armnn/test/RuntimeTests.cpp index abf13f5dc6..397a545878 100644 --- a/src/armnn/test/RuntimeTests.cpp +++ b/src/armnn/test/RuntimeTests.cpp @@ -64,11 +64,10 @@ TEST_CASE("RuntimeUnloadNetwork") TEST_CASE("RuntimePreImportInputs") { armnn::IRuntime::CreationOptions options; - armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options)); - - armnn::NetworkId networkIdentifier1 = 1; - + armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options)); + armnn::NetworkId networkId = 1; armnn::INetworkPtr testNetwork(armnn::INetwork::Create()); + auto inputLayer1 = testNetwork->AddInputLayer(0, "input 1 layer"); auto inputLayer2 = testNetwork->AddInputLayer(1, "input 2 layer"); auto addLayer = testNetwork->AddAdditionLayer("add layer"); @@ -78,17 +77,18 @@ TEST_CASE("RuntimePreImportInputs") inputLayer1->GetOutputSlot(0).Connect(addLayer->GetInputSlot(0)); inputLayer1->GetOutputSlot(0).SetTensorInfo(tensorInfo); + inputLayer2->GetOutputSlot(0).Connect(addLayer->GetInputSlot(1)); inputLayer2->GetOutputSlot(0).SetTensorInfo(tensorInfo); addLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); addLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo); - std::vector backends = { armnn::Compute::CpuRef }; + std::vector backends = {armnn::Compute::CpuRef}; std::string er; armnn::INetworkProperties networkProperties(true, MemorySource::Malloc, MemorySource::Undefined); - runtime->LoadNetwork(networkIdentifier1, + runtime->LoadNetwork(networkId, Optimize(*testNetwork, backends, runtime->GetDeviceSpec()), er, networkProperties); @@ -99,73 +99,233 @@ TEST_CASE("RuntimePreImportInputs") ConstTensor inputTensor1({{4}, armnn::DataType::Signed32}, inputData1.data()); ConstTensor inputTensor2({{4}, armnn::DataType::Signed32}, inputData2.data()); - Tensor outputTensor({{4}, armnn::DataType::Signed32}, output.data()); - auto importedInputVec1 = runtime->ImportInputs(networkIdentifier1, {{0, inputTensor1}}); + auto importedInputVec1 = runtime->ImportInputs(networkId, {{0, inputTensor1}}); CHECK(importedInputVec1.size() == 1); CHECK(importedInputVec1[0] == 0); - auto memHandle = runtime->CreateWorkingMemHandle(networkIdentifier1); + auto memHandle = runtime->CreateWorkingMemHandle(networkId); runtime->Execute(*memHandle.get(), {{1, inputTensor2}}, {{2, outputTensor}}, {0 /* pre-imported id */}); - for (auto val : output) - { + for (auto val: output) { CHECK(val == 30); } - auto importedInputVec2 = runtime->ImportInputs(networkIdentifier1, {{1, inputTensor2}}); + auto importedInputVec2 = runtime->ImportInputs(networkId, {{1, inputTensor2}}); CHECK(importedInputVec2.size() == 1); CHECK(importedInputVec2[0] == 1); runtime->Execute(*memHandle.get(), {{0, inputTensor1}}, {{2, outputTensor}}, {1 /* pre-imported id */}); - for (auto val : output) - { + for (auto val: output) { CHECK(val == 30); } runtime->Execute(*memHandle.get(), {}, {{2, outputTensor}}, {0, 1}); - for (auto val : output) - { + for (auto val: output) { CHECK(val == 30); } - // Duplicate ImportedInputId and LayerBindingId - CHECK_THROWS_AS(runtime->Execute(*memHandle.get(),{},{{2, outputTensor}},{0, 0}); - , armnn::InvalidArgumentException); - + CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), {}, {{2, outputTensor}}, {0, 0});, + armnn::InvalidArgumentException); // Duplicate LayerBindingId - CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), {{1, inputTensor2}}, {{2, outputTensor}},{1}); - , armnn::InvalidArgumentException); - + CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), {{1, inputTensor2}}, {{2, outputTensor}}, {1});, + armnn::InvalidArgumentException); // Incorrect ImportedInputId - CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), {{1, inputTensor2}}, {{2, outputTensor}},{10}); - , armnn::InvalidArgumentException); - + CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), {{1, inputTensor2}}, {{2, outputTensor}}, {10});, + armnn::InvalidArgumentException); // Incorrect LayerBindingId - CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), {{-2, inputTensor2}}, {{2, outputTensor}},{1}); - , armnn::InvalidArgumentException); - + CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), {{-2, inputTensor2}}, {{2, outputTensor}}, {1});, + armnn::InvalidArgumentException); // Incorrect layer binding id and ImportedInputId - CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), {{-2, inputTensor2}}, {{2, outputTensor}},{10}); - , armnn::InvalidArgumentException); - - - auto importedInputVec3 = runtime->ImportInputs(networkIdentifier1, {{1, inputTensor2}}); + CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), {{-2, inputTensor2}}, {{2, outputTensor}}, {10});, + armnn::InvalidArgumentException); + auto importedInputVec3 = runtime->ImportInputs(networkId, {{1, inputTensor2}}); CHECK(importedInputVec3[0] == 2); // Too many ImportedInputIds - CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), {}, {{2, outputTensor}},{0, 1, 2}); - , armnn::InvalidArgumentException); - + CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), {}, {{2, outputTensor}}, {0, 1, 2});, + armnn::InvalidArgumentException); // Too many InputTensors CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), - {{0, inputTensor2}, {1, inputTensor2}, {2, inputTensor2}}, - {{2, outputTensor}}); - , armnn::InvalidArgumentException); - + {{0, inputTensor2}, + {1, inputTensor2}, + {2, inputTensor2}}, + {{2, outputTensor}});, armnn::InvalidArgumentException); // Too few ImportedInputIds - CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), {}, {{2, outputTensor}},{0}); - , armnn::InvalidArgumentException); + CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), {}, {{2, outputTensor}}, {0});, + armnn::InvalidArgumentException); + runtime->ClearImportedInputs(networkId, {1}); + runtime->Execute(*memHandle.get(), {{1, inputTensor2}}, {{2, outputTensor}}, {0}, {}); + for (auto val: output) { + CHECK(val == 30); + } + // Using deleted pre-imported input + CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), {}, {{2, outputTensor}}, {0, 1}, {});, + armnn::InvalidArgumentException); + + // Trying to delete deleted pre-imported tensor + CHECK_THROWS_AS(runtime->ClearImportedInputs(networkId, {1});, armnn::InvalidArgumentException); + + // Trying to delete unknown pre-imported tensor + CHECK_THROWS_AS(runtime->ClearImportedInputs(networkId, {10});, armnn::InvalidArgumentException); +} +TEST_CASE("RuntimePreImportOutputs") +{ + armnn::IRuntime::CreationOptions options; + armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options)); + + armnn::NetworkId networkId = 1; + + armnn::INetworkPtr testNetwork(armnn::INetwork::Create()); + TensorInfo tensorInfo{{4}, armnn::DataType::Float32}; + + auto inputLayer1 = testNetwork->AddInputLayer(0, "input 1 layer"); + inputLayer1->GetOutputSlot(0).SetTensorInfo(tensorInfo); + + ActivationDescriptor activationDescriptor; + activationDescriptor.m_Function = ActivationFunction::BoundedReLu; + activationDescriptor.m_A = 2.0f; + activationDescriptor.m_B = 0.0f; + auto activationLayer1 = testNetwork->AddActivationLayer(activationDescriptor, "add layer"); + auto outputLayer1 = testNetwork->AddOutputLayer(2, "output layer"); + + inputLayer1->GetOutputSlot(0).Connect(activationLayer1->GetInputSlot(0)); + + activationLayer1->GetOutputSlot(0).Connect(outputLayer1->GetInputSlot(0)); + activationLayer1->GetOutputSlot(0).SetTensorInfo(tensorInfo); + + auto inputLayer2 = testNetwork->AddInputLayer(1, "input 1 layer"); + + activationDescriptor.m_A = 4.0f; + activationDescriptor.m_B = 2.0f; + auto activationLayer2 = testNetwork->AddActivationLayer(activationDescriptor, "add layer"); + auto outputLayer2 = testNetwork->AddOutputLayer(3, "output layer"); + + inputLayer2->GetOutputSlot(0).Connect(activationLayer2->GetInputSlot(0)); + inputLayer2->GetOutputSlot(0).SetTensorInfo(tensorInfo); + + activationLayer2->GetOutputSlot(0).Connect(outputLayer2->GetInputSlot(0)); + activationLayer2->GetOutputSlot(0).SetTensorInfo(tensorInfo); + + std::vector backends = { armnn::Compute::CpuRef }; + + std::string er; + armnn::INetworkProperties networkProperties(true, MemorySource::Malloc, MemorySource::Malloc); + runtime->LoadNetwork(networkId, + Optimize(*testNetwork, backends, runtime->GetDeviceSpec()), + er, + networkProperties); + + std::vector inputData1(4, 1.0f); + std::vector inputData2(4, 3.0f); + + std::vector outputData1(4); + std::vector outputData2(4); + + ConstTensor inputTensor1(tensorInfo, inputData1.data()); + ConstTensor inputTensor2(tensorInfo, inputData2.data()); + + Tensor outputTensor1{tensorInfo, outputData1.data()}; + Tensor outputTensor2{tensorInfo, outputData2.data()}; + + InputTensors inputTensors = {{0, inputTensor1}, {1, inputTensor2}}; + + std::pair output1{2, outputTensor1}; + std::pair output2{3, outputTensor2}; + + auto testOutputs = [&]() + { + for (auto val : outputData1) + { + CHECK(val == 1.0f); + } + + for (auto val : outputData2) + { + CHECK(val == 3.0f); + } + }; + + auto memHandle = runtime->CreateWorkingMemHandle(networkId); + + runtime->Execute(*memHandle.get(),inputTensors, {output1, output2}); + testOutputs(); + + auto importedOutputVec = runtime->ImportOutputs(networkId, {output1, output2 }); + CHECK(importedOutputVec.size() == 2); + CHECK(importedOutputVec[0] == 0); + CHECK(importedOutputVec[1] == 1); + + runtime->Execute(*memHandle.get(), inputTensors, {}, {}, importedOutputVec); + testOutputs(); + + runtime->Execute(*memHandle.get(), inputTensors, {output1}, {}, {1}); + testOutputs(); + + runtime->Execute(*memHandle.get(), inputTensors, {output2}, {}, {0}); + testOutputs(); + + auto importedInputVec = runtime->ImportInputs(networkId, inputTensors); + CHECK(importedInputVec.size() == 2); + CHECK(importedInputVec[0] == 0); + CHECK(importedInputVec[1] == 1); + + runtime->Execute(*memHandle.get(), {}, {}, importedInputVec, importedOutputVec); + testOutputs(); + + runtime->Execute(*memHandle.get(), {{0, inputTensor1}}, {output2}, {1}, {0}); + testOutputs(); + + // Too many ids + CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), inputTensors, {output1, output2}, {}, {0, 1});, + armnn::InvalidArgumentException); + + // Duplicate ids + CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), inputTensors, {output2}, {}, {1});, + armnn::InvalidArgumentException); + + // Duplicate ids + CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), inputTensors, {output1, output1}, {}, {});, + armnn::InvalidArgumentException); + + // Duplicate ids + CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), inputTensors, {}, {}, {0, 0}), + armnn::InvalidArgumentException); + + // Unknown id + CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), inputTensors, {output1}, {}, {3});, + armnn::InvalidArgumentException); + + // Unknown id + CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), inputTensors, {{4, outputTensor2}}, {}, {1});, + armnn::InvalidArgumentException); + + // Input id for output + CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), inputTensors, {{0, outputTensor2}}, {}, {1});, + armnn::InvalidArgumentException); + + // Input id for output + CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), inputTensors, {{0, outputTensor2}}, {}, {1});, + armnn::InvalidArgumentException); + + // Output id for input + CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), {{2, inputTensor1}}, {{0, outputTensor2}}, {1}, {1, 0});, + armnn::InvalidArgumentException); + + runtime->ClearImportedOutputs(networkId, {1}); + + runtime->Execute(*memHandle.get(), inputTensors, {output2}, {}, {0}); + testOutputs(); + + // Trying to use deleted pre-imported tensor + CHECK_THROWS_AS(runtime->Execute(*memHandle.get(), inputTensors, {}, {}, importedOutputVec), + armnn::InvalidArgumentException); + + // Trying to delete deleted pre-imported tensor + CHECK_THROWS_AS(runtime->ClearImportedOutputs(networkId, {1});, armnn::InvalidArgumentException); + + // Trying to delete unknown pre-imported tensor + CHECK_THROWS_AS(runtime->ClearImportedOutputs(networkId, {10});, armnn::InvalidArgumentException); } // Note: the current builds we don't do valgrind and gperftools based leak checking at the same -- cgit v1.2.1