blob: 117df5e55ab741718e800b0e65ecd71fe41e7d79 [file] [log] [blame]
telsoa014fcda012018-03-09 14:13:49 +00001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// See LICENSE file in the project root for full license information.
4//
5#include <boost/test/unit_test.hpp>
6
7#include "armnn/TypesUtils.hpp"
8
9#include "armnn/IRuntime.hpp"
10#include "armnn/INetwork.hpp"
11#include "armnn/Descriptors.hpp"
12#include "Runtime.hpp"
13
14#ifdef WITH_VALGRIND
15#include "valgrind/memcheck.h"
16#endif
17
18#include <boost/core/ignore_unused.hpp>
19
20namespace armnn
21{
22
23void RuntimeLoadedNetworksReserve(armnn::Runtime* runtime)
24{
25 runtime->m_LoadedNetworks.reserve(1);
26}
27
28}
29
30BOOST_AUTO_TEST_SUITE(Runtime)
31
32BOOST_AUTO_TEST_CASE(RuntimeUnloadNetwork)
33{
34 // build 2 mock-networks and load them into the runtime
35 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(armnn::Compute::CpuRef));
36
37 // mock network 1
38 armnn::NetworkId networkIdentifier1 = 1;
39 armnn::INetworkPtr mockNetwork1(armnn::INetwork::Create());
40 mockNetwork1->AddInputLayer(0, "test layer");
41 runtime->LoadNetwork(networkIdentifier1, Optimize(*mockNetwork1, runtime->GetDeviceSpec()));
42
43 // mock network 2
44 armnn::NetworkId networkIdentifier2 = 2;
45 armnn::INetworkPtr mockNetwork2(armnn::INetwork::Create());
46 mockNetwork2->AddInputLayer(0, "test layer");
47 runtime->LoadNetwork(networkIdentifier2, Optimize(*mockNetwork2, runtime->GetDeviceSpec()));
48
49 // unload one by its networkID
50 BOOST_TEST(runtime->UnloadNetwork(networkIdentifier1) == armnn::Status::Success);
51
52 BOOST_TEST(runtime->UnloadNetwork(networkIdentifier1) == armnn::Status::Failure);
53}
54
55#if defined(ARMCOMPUTECL_ENABLED) && defined(WITH_VALGRIND)
56BOOST_AUTO_TEST_CASE(RuntimeMemoryUsage)
57{
58 // From documentation:
59
60 // This means that no pointer to the block can be found. The block is classified as "lost",
61 // because the programmer could not possibly have freed it at program exit, since no pointer to it exists.
62 unsigned long leakedBefore = 0;
63 unsigned long leakedAfter = 0;
64
65 // A start-pointer or chain of start-pointers to the block is found. Since the block is still pointed at,
66 // the programmer could, at least in principle, have freed it before program exit.
67 // We want to test this in case memory is not freed as early as it could have been
68 unsigned long reachableBefore = 0;
69 unsigned long reachableAfter = 0;
70
71 // needed as out params but we don't test them
72 unsigned long dubious = 0;
73 unsigned long suppressed = 0;
74
75 // ensure that runtime is large enough before checking for memory leaks
76 // otherwise when loading the network it will automatically reserve memory that won't be released until destruction
77 armnn::NetworkId networkIdentifier;
78 armnn::Runtime runtime(armnn::Compute::GpuAcc);
79 armnn::RuntimeLoadedNetworksReserve(&runtime);
80
81 // check for leaks before we load the network and record them so that we can see the delta after unloading
82 VALGRIND_DO_QUICK_LEAK_CHECK;
83 VALGRIND_COUNT_LEAKS(leakedBefore, dubious, reachableBefore, suppressed);
84
85 // build a mock-network and load it into the runtime
86 {
87 armnn::TensorInfo inputTensorInfo(armnn::TensorShape({ 7, 7 }), armnn::DataType::Float32);
88 armnn::TensorInfo outputTensorInfo(armnn::TensorShape({ 7, 7 }), armnn::DataType::Float32);
89
90 armnn::INetworkPtr mockNetwork(armnn::INetwork::Create());
91
92 armnn::IConnectableLayer* input = mockNetwork->AddInputLayer(0, "input");
93 armnn::IConnectableLayer* layer = mockNetwork->AddActivationLayer(armnn::ActivationDescriptor(), "test");
94 armnn::IConnectableLayer* output = mockNetwork->AddOutputLayer(0, "output");
95
96 input->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
97 layer->GetOutputSlot(0).Connect(output->GetInputSlot(0));
98
99 // set the tensors in the network
100 input->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
101 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
102
103 // optimize the network
104 armnn::IOptimizedNetworkPtr optNet = Optimize(*mockNetwork, runtime.GetDeviceSpec());
105
106 runtime.LoadNetwork(networkIdentifier, std::move(optNet));
107 }
108
109 runtime.UnloadNetwork(networkIdentifier);
110
111 VALGRIND_DO_ADDED_LEAK_CHECK;
112 VALGRIND_COUNT_LEAKS(leakedAfter, dubious, reachableAfter, suppressed);
113
114 // if we're not running under Valgrind, these vars will have been initialised to 0, so this will always pass
115 BOOST_TEST(leakedBefore == leakedAfter);
116
117 // Add resonable threshold after and before running valgrind with the ACL clear cache function.
118 BOOST_TEST(reachableAfter - reachableBefore < 30000);
119
120 // these are needed because VALGRIND_COUNT_LEAKS is a macro that assigns to the parameters
121 // so they are assigned to, but still considered unused, causing a warning
122 boost::ignore_unused(dubious);
123 boost::ignore_unused(suppressed);
124}
125#endif
126
127#ifdef WITH_VALGRIND
128// run with the following command to get all the amazing output (in the devenv/build folder) :)
129// valgrind --leak-check=full --show-leak-kinds=all --log-file=Valgrind_Memcheck_Leak_Report.txt armnn/test/UnitTests
130BOOST_AUTO_TEST_CASE(RuntimeMemoryLeak)
131{
132 // From documentation:
133
134 // This means that no pointer to the block can be found. The block is classified as "lost",
135 // because the programmer could not possibly have freed it at program exit, since no pointer to it exists.
136 unsigned long leakedBefore = 0;
137 unsigned long leakedAfter = 0;
138
139 // A start-pointer or chain of start-pointers to the block is found. Since the block is still pointed at,
140 // the programmer could, at least in principle, have freed it before program exit.
141 // We want to test this in case memory is not freed as early as it could have been
142 unsigned long reachableBefore = 0;
143 unsigned long reachableAfter = 0;
144
145 // needed as out params but we don't test them
146 unsigned long dubious = 0;
147 unsigned long suppressed = 0;
148
149 armnn::NetworkId networkIdentifier1 = 1;
150
151 // ensure that runtime is large enough before checking for memory leaks
152 // otherwise when loading the network it will automatically reserve memory that won't be released until destruction
153 armnn::Runtime runtime(armnn::Compute::CpuRef);
154 armnn::RuntimeLoadedNetworksReserve(&runtime);
155
156 // check for leaks before we load the network and record them so that we can see the delta after unloading
157 VALGRIND_DO_QUICK_LEAK_CHECK;
158 VALGRIND_COUNT_LEAKS(leakedBefore, dubious, reachableBefore, suppressed);
159
160 // build a mock-network and load it into the runtime
161 {
162 unsigned int inputShape[] = {1, 7, 1, 1};
163 armnn::TensorInfo inputTensorInfo(4, inputShape, armnn::DataType::Float32);
164
165 std::unique_ptr<armnn::Network> mockNetwork1 = std::make_unique<armnn::Network>();
166 mockNetwork1->AddInputLayer(0, "test layer");
167
168 armnn::DeviceSpec device;
169 device.DefaultComputeDevice = armnn::Compute::CpuRef;
170
171 runtime.LoadNetwork(networkIdentifier1, Optimize(*mockNetwork1, device));
172 }
173
174 runtime.UnloadNetwork(networkIdentifier1);
175
176 VALGRIND_DO_ADDED_LEAK_CHECK;
177 VALGRIND_COUNT_LEAKS(leakedAfter, dubious, reachableAfter, suppressed);
178
179 // if we're not running under Valgrind, these vars will have been initialised to 0, so this will always pass
180 BOOST_TEST(leakedBefore == leakedAfter);
181 BOOST_TEST(reachableBefore == reachableAfter);
182
183 // these are needed because VALGRIND_COUNT_LEAKS is a macro that assigns to the parameters
184 // so they are assigned to, but still considered unused, causing a warning
185 boost::ignore_unused(dubious);
186 boost::ignore_unused(suppressed);
187}
188#endif
189
190BOOST_AUTO_TEST_SUITE_END()