xref: /aosp_15_r20/external/armnn/delegate/test/DelegateOptionsTest.cpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1 //
2 // Copyright © 2021, 2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "DelegateOptionsTestHelper.hpp"
7 #include <common/include/ProfilingGuid.hpp>
8 #include <armnnUtils/Filesystem.hpp>
9 
10 namespace armnnDelegate
11 {
12 
13 TEST_SUITE("DelegateOptions")
14 {
15 
16 TEST_CASE ("ArmnnDelegateOptimizerOptionsReduceFp32ToFp16")
17 {
18     std::stringstream ss;
19     {
20         StreamRedirector redirect(std::cout, ss.rdbuf());
21 
22         std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef };
23         std::vector<int32_t> tensorShape { 1, 2, 2, 1 };
24         std::vector<float> inputData = { 1, 2, 3, 4 };
25         std::vector<float> divData = { 2, 2, 3, 4 };
26         std::vector<float> expectedResult = { 1, 2, 2, 2 };
27 
28         // Enable ReduceFp32ToFp16
29         armnn::OptimizerOptionsOpaque optimizerOptions(true, true, false, false);
30         armnnDelegate::DelegateOptions delegateOptions(backends, optimizerOptions);
31 
32         DelegateOptionTest<float>(::tflite::TensorType_FLOAT32,
33                                   tensorShape,
34                                   inputData,
35                                   inputData,
36                                   divData,
37                                   expectedResult,
38                                   delegateOptions);
39     }
40     // ReduceFp32ToFp16 option is enabled
41     CHECK(ss.str().find("convert_fp32_to_fp16") != std::string::npos);
42     CHECK(ss.str().find("convert_fp16_to_fp32") != std::string::npos);
43 }
44 
45 TEST_CASE ("ArmnnDelegateOptimizerOptionsDebug")
46 {
47     std::stringstream ss;
48     {
49         StreamRedirector redirect(std::cout, ss.rdbuf());
50 
51         std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef };
52         std::vector<int32_t> tensorShape { 1, 2, 2, 1 };
53         std::vector<float> inputData = { 1, 2, 3, 4 };
54         std::vector<float> divData = { 2, 2, 3, 4 };
55         std::vector<float> expectedResult = { 1, 2, 2, 2 };
56 
57         // Enable Debug
58         armnn::OptimizerOptionsOpaque optimizerOptions(false, true, false, false);
59         armnnDelegate::DelegateOptions delegateOptions(backends, optimizerOptions);
60 
61         DelegateOptionTest<float>(::tflite::TensorType_FLOAT32,
62                                   tensorShape,
63                                   inputData,
64                                   inputData,
65                                   divData,
66                                   expectedResult,
67                                   delegateOptions);
68     }
69     // Debug option triggered.
70     CHECK(ss.str().find("layerGuid") != std::string::npos);
71     CHECK(ss.str().find("layerName") != std::string::npos);
72     CHECK(ss.str().find("outputSlot") != std::string::npos);
73     CHECK(ss.str().find("shape") != std::string::npos);
74     CHECK(ss.str().find("data") != std::string::npos);
75 }
76 
77 TEST_CASE ("ArmnnDelegateOptimizerOptionsDebugFunction")
78 {
79     std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef };
80     std::vector<int32_t> tensorShape { 1, 2, 2, 1 };
81     std::vector<float> inputData = { 1, 2, 3, 4 };
82     std::vector<float> divData = { 2, 2, 3, 4 };
83     std::vector<float> expectedResult = { 1, 2, 2, 2 };
84 
85     // Enable debug with debug callback function
86     armnn::OptimizerOptionsOpaque optimizerOptions(false, true, false, false);
87     bool callback = false;
88     auto mockCallback = [&](LayerGuid guid, unsigned int slotIndex, armnn::ITensorHandle* tensor)
__anond0a399830102(LayerGuid guid, unsigned int slotIndex, armnn::ITensorHandle* tensor) 89     {
90         armnn::IgnoreUnused(guid);
91         armnn::IgnoreUnused(slotIndex);
92         armnn::IgnoreUnused(tensor);
93         callback = true;
94     };
95 
96     armnn::INetworkProperties networkProperties(false, armnn::MemorySource::Undefined, armnn::MemorySource::Undefined);
97     armnnDelegate::DelegateOptions delegateOptions(backends,
98                                                    optimizerOptions,
99                                                    armnn::EmptyOptional(),
100                                                    armnn::Optional<armnn::DebugCallbackFunction>(mockCallback));
101 
102     CHECK(!callback);
103 
104     DelegateOptionTest<float>(::tflite::TensorType_FLOAT32,
105                               tensorShape,
106                               inputData,
107                               inputData,
108                               divData,
109                               expectedResult,
110                               delegateOptions);
111 
112     // Check that the debug callback function was called.
113     CHECK(callback);
114 }
115 
116 TEST_CASE ("ArmnnDelegateOptimizerOptionsImport")
117 {
118     std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef };
119     std::vector<int32_t> tensorShape { 1, 2, 2, 1 };
120     std::vector<uint8_t> inputData = { 1, 2, 3, 4 };
121     std::vector<uint8_t> divData = { 2, 2, 3, 4 };
122     std::vector<uint8_t> expectedResult = { 1, 2, 2, 2 };
123 
124     armnn::OptimizerOptionsOpaque optimizerOptions(false, false, false, true);
125     armnnDelegate::DelegateOptions delegateOptions(backends, optimizerOptions);
126 
127     DelegateOptionTest<uint8_t>(::tflite::TensorType_UINT8,
128                                 tensorShape,
129                                 inputData,
130                                 inputData,
131                                 divData,
132                                 expectedResult,
133                                 delegateOptions);
134 }
135 
136 TEST_CASE ("ArmnnDelegateStringParsingOptionDisableTfLiteRuntimeFallback")
137 {
138     std::stringstream stringStream;
139     std::vector<std::string> keys   {  "backends", "debug-data", "disable-tflite-runtime-fallback"};
140     std::vector<std::string> values {    "CpuRef",          "1",                               "1"};
141 
142     std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef };
143     std::vector<int32_t> tensorShape { 1, 2, 2, 1 };
144     std::vector<float> inputData = { 0.1f, -2.1f, 3.0f, -4.6f };
145     std::vector<float> expectedResult = { 1.0f, -2.0f, 3.0f, -4.0f };
146 
147     // Create options_keys and options_values char array
148     size_t num_options = keys.size();
149     std::unique_ptr<const char*> options_keys =
150             std::unique_ptr<const char*>(new const char*[num_options + 1]);
151     std::unique_ptr<const char*> options_values =
152             std::unique_ptr<const char*>(new const char*[num_options + 1]);
153     for (size_t i=0; i<num_options; ++i)
154     {
155         options_keys.get()[i]   = keys[i].c_str();
156         options_values.get()[i] = values[i].c_str();
157     }
158 
159     StreamRedirector redirect(std::cout, stringStream.rdbuf());
160 
161     armnnDelegate::DelegateOptions delegateOptions(options_keys.get(), options_values.get(), num_options, nullptr);
162     DelegateOptionNoFallbackTest<float>(::tflite::TensorType_FLOAT32,
163                                         tensorShape,
164                                         inputData,
165                                         expectedResult,
166                                         delegateOptions);
167     CHECK(stringStream.str().find("TfLiteArmnnDelegate: There are unsupported operators in the model")
168                                                                                                  != std::string::npos);
169 }
170 
171 TEST_CASE ("ArmnnDelegateStringParsingOptionEnableTfLiteRuntimeFallback")
172 {
173     std::stringstream stringStream;
174     std::vector<std::string> keys   {  "backends", "debug-data", "disable-tflite-runtime-fallback"};
175     std::vector<std::string> values {    "CpuRef",          "1",                               "0"};
176 
177     std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef };
178     std::vector<int32_t> tensorShape { 1, 2, 2, 1 };
179     std::vector<float> inputData = { 0.1f, -2.1f, 3.0f, -4.6f };
180     std::vector<float> expectedResult = { 0.995004177f, -0.504846036f, -0.989992499f, -0.112152621f };
181 
182     // Create options_keys and options_values char array
183     size_t num_options = keys.size();
184     std::unique_ptr<const char*> options_keys =
185             std::unique_ptr<const char*>(new const char*[num_options + 1]);
186     std::unique_ptr<const char*> options_values =
187             std::unique_ptr<const char*>(new const char*[num_options + 1]);
188     for (size_t i=0; i<num_options; ++i)
189     {
190         options_keys.get()[i]   = keys[i].c_str();
191         options_values.get()[i] = values[i].c_str();
192     }
193 
194     StreamRedirector redirect(std::cout, stringStream.rdbuf());
195 
196     armnnDelegate::DelegateOptions delegateOptions(options_keys.get(), options_values.get(), num_options, nullptr);
197     DelegateOptionNoFallbackTest<float>(::tflite::TensorType_FLOAT32,
198                                         tensorShape,
199                                         inputData,
200                                         expectedResult,
201                                         delegateOptions);
202 
203     CHECK(stringStream.str().find("TfLiteArmnnDelegate: There are unsupported operators in the model")
204                                                                                                  == std::string::npos);
205 }
206 
207 }
208 
209 TEST_SUITE("DelegateOptions_CpuAccTests")
210 {
211 
212 TEST_CASE ("ArmnnDelegateModelOptions_CpuAcc_Test")
213 {
214     std::vector<armnn::BackendId> backends = { armnn::Compute::CpuAcc };
215     std::vector<int32_t> tensorShape { 1, 2, 2, 1 };
216     std::vector<float> inputData = { 1, 2, 3, 4 };
217     std::vector<float> divData = { 2, 2, 3, 4 };
218     std::vector<float> expectedResult = { 1, 2, 2, 2 };
219 
220     unsigned int numberOfThreads = 2;
221 
222     armnn::ModelOptions modelOptions;
223     armnn::BackendOptions cpuAcc("CpuAcc",
224                                  {
225                                          { "FastMathEnabled", true },
226                                          { "NumberOfThreads", numberOfThreads }
227                                  });
228     modelOptions.push_back(cpuAcc);
229 
230     armnn::OptimizerOptionsOpaque optimizerOptions(false, false, false,
231                                                    false, modelOptions, false);
232     armnnDelegate::DelegateOptions delegateOptions(backends, optimizerOptions);
233 
234     DelegateOptionTest<float>(::tflite::TensorType_FLOAT32,
235                               tensorShape,
236                               inputData,
237                               inputData,
238                               divData,
239                               expectedResult,
240                               delegateOptions);
241 }
242 
243 TEST_CASE ("ArmnnDelegateSerializeToDot")
244 {
245     const fs::path filename(fs::temp_directory_path() / "ArmnnDelegateSerializeToDot.dot");
246     if ( fs::exists(filename) )
247     {
248         fs::remove(filename);
249     }
250     std::stringstream ss;
251     {
252         StreamRedirector redirect(std::cout, ss.rdbuf());
253 
254         std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef };
255         std::vector<int32_t> tensorShape { 1, 2, 2, 1 };
256         std::vector<float> inputData = { 1, 2, 3, 4 };
257         std::vector<float> divData = { 2, 2, 3, 4 };
258         std::vector<float> expectedResult = { 1, 2, 2, 2 };
259 
260         armnn::OptimizerOptionsOpaque optimizerOptions(false, false,
261                                                        false, false);
262         armnnDelegate::DelegateOptions delegateOptions(backends, optimizerOptions);
263         // Enable serialize to dot by specifying the target file name.
264         delegateOptions.SetSerializeToDot(filename);
265         DelegateOptionTest<float>(::tflite::TensorType_FLOAT32,
266                                   tensorShape,
267                                   inputData,
268                                   inputData,
269                                   divData,
270                                   expectedResult,
271                                   delegateOptions);
272     }
273     CHECK(fs::exists(filename));
274     // The file should have a size greater than 0 bytes.
275     CHECK(fs::file_size(filename) > 0);
276     // Clean up.
277     fs::remove(filename);
278 }
279 
CreateFp16StringParsingTestRun(std::vector<std::string> & keys,std::vector<std::string> & values,std::stringstream & ss)280 void CreateFp16StringParsingTestRun(std::vector<std::string>& keys,
281                                     std::vector<std::string>& values,
282                                     std::stringstream& ss)
283 {
284     StreamRedirector redirect(std::cout, ss.rdbuf());
285 
286     std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef };
287     std::vector<int32_t> tensorShape { 1, 2, 2, 1 };
288     std::vector<float> inputData = { 1, 2, 3, 4 };
289     std::vector<float> divData = { 2, 2, 3, 4 };
290     std::vector<float> expectedResult = { 1, 2, 2, 2 };
291 
292     // Create options_keys and options_values char array
293     size_t num_options = keys.size();
294     std::unique_ptr<const char*> options_keys =
295             std::unique_ptr<const char*>(new const char*[num_options + 1]);
296     std::unique_ptr<const char*> options_values =
297             std::unique_ptr<const char*>(new const char*[num_options + 1]);
298     for (size_t i=0; i<num_options; ++i)
299     {
300         options_keys.get()[i]   = keys[i].c_str();
301         options_values.get()[i] = values[i].c_str();
302     }
303 
304     armnnDelegate::DelegateOptions delegateOptions(options_keys.get(), options_values.get(),
305                                                    num_options, nullptr);
306     DelegateOptionTest<float>(::tflite::TensorType_FLOAT32,
307                               tensorShape,
308                               inputData,
309                               inputData,
310                               divData,
311                               expectedResult,
312                               delegateOptions);
313 }
314 
315 TEST_CASE ("ArmnnDelegateStringParsingOptionReduceFp32ToFp16")
316 {
317     SUBCASE("Fp16=1")
318     {
319         std::stringstream ss;
320         std::vector<std::string> keys   {  "backends", "debug-data", "reduce-fp32-to-fp16", "logging-severity"};
321         std::vector<std::string> values {    "CpuRef",          "1",                   "1",             "info"};
322         CreateFp16StringParsingTestRun(keys, values, ss);
323         CHECK(ss.str().find("convert_fp32_to_fp16") != std::string::npos);
324         CHECK(ss.str().find("convert_fp16_to_fp32") != std::string::npos);
325     }
326     SUBCASE("Fp16=true")
327     {
328         std::stringstream ss;
329         std::vector<std::string> keys   {  "backends", "debug-data", "reduce-fp32-to-fp16"};
330         std::vector<std::string> values {    "CpuRef",       "TRUE",                "true"};
331         CreateFp16StringParsingTestRun(keys, values, ss);
332         CHECK(ss.str().find("convert_fp32_to_fp16") != std::string::npos);
333         CHECK(ss.str().find("convert_fp16_to_fp32") != std::string::npos);
334     }
335     SUBCASE("Fp16=True")
336     {
337         std::stringstream ss;
338         std::vector<std::string> keys   {  "backends", "debug-data", "reduce-fp32-to-fp16"};
339         std::vector<std::string> values {    "CpuRef",       "true",                "True"};
340         CreateFp16StringParsingTestRun(keys, values, ss);
341         CHECK(ss.str().find("convert_fp32_to_fp16") != std::string::npos);
342         CHECK(ss.str().find("convert_fp16_to_fp32") != std::string::npos);
343     }
344     SUBCASE("Fp16=0")
345     {
346         std::stringstream ss;
347         std::vector<std::string> keys   {  "backends", "debug-data", "reduce-fp32-to-fp16"};
348         std::vector<std::string> values {    "CpuRef",       "true",                   "0"};
349         CreateFp16StringParsingTestRun(keys, values, ss);
350         CHECK(ss.str().find("convert_fp32_to_fp16") == std::string::npos);
351         CHECK(ss.str().find("convert_fp16_to_fp32") == std::string::npos);
352     }
353     SUBCASE("Fp16=false")
354     {
355         std::stringstream ss;
356         std::vector<std::string> keys   {  "backends", "debug-data", "reduce-fp32-to-fp16"};
357         std::vector<std::string> values {    "CpuRef",     "1",               "false"};
358         CreateFp16StringParsingTestRun(keys, values, ss);
359         CHECK(ss.str().find("convert_fp32_to_fp16") == std::string::npos);
360         CHECK(ss.str().find("convert_fp16_to_fp32") == std::string::npos);
361     }
362 }
363 
364 }
365 
366 } // namespace armnnDelegate
367