aboutsummaryrefslogtreecommitdiff
path: root/src/armnn/test/RuntimeTests.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/armnn/test/RuntimeTests.cpp')
-rw-r--r--src/armnn/test/RuntimeTests.cpp190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/armnn/test/RuntimeTests.cpp b/src/armnn/test/RuntimeTests.cpp
new file mode 100644
index 0000000000..117df5e55a
--- /dev/null
+++ b/src/armnn/test/RuntimeTests.cpp
@@ -0,0 +1,190 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// See LICENSE file in the project root for full license information.
+//
+#include <boost/test/unit_test.hpp>
+
+#include "armnn/TypesUtils.hpp"
+
+#include "armnn/IRuntime.hpp"
+#include "armnn/INetwork.hpp"
+#include "armnn/Descriptors.hpp"
+#include "Runtime.hpp"
+
+#ifdef WITH_VALGRIND
+#include "valgrind/memcheck.h"
+#endif
+
+#include <boost/core/ignore_unused.hpp>
+
+namespace armnn
+{
+
+void RuntimeLoadedNetworksReserve(armnn::Runtime* runtime)
+{
+ runtime->m_LoadedNetworks.reserve(1);
+}
+
+}
+
+BOOST_AUTO_TEST_SUITE(Runtime)
+
+BOOST_AUTO_TEST_CASE(RuntimeUnloadNetwork)
+{
+ // build 2 mock-networks and load them into the runtime
+ armnn::IRuntimePtr runtime(armnn::IRuntime::Create(armnn::Compute::CpuRef));
+
+ // mock network 1
+ armnn::NetworkId networkIdentifier1 = 1;
+ armnn::INetworkPtr mockNetwork1(armnn::INetwork::Create());
+ mockNetwork1->AddInputLayer(0, "test layer");
+ runtime->LoadNetwork(networkIdentifier1, Optimize(*mockNetwork1, runtime->GetDeviceSpec()));
+
+ // mock network 2
+ armnn::NetworkId networkIdentifier2 = 2;
+ armnn::INetworkPtr mockNetwork2(armnn::INetwork::Create());
+ mockNetwork2->AddInputLayer(0, "test layer");
+ runtime->LoadNetwork(networkIdentifier2, Optimize(*mockNetwork2, runtime->GetDeviceSpec()));
+
+ // unload one by its networkID
+ BOOST_TEST(runtime->UnloadNetwork(networkIdentifier1) == armnn::Status::Success);
+
+ BOOST_TEST(runtime->UnloadNetwork(networkIdentifier1) == armnn::Status::Failure);
+}
+
+#if defined(ARMCOMPUTECL_ENABLED) && defined(WITH_VALGRIND)
+BOOST_AUTO_TEST_CASE(RuntimeMemoryUsage)
+{
+ // From documentation:
+
+ // This means that no pointer to the block can be found. The block is classified as "lost",
+ // because the programmer could not possibly have freed it at program exit, since no pointer to it exists.
+ unsigned long leakedBefore = 0;
+ unsigned long leakedAfter = 0;
+
+ // A start-pointer or chain of start-pointers to the block is found. Since the block is still pointed at,
+ // the programmer could, at least in principle, have freed it before program exit.
+ // We want to test this in case memory is not freed as early as it could have been
+ unsigned long reachableBefore = 0;
+ unsigned long reachableAfter = 0;
+
+ // needed as out params but we don't test them
+ unsigned long dubious = 0;
+ unsigned long suppressed = 0;
+
+ // ensure that runtime is large enough before checking for memory leaks
+ // otherwise when loading the network it will automatically reserve memory that won't be released until destruction
+ armnn::NetworkId networkIdentifier;
+ armnn::Runtime runtime(armnn::Compute::GpuAcc);
+ armnn::RuntimeLoadedNetworksReserve(&runtime);
+
+ // check for leaks before we load the network and record them so that we can see the delta after unloading
+ VALGRIND_DO_QUICK_LEAK_CHECK;
+ VALGRIND_COUNT_LEAKS(leakedBefore, dubious, reachableBefore, suppressed);
+
+ // build a mock-network and load it into the runtime
+ {
+ armnn::TensorInfo inputTensorInfo(armnn::TensorShape({ 7, 7 }), armnn::DataType::Float32);
+ armnn::TensorInfo outputTensorInfo(armnn::TensorShape({ 7, 7 }), armnn::DataType::Float32);
+
+ armnn::INetworkPtr mockNetwork(armnn::INetwork::Create());
+
+ armnn::IConnectableLayer* input = mockNetwork->AddInputLayer(0, "input");
+ armnn::IConnectableLayer* layer = mockNetwork->AddActivationLayer(armnn::ActivationDescriptor(), "test");
+ armnn::IConnectableLayer* output = mockNetwork->AddOutputLayer(0, "output");
+
+ input->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
+ layer->GetOutputSlot(0).Connect(output->GetInputSlot(0));
+
+ // set the tensors in the network
+ input->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
+ layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
+
+ // optimize the network
+ armnn::IOptimizedNetworkPtr optNet = Optimize(*mockNetwork, runtime.GetDeviceSpec());
+
+ runtime.LoadNetwork(networkIdentifier, std::move(optNet));
+ }
+
+ runtime.UnloadNetwork(networkIdentifier);
+
+ VALGRIND_DO_ADDED_LEAK_CHECK;
+ VALGRIND_COUNT_LEAKS(leakedAfter, dubious, reachableAfter, suppressed);
+
+ // if we're not running under Valgrind, these vars will have been initialised to 0, so this will always pass
+ BOOST_TEST(leakedBefore == leakedAfter);
+
+ // Add resonable threshold after and before running valgrind with the ACL clear cache function.
+ BOOST_TEST(reachableAfter - reachableBefore < 30000);
+
+ // these are needed because VALGRIND_COUNT_LEAKS is a macro that assigns to the parameters
+ // so they are assigned to, but still considered unused, causing a warning
+ boost::ignore_unused(dubious);
+ boost::ignore_unused(suppressed);
+}
+#endif
+
+#ifdef WITH_VALGRIND
+// run with the following command to get all the amazing output (in the devenv/build folder) :)
+// valgrind --leak-check=full --show-leak-kinds=all --log-file=Valgrind_Memcheck_Leak_Report.txt armnn/test/UnitTests
+BOOST_AUTO_TEST_CASE(RuntimeMemoryLeak)
+{
+ // From documentation:
+
+ // This means that no pointer to the block can be found. The block is classified as "lost",
+ // because the programmer could not possibly have freed it at program exit, since no pointer to it exists.
+ unsigned long leakedBefore = 0;
+ unsigned long leakedAfter = 0;
+
+ // A start-pointer or chain of start-pointers to the block is found. Since the block is still pointed at,
+ // the programmer could, at least in principle, have freed it before program exit.
+ // We want to test this in case memory is not freed as early as it could have been
+ unsigned long reachableBefore = 0;
+ unsigned long reachableAfter = 0;
+
+ // needed as out params but we don't test them
+ unsigned long dubious = 0;
+ unsigned long suppressed = 0;
+
+ armnn::NetworkId networkIdentifier1 = 1;
+
+ // ensure that runtime is large enough before checking for memory leaks
+ // otherwise when loading the network it will automatically reserve memory that won't be released until destruction
+ armnn::Runtime runtime(armnn::Compute::CpuRef);
+ armnn::RuntimeLoadedNetworksReserve(&runtime);
+
+ // check for leaks before we load the network and record them so that we can see the delta after unloading
+ VALGRIND_DO_QUICK_LEAK_CHECK;
+ VALGRIND_COUNT_LEAKS(leakedBefore, dubious, reachableBefore, suppressed);
+
+ // build a mock-network and load it into the runtime
+ {
+ unsigned int inputShape[] = {1, 7, 1, 1};
+ armnn::TensorInfo inputTensorInfo(4, inputShape, armnn::DataType::Float32);
+
+ std::unique_ptr<armnn::Network> mockNetwork1 = std::make_unique<armnn::Network>();
+ mockNetwork1->AddInputLayer(0, "test layer");
+
+ armnn::DeviceSpec device;
+ device.DefaultComputeDevice = armnn::Compute::CpuRef;
+
+ runtime.LoadNetwork(networkIdentifier1, Optimize(*mockNetwork1, device));
+ }
+
+ runtime.UnloadNetwork(networkIdentifier1);
+
+ VALGRIND_DO_ADDED_LEAK_CHECK;
+ VALGRIND_COUNT_LEAKS(leakedAfter, dubious, reachableAfter, suppressed);
+
+ // if we're not running under Valgrind, these vars will have been initialised to 0, so this will always pass
+ BOOST_TEST(leakedBefore == leakedAfter);
+ BOOST_TEST(reachableBefore == reachableAfter);
+
+ // these are needed because VALGRIND_COUNT_LEAKS is a macro that assigns to the parameters
+ // so they are assigned to, but still considered unused, causing a warning
+ boost::ignore_unused(dubious);
+ boost::ignore_unused(suppressed);
+}
+#endif
+
+BOOST_AUTO_TEST_SUITE_END()