blob: 0863ee45ca69810e6e27f44edabaf85766c94a70 [file] [log] [blame]
Finn Williamsb76eaed2021-03-31 16:22:40 +01001//
Matthew Sloyan21a6a1a2022-06-30 17:13:04 +01002// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
Finn Williamsb76eaed2021-03-31 16:22:40 +01003// SPDX-License-Identifier: MIT
4//
5
6#include <armnn/Exceptions.hpp>
7
Colm Donelan0c479742021-12-10 12:43:54 +00008#include <armnn/backends/TensorHandle.hpp>
9#include <armnn/backends/Workload.hpp>
Finn Williamsb76eaed2021-03-31 16:22:40 +010010
Sadik Armagan1625efc2021-06-10 18:24:34 +010011#include <doctest/doctest.h>
Finn Williamsb76eaed2021-03-31 16:22:40 +010012
Jim Flynn27761832022-03-20 21:52:17 +000013#include <thread>
14
Finn Williamsb76eaed2021-03-31 16:22:40 +010015using namespace armnn;
16
Finn Williamsb76eaed2021-03-31 16:22:40 +010017
18namespace
19{
20
Sadik Armagan1625efc2021-06-10 18:24:34 +010021TEST_SUITE("WorkloadAsyncExecuteTests")
22{
23
Finn Williamsb76eaed2021-03-31 16:22:40 +010024struct Workload0 : BaseWorkload<ElementwiseUnaryQueueDescriptor>
25{
26 Workload0(const ElementwiseUnaryQueueDescriptor& descriptor, const WorkloadInfo& info)
Sadik Armagan1625efc2021-06-10 18:24:34 +010027 : BaseWorkload(descriptor, info)
Finn Williamsb76eaed2021-03-31 16:22:40 +010028 {
29 }
30
31 Workload0() : BaseWorkload(ElementwiseUnaryQueueDescriptor(), WorkloadInfo())
32 {
33 }
34
35 void Execute() const
36 {
37 int* inVals = static_cast<int*>(m_Data.m_Inputs[0][0].Map());
38 int* outVals = static_cast<int*>(m_Data.m_Outputs[0][0].Map());
39
Sadik Armagan1625efc2021-06-10 18:24:34 +010040 for (unsigned int i = 0;
41 i < m_Data.m_Inputs[0][0].GetShape().GetNumElements();
42 ++i)
Finn Williamsb76eaed2021-03-31 16:22:40 +010043 {
44 outVals[i] = inVals[i] * outVals[i];
45 inVals[i] = outVals[i];
46 }
47 }
48
Matthew Sloyan21a6a1a2022-06-30 17:13:04 +010049 void ExecuteAsync(ExecutionData& executionData)
Finn Williamsb76eaed2021-03-31 16:22:40 +010050 {
Matthew Sloyan21a6a1a2022-06-30 17:13:04 +010051 WorkingMemDescriptor* workingMemDescriptor = static_cast<WorkingMemDescriptor*>(executionData.m_Data);
52 int* inVals = static_cast<int*>(workingMemDescriptor->m_Inputs[0][0].Map());
53 int* outVals = static_cast<int*>(workingMemDescriptor->m_Outputs[0][0].Map());
Finn Williamsb76eaed2021-03-31 16:22:40 +010054
Sadik Armagan1625efc2021-06-10 18:24:34 +010055 for (unsigned int i = 0;
Matthew Sloyan21a6a1a2022-06-30 17:13:04 +010056 i < workingMemDescriptor->m_Inputs[0][0].GetShape().GetNumElements();
Sadik Armagan1625efc2021-06-10 18:24:34 +010057 ++i)
Finn Williamsb76eaed2021-03-31 16:22:40 +010058 {
59 outVals[i] = inVals[i] + outVals[i];
60 inVals[i] = outVals[i];
61 }
62 }
63
64 QueueDescriptor* GetQueueDescriptor()
65 {
66 return &m_Data;
67 }
68};
69
70struct Workload1 : BaseWorkload<ElementwiseUnaryQueueDescriptor>
71{
72 Workload1(const ElementwiseUnaryQueueDescriptor& descriptor, const WorkloadInfo& info)
Sadik Armagan1625efc2021-06-10 18:24:34 +010073 : BaseWorkload(descriptor, info)
Finn Williamsb76eaed2021-03-31 16:22:40 +010074 {
75 }
76
77 void Execute() const
78 {
79 int* inVals = static_cast<int*>(m_Data.m_Inputs[0][0].Map());
80 int* outVals = static_cast<int*>(m_Data.m_Outputs[0][0].Map());
81
Sadik Armagan1625efc2021-06-10 18:24:34 +010082 for (unsigned int i = 0;
83 i < m_Data.m_Inputs[0][0].GetShape().GetNumElements();
84 ++i)
Finn Williamsb76eaed2021-03-31 16:22:40 +010085 {
86 outVals[i] = inVals[i] * outVals[i];
87 inVals[i] = outVals[i];
88 }
89 }
90};
91
92void ValidateTensor(ITensorHandle* tensorHandle, int expectedValue)
93{
94 int* actualOutput = static_cast<int*>(tensorHandle->Map());
95
96 bool allValuesCorrect = true;
Sadik Armagan1625efc2021-06-10 18:24:34 +010097 for (unsigned int i = 0;
98 i < tensorHandle->GetShape().GetNumElements();
99 ++i)
Finn Williamsb76eaed2021-03-31 16:22:40 +0100100 {
101 if (actualOutput[i] != expectedValue)
102 {
103 allValuesCorrect = false;
104 }
105 }
106
Sadik Armagan1625efc2021-06-10 18:24:34 +0100107 CHECK(allValuesCorrect);
Finn Williamsb76eaed2021-03-31 16:22:40 +0100108}
109
110template<typename Workload>
111std::unique_ptr<Workload> CreateWorkload(TensorInfo info, ITensorHandle* inputTensor, ITensorHandle* outputTensor)
112{
113 WorkloadInfo workloadInfo;
114 workloadInfo.m_InputTensorInfos = std::vector<TensorInfo>{info};
115 workloadInfo.m_OutputTensorInfos = std::vector<TensorInfo>{info};
116
117 ElementwiseUnaryQueueDescriptor elementwiseUnaryQueueDescriptor;
118 elementwiseUnaryQueueDescriptor.m_Inputs = std::vector<ITensorHandle*>{inputTensor};
119 elementwiseUnaryQueueDescriptor.m_Outputs = std::vector<ITensorHandle*>{outputTensor};
120
121 return std::make_unique<Workload>(elementwiseUnaryQueueDescriptor, workloadInfo);
122}
123
Sadik Armagan1625efc2021-06-10 18:24:34 +0100124TEST_CASE("TestAsyncExecute")
Finn Williamsb76eaed2021-03-31 16:22:40 +0100125{
Cathal Corbett5b8093c2021-10-22 11:12:07 +0100126 TensorInfo info({5}, DataType::Signed32, 0.0, 0, true);
Finn Williamsb76eaed2021-03-31 16:22:40 +0100127
128 int inVals[5]{2, 2, 2, 2, 2};
129 int outVals[5]{1, 1, 1, 1, 1};
130
131 int expectedExecuteval = 2;
132 int expectedExecuteAsyncval = 3;
133
134 ConstTensor constInputTensor(info, inVals);
135 ConstTensor constOutputTensor(info, outVals);
136
James Conroy1f58f032021-04-27 17:13:27 +0100137 ScopedTensorHandle syncInput0(constInputTensor);
138 ScopedTensorHandle syncOutput0(constOutputTensor);
Finn Williamsb76eaed2021-03-31 16:22:40 +0100139
140 std::unique_ptr<Workload0> workload0 = CreateWorkload<Workload0>(info, &syncInput0, &syncOutput0);
141
142 workload0.get()->Execute();
143
James Conroy1f58f032021-04-27 17:13:27 +0100144 ScopedTensorHandle asyncInput0(constInputTensor);
145 ScopedTensorHandle asyncOutput0(constOutputTensor);
Finn Williamsb76eaed2021-03-31 16:22:40 +0100146
147 WorkingMemDescriptor workingMemDescriptor0;
148 workingMemDescriptor0.m_Inputs = std::vector<ITensorHandle*>{&asyncInput0};
149 workingMemDescriptor0.m_Outputs = std::vector<ITensorHandle*>{&asyncOutput0};
150
Matthew Sloyan21a6a1a2022-06-30 17:13:04 +0100151 ExecutionData executionData;
152 executionData.m_Data = &workingMemDescriptor0;
153
154 workload0.get()->ExecuteAsync(executionData);
Finn Williamsb76eaed2021-03-31 16:22:40 +0100155
156 // Inputs are also changed by the execute/executeAsync calls to make sure there is no interference with them
157 ValidateTensor(workingMemDescriptor0.m_Outputs[0], expectedExecuteAsyncval);
158 ValidateTensor(workingMemDescriptor0.m_Inputs[0], expectedExecuteAsyncval);
159
160 ValidateTensor(&workload0.get()->GetQueueDescriptor()->m_Outputs[0][0], expectedExecuteval);
161 ValidateTensor(&workload0.get()->GetQueueDescriptor()->m_Inputs[0][0], expectedExecuteval);
162}
163
Sadik Armagan1625efc2021-06-10 18:24:34 +0100164TEST_CASE("TestDefaultAsyncExecute")
Finn Williamsb76eaed2021-03-31 16:22:40 +0100165{
Cathal Corbett5b8093c2021-10-22 11:12:07 +0100166 TensorInfo info({5}, DataType::Signed32, 0.0f, 0, true);
Finn Williamsb76eaed2021-03-31 16:22:40 +0100167
168 std::vector<int> inVals{2, 2, 2, 2, 2};
169 std::vector<int> outVals{1, 1, 1, 1, 1};
170 std::vector<int> defaultVals{0, 0, 0, 0, 0};
171
172 int expectedExecuteval = 2;
173
174 ConstTensor constInputTensor(info, inVals);
175 ConstTensor constOutputTensor(info, outVals);
176 ConstTensor defaultTensor(info, &defaultVals);
177
James Conroy1f58f032021-04-27 17:13:27 +0100178 ScopedTensorHandle defaultInput = ScopedTensorHandle(defaultTensor);
179 ScopedTensorHandle defaultOutput = ScopedTensorHandle(defaultTensor);
Finn Williamsb76eaed2021-03-31 16:22:40 +0100180
181 std::unique_ptr<Workload1> workload1 = CreateWorkload<Workload1>(info, &defaultInput, &defaultOutput);
182
James Conroy1f58f032021-04-27 17:13:27 +0100183 ScopedTensorHandle asyncInput(constInputTensor);
184 ScopedTensorHandle asyncOutput(constOutputTensor);
Finn Williamsb76eaed2021-03-31 16:22:40 +0100185
186 WorkingMemDescriptor workingMemDescriptor;
187 workingMemDescriptor.m_Inputs = std::vector<ITensorHandle*>{&asyncInput};
188 workingMemDescriptor.m_Outputs = std::vector<ITensorHandle*>{&asyncOutput};
189
Matthew Sloyan21a6a1a2022-06-30 17:13:04 +0100190 ExecutionData executionData;
191 executionData.m_Data = &workingMemDescriptor;
192
193 workload1.get()->ExecuteAsync(executionData);
Finn Williamsb76eaed2021-03-31 16:22:40 +0100194
195 // workload1 has no AsyncExecute implementation and so should use the default workload AsyncExecute
196 // implementation which will call workload1.Execute() in a thread safe manner
197 ValidateTensor(workingMemDescriptor.m_Outputs[0], expectedExecuteval);
198 ValidateTensor(workingMemDescriptor.m_Inputs[0], expectedExecuteval);
199}
200
Sadik Armagan1625efc2021-06-10 18:24:34 +0100201TEST_CASE("TestDefaultAsyncExeuteWithThreads")
Finn Williamsb76eaed2021-03-31 16:22:40 +0100202{
203 // Use a large vector so the threads have a chance to interact
204 unsigned int vecSize = 1000;
Cathal Corbett5b8093c2021-10-22 11:12:07 +0100205 TensorInfo info({vecSize}, DataType::Signed32, 0.0f, 0, true);
Finn Williamsb76eaed2021-03-31 16:22:40 +0100206
207 std::vector<int> inVals1(vecSize, 2);
208 std::vector<int> outVals1(vecSize, 1);
209 std::vector<int> inVals2(vecSize, 5);
210 std::vector<int> outVals2(vecSize, -1);
211
212 std::vector<int> defaultVals(vecSize, 0);
213
214 int expectedExecuteval1 = 4;
215 int expectedExecuteval2 = 25;
216 ConstTensor constInputTensor1(info, inVals1);
217 ConstTensor constOutputTensor1(info, outVals1);
218
219 ConstTensor constInputTensor2(info, inVals2);
220 ConstTensor constOutputTensor2(info, outVals2);
221
Ryan OShea49428b72022-02-07 11:16:23 +0000222 ConstTensor defaultTensor(info, defaultVals.data());
Finn Williamsb76eaed2021-03-31 16:22:40 +0100223
James Conroy1f58f032021-04-27 17:13:27 +0100224 ScopedTensorHandle defaultInput = ScopedTensorHandle(defaultTensor);
225 ScopedTensorHandle defaultOutput = ScopedTensorHandle(defaultTensor);
Finn Williamsb76eaed2021-03-31 16:22:40 +0100226 std::unique_ptr<Workload1> workload = CreateWorkload<Workload1>(info, &defaultInput, &defaultOutput);
227
James Conroy1f58f032021-04-27 17:13:27 +0100228 ScopedTensorHandle asyncInput1(constInputTensor1);
229 ScopedTensorHandle asyncOutput1(constOutputTensor1);
Finn Williamsb76eaed2021-03-31 16:22:40 +0100230
231 WorkingMemDescriptor workingMemDescriptor1;
232 workingMemDescriptor1.m_Inputs = std::vector<ITensorHandle*>{&asyncInput1};
233 workingMemDescriptor1.m_Outputs = std::vector<ITensorHandle*>{&asyncOutput1};
234
Matthew Sloyan21a6a1a2022-06-30 17:13:04 +0100235 ExecutionData executionData1;
236 executionData1.m_Data = &workingMemDescriptor1;
Finn Williamsb76eaed2021-03-31 16:22:40 +0100237
James Conroy1f58f032021-04-27 17:13:27 +0100238 ScopedTensorHandle asyncInput2(constInputTensor2);
239 ScopedTensorHandle asyncOutput2(constOutputTensor2);
Finn Williamsb76eaed2021-03-31 16:22:40 +0100240
241 WorkingMemDescriptor workingMemDescriptor2;
242 workingMemDescriptor2.m_Inputs = std::vector<ITensorHandle*>{&asyncInput2};
243 workingMemDescriptor2.m_Outputs = std::vector<ITensorHandle*>{&asyncOutput2};
244
Matthew Sloyan21a6a1a2022-06-30 17:13:04 +0100245 ExecutionData executionData2;
246 executionData2.m_Data = &workingMemDescriptor2;
247
Finn Williamsb76eaed2021-03-31 16:22:40 +0100248 std::thread thread1 = std::thread([&]()
249 {
Matthew Sloyan21a6a1a2022-06-30 17:13:04 +0100250 workload.get()->ExecuteAsync(executionData1);
251 workload.get()->ExecuteAsync(executionData1);
Finn Williamsb76eaed2021-03-31 16:22:40 +0100252 });
253
254 std::thread thread2 = std::thread([&]()
255 {
Matthew Sloyan21a6a1a2022-06-30 17:13:04 +0100256 workload.get()->ExecuteAsync(executionData2);
257 workload.get()->ExecuteAsync(executionData2);
Finn Williamsb76eaed2021-03-31 16:22:40 +0100258 });
259
260 thread1.join();
261 thread2.join();
262
263 ValidateTensor(workingMemDescriptor1.m_Outputs[0], expectedExecuteval1);
264 ValidateTensor(workingMemDescriptor1.m_Inputs[0], expectedExecuteval1);
265
266 ValidateTensor(workingMemDescriptor2.m_Outputs[0], expectedExecuteval2);
267 ValidateTensor(workingMemDescriptor2.m_Inputs[0], expectedExecuteval2);
268}
269
Sadik Armagan1625efc2021-06-10 18:24:34 +0100270}
Finn Williamsb76eaed2021-03-31 16:22:40 +0100271
Jim Flynn27761832022-03-20 21:52:17 +0000272}