blob: 1562c9f837a4645f766e6fe6f725f8dd0ed83149 [file] [log] [blame]
Matthew Sloyan65c21a12023-04-04 12:06:14 +01001//
2// Copyright © 2023 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
7#include <doctest/doctest.h>
8
9#include <opaque/include/armnn_delegate.hpp>
Narumol Prangnawarat26654cb2023-05-03 16:08:11 +010010
Teresa Charlin3e4b6082023-10-19 19:13:29 +010011#include <tensorflow/lite/kernels/builtin_op_kernels.h>
12#include <tensorflow/lite/interpreter.h>
13#include <tensorflow/lite/kernels/register.h>
14#include "tensorflow/lite/core/c/builtin_op_data.h"
15
Matthew Sloyan65c21a12023-04-04 12:06:14 +010016namespace armnnOpaqueDelegate
17{
18
19TEST_SUITE("ArmnnOpaqueDelegate")
20{
21
Teresa Charlin3e4b6082023-10-19 19:13:29 +010022TEST_CASE ("ArmnnOpaqueDelegate_Registered")
23{
24 using namespace tflite;
25 auto tfLiteInterpreter = std::make_unique<Interpreter>();
26
27 tfLiteInterpreter->AddTensors(3);
28 tfLiteInterpreter->SetInputs({0, 1});
29 tfLiteInterpreter->SetOutputs({2});
30
31 tfLiteInterpreter->SetTensorParametersReadWrite(0, kTfLiteFloat32, "input1", {1,2,2,1}, TfLiteQuantization());
32 tfLiteInterpreter->SetTensorParametersReadWrite(1, kTfLiteFloat32, "input2", {1,2,2,1}, TfLiteQuantization());
33 tfLiteInterpreter->SetTensorParametersReadWrite(2, kTfLiteFloat32, "output", {1,2,2,1}, TfLiteQuantization());
34
35 TfLiteAddParams* addParams = reinterpret_cast<TfLiteAddParams*>(malloc(sizeof(TfLiteAddParams)));
36 addParams->activation = kTfLiteActNone;
37 addParams->pot_scale_int16 = false;
38
39 tflite::ops::builtin::BuiltinOpResolver opResolver;
40 const TfLiteRegistration* opRegister = opResolver.FindOp(BuiltinOperator_ADD, 1);
41 tfLiteInterpreter->AddNodeWithParameters({0, 1}, {2}, "", 0, addParams, opRegister);
42
43 // Create the Armnn Delegate
44 std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef };
45 std::vector<armnn::BackendOptions> backendOptions;
46 backendOptions.emplace_back(
47 armnn::BackendOptions{ "BackendName",
48 {
49 { "Option1", 42 },
50 { "Option2", true }
51 }}
52 );
53
54 armnnDelegate::DelegateOptions delegateOptions(backends, backendOptions);
55 std::unique_ptr<TfLiteDelegate, decltype(&armnnOpaqueDelegate::TfLiteArmnnOpaqueDelegateDelete)>
56 theArmnnDelegate(armnnOpaqueDelegate::TfLiteArmnnOpaqueDelegateCreate(delegateOptions),
57 armnnOpaqueDelegate::TfLiteArmnnOpaqueDelegateDelete);
58
59 auto status = tfLiteInterpreter->ModifyGraphWithDelegate(std::move(theArmnnDelegate));
60 CHECK(status == kTfLiteOk);
61 CHECK(tfLiteInterpreter != nullptr);
62}
63
64TEST_CASE ("ArmnnOpaqueDelegate_OptimizerOptionsRegistered")
65{
66 using namespace tflite;
67 auto tfLiteInterpreter = std::make_unique<Interpreter>();
68
69 tfLiteInterpreter->AddTensors(3);
70 tfLiteInterpreter->SetInputs({0, 1});
71 tfLiteInterpreter->SetOutputs({2});
72
73 tfLiteInterpreter->SetTensorParametersReadWrite(0, kTfLiteFloat32, "input1", {1,2,2,1}, TfLiteQuantization());
74 tfLiteInterpreter->SetTensorParametersReadWrite(1, kTfLiteFloat32, "input2", {1,2,2,1}, TfLiteQuantization());
75 tfLiteInterpreter->SetTensorParametersReadWrite(2, kTfLiteFloat32, "output", {1,2,2,1}, TfLiteQuantization());
76
77 TfLiteAddParams* addParams = reinterpret_cast<TfLiteAddParams*>(malloc(sizeof(TfLiteAddParams)));
78 addParams->activation = kTfLiteActNone;
79 addParams->pot_scale_int16 = false;
80
81 tflite::ops::builtin::BuiltinOpResolver opResolver;
82 const TfLiteRegistration* opRegister = opResolver.FindOp(BuiltinOperator_ADD, 1);
83 tfLiteInterpreter->AddNodeWithParameters({0, 1}, {2}, "", 0, addParams, opRegister);
84
85 // Create the Armnn Delegate
86 std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef };
87
88 armnn::OptimizerOptionsOpaque optimizerOptions(true, true, false, true);
89
90 armnnDelegate::DelegateOptions delegateOptions(backends, optimizerOptions);
91 std::unique_ptr<TfLiteDelegate, decltype(&armnnOpaqueDelegate::TfLiteArmnnOpaqueDelegateDelete)>
92 theArmnnDelegate(armnnOpaqueDelegate::TfLiteArmnnOpaqueDelegateCreate(delegateOptions),
93 armnnOpaqueDelegate::TfLiteArmnnOpaqueDelegateDelete);
94
95 auto status = tfLiteInterpreter->ModifyGraphWithDelegate(std::move(theArmnnDelegate));
96 CHECK(status == kTfLiteOk);
97 CHECK(tfLiteInterpreter != nullptr);
98}
99
Matthew Sloyan65c21a12023-04-04 12:06:14 +0100100TEST_CASE ("DelegateOptions_OpaqueDelegateDefault")
101{
102 // Check default options can be created
103 auto options = armnnOpaqueDelegate::TfLiteArmnnDelegateOptionsDefault();
104 armnnOpaqueDelegate::ArmnnOpaqueDelegate delegate(options);
105
106 // Check version returns correctly
107 auto version = delegate.GetVersion();
108 CHECK_EQ(version, OPAQUE_DELEGATE_VERSION);
109
110 auto* builder = delegate.GetDelegateBuilder();
111 CHECK(builder);
112
113 // Check Opaque delegate created
Teresa Charlin3e4b6082023-10-19 19:13:29 +0100114 auto opaqueDelegate = armnnOpaqueDelegate::TfLiteArmnnOpaqueDelegateCreate(options);
Matthew Sloyan65c21a12023-04-04 12:06:14 +0100115 CHECK(opaqueDelegate);
116
117 // Check Opaque Delegate can be deleted
118 CHECK(opaqueDelegate->opaque_delegate_builder->data);
119 armnnOpaqueDelegate::TfLiteArmnnOpaqueDelegateDelete(opaqueDelegate);
120}
121
Narumol Prangnawarat26654cb2023-05-03 16:08:11 +0100122TEST_CASE ("DelegatePluginTest")
123{
Teresa Charlin3e4b6082023-10-19 19:13:29 +0100124 const char* backends = "CpuRef";
125 bool fastmath = false;
126 const char* additional_parameters = "allow-expanded-dims=true";
127
128 flatbuffers::FlatBufferBuilder flatbuffer_builder;
129 flatbuffers::Offset<tflite::ArmNNSettings>
130 armnn_settings_offset = tflite::CreateArmNNSettingsDirect(flatbuffer_builder,
131 backends,
132 fastmath,
133 additional_parameters);
134
135 tflite::TFLiteSettingsBuilder tflite_settings_builder(flatbuffer_builder);
136 tflite_settings_builder.add_armnn_settings(armnn_settings_offset);
137 flatbuffers::Offset<tflite::TFLiteSettings> tflite_settings_offset = tflite_settings_builder.Finish();
138 flatbuffer_builder.Finish(tflite_settings_offset);
139
140 const tflite::TFLiteSettings* tflite_settings = flatbuffers::GetRoot<tflite::TFLiteSettings>(
141 flatbuffer_builder.GetBufferPointer());
Narumol Prangnawarat26654cb2023-05-03 16:08:11 +0100142
143 std::unique_ptr<tflite::delegates::DelegatePluginInterface> delegatePlugin =
Teresa Charlin3e4b6082023-10-19 19:13:29 +0100144 tflite::delegates::DelegatePluginRegistry::CreateByName("armnn_delegate", *tflite_settings);
Narumol Prangnawarat26654cb2023-05-03 16:08:11 +0100145
146 // Plugin is created correctly using armnn_delegate name.
147 CHECK((delegatePlugin != nullptr));
148
149 tflite::delegates::TfLiteDelegatePtr armnnDelegate = delegatePlugin->Create();
150
151 // Armnn Opaque Delegate is created correctly.
152 CHECK((armnnDelegate != nullptr));
153 CHECK((armnnDelegate->opaque_delegate_builder != nullptr));
Matthew Sloyan65c21a12023-04-04 12:06:14 +0100154}
155
Teresa Charlin19ad8162023-10-04 11:17:03 +0100156armnnDelegate::DelegateOptions BuildDelegateOptions(const char* backends,
157 bool fastmath,
158 const char* additional_parameters)
159{
160 flatbuffers::FlatBufferBuilder flatbuffer_builder;
161
162 flatbuffers::Offset<tflite::ArmNNSettings>
163 armnn_settings_offset = tflite::CreateArmNNSettingsDirect(flatbuffer_builder,
164 backends,
165 fastmath,
166 additional_parameters);
167
168 tflite::TFLiteSettingsBuilder tflite_settings_builder(flatbuffer_builder);
169 tflite_settings_builder.add_armnn_settings(armnn_settings_offset);
170 flatbuffers::Offset<tflite::TFLiteSettings> tflite_settings_offset = tflite_settings_builder.Finish();
171 flatbuffer_builder.Finish(tflite_settings_offset);
172
173 const tflite::TFLiteSettings* tflite_settings = flatbuffers::GetRoot<tflite::TFLiteSettings>(
174 flatbuffer_builder.GetBufferPointer());
175
176 armnnDelegate::DelegateOptions delegateOptions = ParseArmNNSettings(tflite_settings);
177
178 return delegateOptions;
179}
180
181unsigned int CountBackendOptions(armnn::BackendId backendId,
182 armnnDelegate::DelegateOptions& delegateOptions,
183 bool runtime = false)
184{
185 unsigned int count = 0;
186
187 std::vector<armnn::BackendOptions> modelOptions = runtime ? delegateOptions.GetRuntimeOptions().m_BackendOptions
188 : delegateOptions.GetOptimizerOptions().GetModelOptions();
189 for (const auto& backendOptions : modelOptions)
190 {
191 if (backendOptions.GetBackendId() == backendId)
192 {
193 count = backendOptions.GetOptionCount();
194 }
195 }
196
197 return count;
198}
199
200bool GetBackendOption(armnn::BackendId backendId,
201 armnnDelegate::DelegateOptions& delegateOptions,
202 std::string& optionName,
203 armnn::BackendOptions::BackendOption& backendOption,
204 bool runtime = false)
205{
206 bool result = false;
207
208 std::vector<armnn::BackendOptions> modelOptions = runtime ? delegateOptions.GetRuntimeOptions().m_BackendOptions
209 : delegateOptions.GetOptimizerOptions().GetModelOptions();
210
211 for (const auto& backendOptions : modelOptions)
212 {
213 if (backendOptions.GetBackendId() == backendId)
214 {
215 for (size_t i = 0; i < backendOptions.GetOptionCount(); ++i)
216 {
217 const armnn::BackendOptions::BackendOption& option = backendOptions.GetOption(i);
218 if (option.GetName() == optionName)
219 {
220 backendOption = option;
221 result = true;
222 break;
223 }
224 }
225 }
226 }
227
228 return result;
229}
230
231TEST_CASE ("ParseArmNNSettings_backend")
232{
233 {
234 armnnDelegate::DelegateOptions delegateOptions = BuildDelegateOptions("CpuRef,GpuAcc", false, nullptr);
235
236 std::vector<armnn::BackendId> expectedBackends = {"CpuRef", "GpuAcc"};
237 CHECK_EQ(expectedBackends, delegateOptions.GetBackends());
238 }
239 {
240 armnnDelegate::DelegateOptions delegateOptions = BuildDelegateOptions("GpuAcc", false, nullptr);
241
242 std::vector<armnn::BackendId> expectedBackends = {"GpuAcc"};
243 CHECK_EQ(expectedBackends, delegateOptions.GetBackends());
244 }
245}
246
247TEST_CASE ("ParseArmNNSettings_fastmath")
248{
249 // Test fastmath true in both backends
250 {
251 armnnDelegate::DelegateOptions delegateOptions = BuildDelegateOptions("CpuAcc,GpuAcc", true, nullptr);
252
253 std::vector<armnn::BackendId> expectedBackends = {"CpuAcc", "GpuAcc"};
254 CHECK_EQ(expectedBackends, delegateOptions.GetBackends());
255 CHECK_EQ(CountBackendOptions(armnn::Compute::CpuAcc, delegateOptions), 1);
256 CHECK_EQ(CountBackendOptions(armnn::Compute::CpuAcc, delegateOptions), 1);
257
258 armnn::BackendOptions::BackendOption backendOption("", false);
259 std::string optionName = "FastMathEnabled";
260 CHECK_EQ(GetBackendOption(armnn::Compute::CpuAcc, delegateOptions, optionName, backendOption), true);
261 CHECK_EQ(backendOption.GetValue().AsBool(), true);
262 CHECK_EQ(backendOption.GetName(), optionName);
263 CHECK_EQ(GetBackendOption(armnn::Compute::GpuAcc, delegateOptions, optionName, backendOption), true);
264 CHECK_EQ(backendOption.GetValue().AsBool(), true);
265 CHECK_EQ(backendOption.GetName(), optionName);
266 }
267
268 // Test fastmath true in one backend
269 {
270 armnnDelegate::DelegateOptions delegateOptions = BuildDelegateOptions("CpuAcc,CpuRef", true, nullptr);
271
272 std::vector<armnn::BackendId> expectedBackends = {"CpuAcc", "CpuRef"};
273 CHECK_EQ(expectedBackends, delegateOptions.GetBackends());
274 CHECK_EQ(CountBackendOptions(armnn::Compute::CpuAcc, delegateOptions), 1);
275 CHECK_EQ(CountBackendOptions(armnn::Compute::CpuRef, delegateOptions), 0);
276
277 armnn::BackendOptions::BackendOption backendOption("", false);
278 std::string optionName = "FastMathEnabled";
279 CHECK_EQ(GetBackendOption(armnn::Compute::CpuAcc, delegateOptions, optionName, backendOption), true);
280 CHECK_EQ(backendOption.GetValue().AsBool(), true);
281 CHECK_EQ(backendOption.GetName(), optionName);
282 CHECK_EQ(GetBackendOption(armnn::Compute::CpuRef, delegateOptions, optionName, backendOption), false);
283 }
284
285 // Test fastmath false
286 {
287 armnnDelegate::DelegateOptions delegateOptions = BuildDelegateOptions("GpuAcc", false, nullptr);
288
289 std::vector<armnn::BackendId> expectedBackends = {"GpuAcc"};
290 CHECK_EQ(expectedBackends, delegateOptions.GetBackends());
291 CHECK_EQ(CountBackendOptions(armnn::Compute::GpuAcc, delegateOptions), 1);
292
293 armnn::BackendOptions::BackendOption backendOption("", false);
294 std::string optionName = "FastMathEnabled";
295 CHECK_EQ(GetBackendOption(armnn::Compute::GpuAcc, delegateOptions, optionName, backendOption), true);
296 CHECK_EQ(backendOption.GetValue().AsBool(), false);
297 CHECK_EQ(backendOption.GetName(), optionName);
298 }
299}
300
301TEST_CASE ("ParseArmNNSettings_additional_options_raw")
302{
303 const char* backends = "GpuAcc";
304 bool fastmath = false;
305 const char* additional_parameters = "allow-expanded-dims=true";
306
307 flatbuffers::FlatBufferBuilder flatbuffer_builder;
308 flatbuffers::Offset<tflite::ArmNNSettings>
309 armnn_settings_offset = tflite::CreateArmNNSettingsDirect(flatbuffer_builder,
310 backends,
311 fastmath,
312 additional_parameters);
313
314 tflite::TFLiteSettingsBuilder tflite_settings_builder(flatbuffer_builder);
315 tflite_settings_builder.add_armnn_settings(armnn_settings_offset);
316 flatbuffers::Offset<tflite::TFLiteSettings> tflite_settings_offset = tflite_settings_builder.Finish();
317 flatbuffer_builder.Finish(tflite_settings_offset);
318
319 const tflite::TFLiteSettings* tflite_settings = flatbuffers::GetRoot<tflite::TFLiteSettings>(
320 flatbuffer_builder.GetBufferPointer());
321 CHECK((tflite_settings->armnn_settings()->additional_parameters() != nullptr));
322 CHECK_EQ(tflite_settings->armnn_settings()->additional_parameters()->str(), additional_parameters);
323
324 armnnDelegate::DelegateOptions delegateOptions = ParseArmNNSettings(tflite_settings);
325 CHECK_EQ(delegateOptions.GetOptimizerOptions().GetAllowExpandedDims(), true);
326}
327
328TEST_CASE ("ParseArmNNSettings_additional_options")
329{
330 std::string options = "number-of-threads=29," // optimizer-backend option only Cpu
331 "gpu-kernel-profiling-enabled=true," // runtime-backend option only GPU
332 "allow-expanded-dims=true," // optimizer option
333 "logging-severity=debug," // option
334 "counter-capture-period=100u"; // runtime-profiling option
335 armnnDelegate::DelegateOptions delegateOptions = BuildDelegateOptions("CpuAcc,GpuAcc", false, options.c_str());
336
337 // Variables to be used in all checks
338 armnn::BackendOptions::BackendOption backendOption("", false);
339 std::string optionName;
340
341 // number-of-threads
342 CHECK_EQ(CountBackendOptions(armnn::Compute::CpuAcc, delegateOptions), 1);
343 optionName = "NumberOfThreads";
344 CHECK_EQ(GetBackendOption(armnn::Compute::CpuAcc, delegateOptions, optionName, backendOption), true);
345 CHECK_EQ(backendOption.GetValue().AsUnsignedInt(), 29);
346 CHECK_EQ(backendOption.GetName(), optionName);
347
348 // gpu-kernel-profiling-enabled
349 CHECK_EQ(CountBackendOptions(armnn::Compute::GpuAcc, delegateOptions, true), 1);
350 optionName = "KernelProfilingEnabled";
351 CHECK_EQ(GetBackendOption(armnn::Compute::GpuAcc, delegateOptions, optionName, backendOption, true), true);
352 CHECK_EQ(backendOption.GetValue().AsBool(), true);
353 CHECK_EQ(backendOption.GetName(), optionName);
354
355 // allow-expanded-dims
356 CHECK_EQ(delegateOptions.GetOptimizerOptions().GetAllowExpandedDims(), true);
357
358 // logging-severity
359 CHECK_EQ(delegateOptions.GetLoggingSeverity(), armnn::LogSeverity::Debug);
360
361 // counter-capture-period
362 CHECK_EQ(delegateOptions.GetRuntimeOptions().m_ProfilingOptions.m_CapturePeriod, 100);
363}
364
365TEST_CASE ("ParseArmNNSettings_additional_options_regex")
366{
367 std::string options = "allow-expanded-dims= true, " // optimizer option
368 "number-of-threads =29 ," // optimizer-backend option only Cpu
369 "logging-severity = trace , " // option
370 "counter-capture-period = 100u"; // runtime-profiling option
371 armnnDelegate::DelegateOptions delegateOptions = BuildDelegateOptions("GpuAcc", false, options.c_str());
372
373 // Variables to be used in all checks
374 armnn::BackendOptions::BackendOption backendOption("", false);
375 std::string optionName;
376
377 std::vector<armnn::BackendId> expectedBackends = {"GpuAcc"};
378 CHECK_EQ(expectedBackends, delegateOptions.GetBackends());
379
380 // enable-fast-math
381 CHECK_EQ(CountBackendOptions(armnn::Compute::GpuAcc, delegateOptions), 1);
382 optionName = "FastMathEnabled";
383 CHECK_EQ(GetBackendOption(armnn::Compute::CpuRef, delegateOptions, optionName, backendOption), false);
384 CHECK_EQ(GetBackendOption(armnn::Compute::CpuAcc, delegateOptions, optionName, backendOption), false);
385 CHECK_EQ(GetBackendOption(armnn::Compute::GpuAcc, delegateOptions, optionName, backendOption), true);
386 CHECK_EQ(backendOption.GetValue().AsBool(), false);
387 CHECK_EQ(backendOption.GetName(), optionName);
388
389 // allow-expanded-dims
390 CHECK_EQ(delegateOptions.GetOptimizerOptions().GetAllowExpandedDims(), true);
391
392 // number-of-threads not saved anywhere, as it is a parameter only valid for CpuAcc
393 optionName="number-of-threads";
394 CHECK_EQ(GetBackendOption(armnn::Compute::CpuAcc, delegateOptions, optionName, backendOption), false);
395 CHECK_EQ(GetBackendOption(armnn::Compute::GpuAcc, delegateOptions, optionName, backendOption), false);
396
397 // logging-severity
398 CHECK_EQ(delegateOptions.GetLoggingSeverity(), armnn::LogSeverity::Trace);
399
400 // counter-capture-period
401 CHECK_EQ(delegateOptions.GetRuntimeOptions().m_ProfilingOptions.m_CapturePeriod, 100);
402}
403
404TEST_CASE ("ParseArmNNSettings_additional_options_incorrect")
405{
406 std::string options = "number-of-thread=29"; // The correct one would be "number-of-threads" in plural
407
408 CHECK_THROWS(BuildDelegateOptions("CpuAcc,GpuAcc", false, options.c_str()));
409}
410
Narumol Prangnawarat26654cb2023-05-03 16:08:11 +0100411}
Matthew Sloyan65c21a12023-04-04 12:06:14 +0100412} // namespace armnnDelegate