blob: 7721206d3dfb9e78979dee5c3cbcdcfb4e53a7eb [file] [log] [blame]
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +00001//
2// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include <backendsCommon/test/CommonTestUtils.hpp>
7
8#include <test/GraphUtils.hpp>
9
Sadik Armagan1625efc2021-06-10 18:24:34 +010010#include <doctest/doctest.h>
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +000011
Sadik Armagan1625efc2021-06-10 18:24:34 +010012TEST_SUITE("ClFallback")
13{
14TEST_CASE("ClImportEnabledFallbackToNeon")
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +000015{
16 using namespace armnn;
17
18 IRuntime::CreationOptions options;
19 IRuntimePtr runtime(IRuntime::Create(options));
20
21 // Builds up the structure of the network.
22 INetworkPtr net(INetwork::Create());
23
24 IConnectableLayer* input0 = net->AddInputLayer(0, "input0");
25 IConnectableLayer* input1 = net->AddInputLayer(1, "input1");
26 IConnectableLayer* input2 = net->AddInputLayer(2, "input2");
27 IConnectableLayer* add = net->AddAdditionLayer("add");
28 IConnectableLayer* sub = net->AddSubtractionLayer("sub");
29 IConnectableLayer* output = net->AddOutputLayer(0, "output");
30
31 input0->GetOutputSlot(0).Connect(add->GetInputSlot(0));
32 input1->GetOutputSlot(0).Connect(add->GetInputSlot(1));
33 input2->GetOutputSlot(0).Connect(sub->GetInputSlot(0));
34 add->GetOutputSlot(0).Connect(sub->GetInputSlot(1));
35 sub->GetOutputSlot(0).Connect(output->GetInputSlot(0));
36
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +010037 TensorInfo info = TensorInfo({ 1, 2, 4, 2 }, DataType::Float32);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +000038
39 input0->GetOutputSlot(0).SetTensorInfo(info);
40 input1->GetOutputSlot(0).SetTensorInfo(info);
41 input2->GetOutputSlot(0).SetTensorInfo(info);
42 add->GetOutputSlot(0).SetTensorInfo(info);
43 sub->GetOutputSlot(0).SetTensorInfo(info);
44
45 std::vector<BackendId> backends = { Compute::GpuAcc, Compute::CpuAcc };
46 // Use BackendSelectionHint to specify CpuAcc for Subtraction layer
47 sub->BackendSelectionHint(backends[1]);
48
49 // optimize the network
50 OptimizerOptions optOptions;
51 optOptions.m_ImportEnabled = true;
52 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec(), optOptions);
53
Francis Murtagh3d2b4b22021-02-15 18:23:17 +000054 Graph& graph = GetGraphForTesting(optNet.get());
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +000055
56 armnn::Layer* const layer0 = GetFirstLayerWithName(graph, "input0");
57 armnn::Layer* const layer1 = GetFirstLayerWithName(graph, "input1");
58 armnn::Layer* const layer2 = GetFirstLayerWithName(graph, "input2");
59 armnn::Layer* const layer3 = GetFirstLayerWithName(graph, "add");
60 armnn::Layer* const layer4 = GetFirstLayerWithName(graph, "[ add (0) -> sub (1) ]");
61 armnn::Layer* const layer5 = GetFirstLayerWithName(graph, "sub");
62 armnn::Layer* const layer6 = GetFirstLayerWithName(graph, "output");
63
64 // Checks order is valid.
Sadik Armagan1625efc2021-06-10 18:24:34 +010065 CHECK(CheckOrder(graph, layer0, layer1));
66 CHECK(CheckOrder(graph, layer1, layer2));
67 CHECK(CheckOrder(graph, layer2, layer3));
68 CHECK(CheckOrder(graph, layer3, layer4));
69 CHECK(CheckOrder(graph, layer4, layer5));
70 CHECK(CheckOrder(graph, layer5, layer6));
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +000071
72 // Use memory import between backends
Sadik Armagan1625efc2021-06-10 18:24:34 +010073 CHECK((layer4->GetType() == LayerType::MemCopy));
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +000074
75 // Correctly use backend hint
Sadik Armagan1625efc2021-06-10 18:24:34 +010076 CHECK((layer5->GetBackendId() == Compute::CpuAcc ));
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +000077
78 // Load it into the runtime. It should pass.
79 NetworkId netId;
80 std::string ignoredErrorMessage;
Francis Murtagh73d3e2e2021-04-29 14:23:04 +010081 INetworkProperties networkProperties(false, MemorySource::Malloc, MemorySource::Malloc);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +000082 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
83
84 // Creates structures for input & output
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +010085 std::vector<float> inputValue0
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +000086 {
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +010087 1.0f, 1.0f, 2.0f, 2.0f, 2.0f, 3.0f, 4.0f, 4.0f, 5.0f, 5.0f, 6.0f, 6.0f, 1.0f, 1.0f, 2.0f, 2.0f
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +000088 };
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +010089 std::vector<float> inputValue1
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +000090 {
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +010091 0.0f, 1.0f, 1.0f, 2.0f, 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 5.0f, 5.0f, 6.0f, 0.0f, 1.0f, 1.0f, 2.0f
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +000092 };
93 std::vector<float> inputData2
94 {
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +010095 12.0f, 11.0f, 10.0f, 9.0f, 8.0f, 7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f, 12.0f, 11.0f, 10.0f, 9.0f
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +000096 };
97
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +010098 std::vector<float> outputData(16);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +000099
100 std::vector<float> expectedOutput
101 {
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100102 11.0f, 9.0f, 7.0f, 5.0f, 3.0f, 1.0f, -1.0f, -3.0f, -5.0f, -7.0f, -9.0f, -11.0f, 11.0f, 9.0f, 7.0f, 5.0f
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000103 };
104
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100105 // Prepare aligned data
106 unsigned int numElements = info.GetNumElements();
107 size_t totalBytes = numElements * sizeof(float);
108 const size_t alignment = 64;
109 size_t space = totalBytes + alignment + alignment;
110 auto inputData0 = std::make_unique<uint8_t[]>(space);
111 void* alignedInputPtr0 = inputData0.get();
Sadik Armagan1625efc2021-06-10 18:24:34 +0100112 CHECK(std::align(alignment, totalBytes, alignedInputPtr0, space));
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100113
114 auto* intputPtr0 = reinterpret_cast<float*>(alignedInputPtr0);
115 std::copy(inputValue0.begin(), inputValue0.end(), intputPtr0);
116
117 auto inputData1 = std::make_unique<uint8_t[]>(space);
118 void* alignedInputPtr1 = inputData1.get();
Sadik Armagan1625efc2021-06-10 18:24:34 +0100119 CHECK(std::align(alignment, totalBytes, alignedInputPtr1, space));
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100120
121 auto* intputPtr1 = reinterpret_cast<float*>(alignedInputPtr1);
122 std::copy(inputValue1.begin(), inputValue1.end(), intputPtr1);
123
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000124 InputTensors inputTensors
125 {
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100126 { 0, armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), alignedInputPtr0) },
127 { 1, armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 1), alignedInputPtr1) },
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000128 { 2, armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 2), inputData2.data()) }
129 };
130 OutputTensors outputTensors
131 {
132 { 0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data()) }
133 };
134
135 runtime->GetProfiler(netId)->EnableProfiling(true);
136
137 // Do the inference
138 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
139
140 // Retrieve the Profiler.Print() output to get the workload execution
141 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
142 std::stringstream ss;
143 profilerManager.GetProfiler()->Print(ss);;
144 std::string dump = ss.str();
145
146 // Executed Subtraction using CpuAcc
147 std::size_t found = dump.find("NeonSubtractionWorkload_Execute");
Sadik Armagan1625efc2021-06-10 18:24:34 +0100148 CHECK(found != std::string::npos);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000149
150 // Contain CopyMemGeneric
151 found = dump.find("CopyMemGeneric");
Sadik Armagan1625efc2021-06-10 18:24:34 +0100152 CHECK(found != std::string::npos);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000153
154 // Check output is as expected
Sadik Armagan1625efc2021-06-10 18:24:34 +0100155 CHECK(outputData == expectedOutput);
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100156
157 runtime->UnloadNetwork(netId);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000158}
159
Sadik Armagan1625efc2021-06-10 18:24:34 +0100160TEST_CASE("ClImportDisabledFallbackToNeon")
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000161{
162 using namespace armnn;
163
164 IRuntime::CreationOptions options;
165 IRuntimePtr runtime(IRuntime::Create(options));
166
167 // Builds up the structure of the network.
168 INetworkPtr net(INetwork::Create());
169
170 IConnectableLayer* input0 = net->AddInputLayer(0, "input0");
171 IConnectableLayer* input1 = net->AddInputLayer(1, "input1");
172 IConnectableLayer* input2 = net->AddInputLayer(2, "input2");
173 IConnectableLayer* add = net->AddAdditionLayer("add");
174 IConnectableLayer* sub = net->AddSubtractionLayer("sub");
175 IConnectableLayer* output = net->AddOutputLayer(0, "output");
176
177 input0->GetOutputSlot(0).Connect(add->GetInputSlot(0));
178 input1->GetOutputSlot(0).Connect(add->GetInputSlot(1));
179 input2->GetOutputSlot(0).Connect(sub->GetInputSlot(0));
180 add->GetOutputSlot(0).Connect(sub->GetInputSlot(1));
181 sub->GetOutputSlot(0).Connect(output->GetInputSlot(0));
182
183 TensorInfo info = TensorInfo({ 1, 2, 3, 2 }, DataType::Float32);
184
185 input0->GetOutputSlot(0).SetTensorInfo(info);
186 input1->GetOutputSlot(0).SetTensorInfo(info);
187 input2->GetOutputSlot(0).SetTensorInfo(info);
188 add->GetOutputSlot(0).SetTensorInfo(info);
189 sub->GetOutputSlot(0).SetTensorInfo(info);
190
191 std::vector<BackendId> backends = { Compute::GpuAcc, Compute::CpuAcc };
192 // Use BackendSelectionHint to specify CpuAcc for Subtraction layer
193 sub->BackendSelectionHint(backends[1]);
194
195 // optimize the network
196 OptimizerOptions optOptions;
197 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec(), optOptions);
198
Francis Murtagh3d2b4b22021-02-15 18:23:17 +0000199 Graph& graph = GetGraphForTesting(optNet.get());
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000200
201 armnn::Layer* const layer0 = GetFirstLayerWithName(graph, "input0");
202 armnn::Layer* const layer1 = GetFirstLayerWithName(graph, "input1");
203 armnn::Layer* const layer2 = GetFirstLayerWithName(graph, "input2");
204 armnn::Layer* const layer3 = GetFirstLayerWithName(graph, "add");
205 armnn::Layer* const layer4 = GetFirstLayerWithName(graph, "[ add (0) -> sub (1) ]");
206 armnn::Layer* const layer5 = GetFirstLayerWithName(graph, "sub");
207 armnn::Layer* const layer6 = GetFirstLayerWithName(graph, "output");
208
209 // Checks order is valid.
Sadik Armagan1625efc2021-06-10 18:24:34 +0100210 CHECK(CheckOrder(graph, layer0, layer1));
211 CHECK(CheckOrder(graph, layer1, layer2));
212 CHECK(CheckOrder(graph, layer2, layer3));
213 CHECK(CheckOrder(graph, layer3, layer4));
214 CHECK(CheckOrder(graph, layer4, layer5));
215 CHECK(CheckOrder(graph, layer5, layer6));
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000216
217 // Use memory import between backends
Sadik Armagan1625efc2021-06-10 18:24:34 +0100218 CHECK((layer4->GetType() == LayerType::MemCopy));
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000219
220 // Correctly use backend hint
Sadik Armagan1625efc2021-06-10 18:24:34 +0100221 CHECK((layer5->GetBackendId() == Compute::CpuAcc ));
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000222
223 // Load it into the runtime. It should pass.
224 NetworkId netId;
225 runtime->LoadNetwork(netId, std::move(optNet));
226
227 // Creates structures for input & output
228 std::vector<float> inputData0
229 {
230 1.0f, 1.0f, 2.0f, 2.0f, 2.0f, 3.0f, 4.0f, 4.0f, 5.0f, 5.0f, 6.0f, 6.0f
231 };
232 std::vector<float> inputData1
233 {
234 0.0f, 1.0f, 1.0f, 2.0f, 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 5.0f, 5.0f, 6.0f
235 };
236 std::vector<float> inputData2
237 {
238 12.0f, 11.0f, 10.0f, 9.0f, 8.0f, 7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f
239 };
240
241 std::vector<float> outputData(12);
242
243 std::vector<float> expectedOutput
244 {
245 11.0f, 9.0f, 7.0f, 5.0f, 3.0f, 1.0f, -1.0f, -3.0f, -5.0f, -7.0f, -9.0f, -11.0f
246 };
247
248 InputTensors inputTensors
249 {
250 { 0, armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData0.data()) },
251 { 1, armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 1), inputData1.data()) },
252 { 2, armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 2), inputData2.data()) }
253 };
254 OutputTensors outputTensors
255 {
256 { 0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data()) }
257 };
258
259 runtime->GetProfiler(netId)->EnableProfiling(true);
260
261 // Do the inference
262 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
263
264 // Retrieve the Profiler.Print() output to get the workload execution
265 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
266 std::stringstream ss;
267 profilerManager.GetProfiler()->Print(ss);;
268 std::string dump = ss.str();
269
270 // Executed Subtraction using CpuAcc
271 std::size_t found = dump.find("NeonSubtractionWorkload_Execute");
Sadik Armagan1625efc2021-06-10 18:24:34 +0100272 CHECK(found != std::string::npos);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000273
274 // Contain CopyMemGeneric
275 found = dump.find("CopyMemGeneric");
Sadik Armagan1625efc2021-06-10 18:24:34 +0100276 CHECK(found != std::string::npos);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000277
278 // Check output is as expected
Sadik Armagan1625efc2021-06-10 18:24:34 +0100279 CHECK(outputData == expectedOutput);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000280}
281
Sadik Armagan1625efc2021-06-10 18:24:34 +0100282TEST_CASE("ClImportEnabledFallbackSubgraphToNeon")
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000283{
284 using namespace armnn;
285
286 IRuntime::CreationOptions options;
287 IRuntimePtr runtime(IRuntime::Create(options));
288
289 // Builds up the structure of the network.
290 INetworkPtr net(INetwork::Create());
291
292 Pooling2dDescriptor desc;
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100293 desc.m_PoolWidth = 2;
294 desc.m_PoolHeight = 2;
295 desc.m_StrideX = 2;
296 desc.m_StrideY = 2;
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000297
298 IConnectableLayer* input0 = net->AddInputLayer(0, "input0");
299 IConnectableLayer* input1 = net->AddInputLayer(1, "input1");
300 IConnectableLayer* input2 = net->AddInputLayer(2, "input2");
301 IConnectableLayer* add = net->AddAdditionLayer("add");
302 IConnectableLayer* sub = net->AddSubtractionLayer("sub");
303 IConnectableLayer* pooling = net->AddPooling2dLayer(desc, "pooling");
304 IConnectableLayer* output = net->AddOutputLayer(0, "output");
305
306 input0->GetOutputSlot(0).Connect(add->GetInputSlot(0));
307 input1->GetOutputSlot(0).Connect(add->GetInputSlot(1));
308 input2->GetOutputSlot(0).Connect(sub->GetInputSlot(0));
309 add->GetOutputSlot(0).Connect(sub->GetInputSlot(1));
310 sub->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
311 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
312
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100313 TensorInfo info = TensorInfo({ 1, 2, 4, 2 }, DataType::Float32);
314 TensorInfo poolingInfo = TensorInfo({ 1, 2, 2, 1 }, DataType::Float32);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000315
316 input0->GetOutputSlot(0).SetTensorInfo(info);
317 input1->GetOutputSlot(0).SetTensorInfo(info);
318 input2->GetOutputSlot(0).SetTensorInfo(info);
319 add->GetOutputSlot(0).SetTensorInfo(info);
320 sub->GetOutputSlot(0).SetTensorInfo(info);
321 pooling->GetOutputSlot(0).SetTensorInfo(poolingInfo);
322
323 std::vector<BackendId> backends = { Compute::GpuAcc, Compute::CpuAcc };
324 // Use BackendSelectionHint to specify CpuAcc for Subtraction layer
325 sub->BackendSelectionHint(backends[1]);
326
327 // optimize the network
328 OptimizerOptions optOptions;
329 optOptions.m_ImportEnabled = true;
330 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec(), optOptions);
331
Francis Murtagh3d2b4b22021-02-15 18:23:17 +0000332 Graph& graph = GetGraphForTesting(optNet.get());
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000333
334 armnn::Layer* const layer0 = GetFirstLayerWithName(graph, "input0");
335 armnn::Layer* const layer1 = GetFirstLayerWithName(graph, "input1");
336 armnn::Layer* const layer2 = GetFirstLayerWithName(graph, "input2");
337 armnn::Layer* const layer3 = GetFirstLayerWithName(graph, "add");
338 armnn::Layer* const layer4 = GetFirstLayerWithName(graph, "[ add (0) -> sub (1) ]");
339 armnn::Layer* const layer5 = GetFirstLayerWithName(graph, "sub");
340 armnn::Layer* const layer6 = GetFirstLayerWithName(graph, "[ sub (0) -> pooling (0) ]");
341 armnn::Layer* const layer7 = GetFirstLayerWithName(graph, "pooling");
342 armnn::Layer* const layer8 = GetFirstLayerWithName(graph, "output");
343
344 // Checks order is valid.
Sadik Armagan1625efc2021-06-10 18:24:34 +0100345 CHECK(CheckOrder(graph, layer0, layer1));
346 CHECK(CheckOrder(graph, layer1, layer2));
347 CHECK(CheckOrder(graph, layer2, layer3));
348 CHECK(CheckOrder(graph, layer3, layer4));
349 CHECK(CheckOrder(graph, layer4, layer5));
350 CHECK(CheckOrder(graph, layer5, layer6));
351 CHECK(CheckOrder(graph, layer6, layer7));
352 CHECK(CheckOrder(graph, layer7, layer8));
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000353
354 // Use memory import between backends
Sadik Armagan1625efc2021-06-10 18:24:34 +0100355 CHECK((layer4->GetType() == LayerType::MemCopy));
356 CHECK((layer6->GetType() == LayerType::MemCopy));
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000357
358 // Correctly use backend hint
Sadik Armagan1625efc2021-06-10 18:24:34 +0100359 CHECK((layer5->GetBackendId() == Compute::CpuAcc ));
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000360
361 // Load it into the runtime. It should pass.
362 NetworkId netId;
363 std::string ignoredErrorMessage;
Francis Murtagh73d3e2e2021-04-29 14:23:04 +0100364 INetworkProperties networkProperties(false, MemorySource::Malloc, MemorySource::Malloc);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000365 runtime->LoadNetwork(netId, std::move(optNet), ignoredErrorMessage, networkProperties);
366
367 // Creates structures for input & output
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100368 std::vector<float> inputValue0
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000369 {
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100370 1.0f, 1.0f, 2.0f, 2.0f, 2.0f, 3.0f, 4.0f, 4.0f, 5.0f, 5.0f, 6.0f, 6.0f, 1.0f, 1.0f, 2.0f, 2.0f
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000371 };
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100372 std::vector<float> inputValue1
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000373 {
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100374 0.0f, 1.0f, 1.0f, 2.0f, 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 5.0f, 5.0f, 6.0f, 0.0f, 1.0f, 1.0f, 2.0f
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000375 };
376 std::vector<float> inputData2
377 {
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100378 12.0f, 11.0f, 10.0f, 9.0f, 8.0f, 7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f, 12.0f, 11.0f, 10.0f, 9.0f
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000379 };
380
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100381 std::vector<float> outputData(4);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000382
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100383 std::vector<float> expectedOutput{ 11.0f, 3.0f, -5.0f, 11.0f };
384
385 unsigned int numElements = info.GetNumElements();
386 size_t totalBytes = numElements * sizeof(float);
387 const size_t alignment = 64;
388 size_t space = totalBytes + alignment + alignment;
389 auto inputData0 = std::make_unique<uint8_t[]>(space);
390 void* alignedInputPtr0 = inputData0.get();
Sadik Armagan1625efc2021-06-10 18:24:34 +0100391 CHECK(std::align(alignment, totalBytes, alignedInputPtr0, space));
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100392
393 auto* intputPtr0 = reinterpret_cast<float*>(alignedInputPtr0);
394 std::copy(inputValue0.begin(), inputValue0.end(), intputPtr0);
395
396 auto inputData1 = std::make_unique<uint8_t[]>(space);
397 void* alignedInputPtr1 = inputData1.get();
Sadik Armagan1625efc2021-06-10 18:24:34 +0100398 CHECK(std::align(alignment, totalBytes, alignedInputPtr1, space));
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100399
400 auto* intputPtr1 = reinterpret_cast<float*>(alignedInputPtr1);
401 std::copy(inputValue1.begin(), inputValue1.end(), intputPtr1);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000402
403 InputTensors inputTensors
404 {
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100405 { 0, armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), alignedInputPtr0) },
406 { 1, armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 1), alignedInputPtr1) },
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000407 { 2, armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 2), inputData2.data()) }
408 };
409 OutputTensors outputTensors
410 {
411 { 0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data()) }
412 };
413
414 runtime->GetProfiler(netId)->EnableProfiling(true);
415
416 // Do the inference
417 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
418
419 // Retrieve the Profiler.Print() output to get the workload execution
420 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
421 std::stringstream ss;
422 profilerManager.GetProfiler()->Print(ss);;
423 std::string dump = ss.str();
424
425 // Executed Subtraction using CpuAcc
426 std::size_t found = dump.find("NeonSubtractionWorkload_Execute");
Sadik Armagan1625efc2021-06-10 18:24:34 +0100427 CHECK(found != std::string::npos);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000428
429 // Correctly switch back to GpuAcc
430 found = dump.find("ClPooling2dWorkload_Execute");
Sadik Armagan1625efc2021-06-10 18:24:34 +0100431 CHECK(found != std::string::npos);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000432
433 // Contain CopyMemGeneric
434 found = dump.find("CopyMemGeneric");
Sadik Armagan1625efc2021-06-10 18:24:34 +0100435 CHECK(found != std::string::npos);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000436
437 // Check output is as expected
Sadik Armagan1625efc2021-06-10 18:24:34 +0100438 CHECK(outputData == expectedOutput);
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100439
440 runtime->UnloadNetwork(netId);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000441}
442
Sadik Armagan1625efc2021-06-10 18:24:34 +0100443TEST_CASE("ClImportDisableFallbackSubgraphToNeon")
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000444{
445 using namespace armnn;
446
447 IRuntime::CreationOptions options;
448 IRuntimePtr runtime(IRuntime::Create(options));
449
450 // Builds up the structure of the network.
451 INetworkPtr net(INetwork::Create());
452
453 Pooling2dDescriptor desc;
454
455 IConnectableLayer* input0 = net->AddInputLayer(0, "input0");
456 IConnectableLayer* input1 = net->AddInputLayer(1, "input1");
457 IConnectableLayer* input2 = net->AddInputLayer(2, "input2");
458 IConnectableLayer* add = net->AddAdditionLayer("add");
459 IConnectableLayer* sub = net->AddSubtractionLayer("sub");
460 IConnectableLayer* pooling = net->AddPooling2dLayer(desc, "pooling");
461 IConnectableLayer* output = net->AddOutputLayer(0, "output");
462
463 input0->GetOutputSlot(0).Connect(add->GetInputSlot(0));
464 input1->GetOutputSlot(0).Connect(add->GetInputSlot(1));
465 input2->GetOutputSlot(0).Connect(sub->GetInputSlot(0));
466 add->GetOutputSlot(0).Connect(sub->GetInputSlot(1));
467 sub->GetOutputSlot(0).Connect(pooling->GetInputSlot(0));
468 pooling->GetOutputSlot(0).Connect(output->GetInputSlot(0));
469
470 TensorInfo info = TensorInfo({ 1, 2, 3, 2 }, DataType::Float32);
471 TensorInfo poolingInfo = TensorInfo({ 1, 2, 1, 1 }, DataType::Float32);
472
473 input0->GetOutputSlot(0).SetTensorInfo(info);
474 input1->GetOutputSlot(0).SetTensorInfo(info);
475 input2->GetOutputSlot(0).SetTensorInfo(info);
476 add->GetOutputSlot(0).SetTensorInfo(info);
477 sub->GetOutputSlot(0).SetTensorInfo(info);
478 pooling->GetOutputSlot(0).SetTensorInfo(poolingInfo);
479
480 std::vector<BackendId> backends = { Compute::GpuAcc, Compute::CpuAcc };
481 // Use BackendSelectionHint to specify CpuAcc for Subtraction layer
482 sub->BackendSelectionHint(backends[1]);
483
484 // optimize the network
485 OptimizerOptions optOptions;
486 IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec(), optOptions);
487
Francis Murtagh3d2b4b22021-02-15 18:23:17 +0000488 Graph& graph = GetGraphForTesting(optNet.get());
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000489
490 armnn::Layer* const layer0 = GetFirstLayerWithName(graph, "input0");
491 armnn::Layer* const layer1 = GetFirstLayerWithName(graph, "input1");
492 armnn::Layer* const layer2 = GetFirstLayerWithName(graph, "input2");
493 armnn::Layer* const layer3 = GetFirstLayerWithName(graph, "add");
494 armnn::Layer* const layer4 = GetFirstLayerWithName(graph, "[ add (0) -> sub (1) ]");
495 armnn::Layer* const layer5 = GetFirstLayerWithName(graph, "sub");
496 armnn::Layer* const layer6 = GetFirstLayerWithName(graph, "[ sub (0) -> pooling (0) ]");
497 armnn::Layer* const layer7 = GetFirstLayerWithName(graph, "pooling");
498 armnn::Layer* const layer8 = GetFirstLayerWithName(graph, "output");
499
500 // Checks order is valid.
Sadik Armagan1625efc2021-06-10 18:24:34 +0100501 CHECK(CheckOrder(graph, layer0, layer1));
502 CHECK(CheckOrder(graph, layer1, layer2));
503 CHECK(CheckOrder(graph, layer2, layer3));
504 CHECK(CheckOrder(graph, layer3, layer4));
505 CHECK(CheckOrder(graph, layer4, layer5));
506 CHECK(CheckOrder(graph, layer5, layer6));
507 CHECK(CheckOrder(graph, layer6, layer7));
508 CHECK(CheckOrder(graph, layer7, layer8));
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000509
510 // Use memory import between backends
Sadik Armagan1625efc2021-06-10 18:24:34 +0100511 CHECK((layer4->GetType() == LayerType::MemCopy));
512 CHECK((layer6->GetType() == LayerType::MemCopy));
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000513
514 // Correctly use backend hint
Sadik Armagan1625efc2021-06-10 18:24:34 +0100515 CHECK((layer5->GetBackendId() == Compute::CpuAcc ));
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000516
517 // Load it into the runtime. It should pass.
518 NetworkId netId;
519 runtime->LoadNetwork(netId, std::move(optNet));
520
521 // Creates structures for input & output
522 std::vector<float> inputData0
523 {
524 1.0f, 1.0f, 2.0f, 2.0f, 2.0f, 3.0f, 4.0f, 4.0f, 5.0f, 5.0f, 6.0f, 6.0f
525 };
526 std::vector<float> inputData1
527 {
528 0.0f, 1.0f, 1.0f, 2.0f, 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 5.0f, 5.0f, 6.0f
529 };
530 std::vector<float> inputData2
531 {
532 12.0f, 11.0f, 10.0f, 9.0f, 8.0f, 7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f
533 };
534
535 std::vector<float> outputData(2);
536
537 std::vector<float> expectedOutput{ 11.0f, -1.0f };
538
539 InputTensors inputTensors
540 {
541 { 0, armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), inputData0.data()) },
542 { 1, armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 1), inputData1.data()) },
543 { 2, armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 2), inputData2.data()) }
544 };
545 OutputTensors outputTensors
546 {
547 { 0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data()) }
548 };
549
550 runtime->GetProfiler(netId)->EnableProfiling(true);
551
552 // Do the inference
553 runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
554
555 // Retrieve the Profiler.Print() output to get the workload execution
556 ProfilerManager& profilerManager = armnn::ProfilerManager::GetInstance();
557 std::stringstream ss;
558 profilerManager.GetProfiler()->Print(ss);;
559 std::string dump = ss.str();
560
561 // Executed Subtraction using CpuAcc
562 std::size_t found = dump.find("NeonSubtractionWorkload_Execute");
Sadik Armagan1625efc2021-06-10 18:24:34 +0100563 CHECK(found != std::string::npos);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000564
565 // Correctly switch back to GpuAcc
566 found = dump.find("ClPooling2dWorkload_Execute");
Sadik Armagan1625efc2021-06-10 18:24:34 +0100567 CHECK(found != std::string::npos);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000568
569 // Contain CopyMemGeneric
570 found = dump.find("CopyMemGeneric");
Sadik Armagan1625efc2021-06-10 18:24:34 +0100571 CHECK(found != std::string::npos);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000572
573 // Check output is as expected
Sadik Armagan1625efc2021-06-10 18:24:34 +0100574 CHECK(outputData == expectedOutput);
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000575}
576
Sadik Armagan1625efc2021-06-10 18:24:34 +0100577}