blob: 884bed009fb5e56f8417acd068fe79a778494ee3 [file] [log] [blame]
telsoa015307bc12018-03-09 13:51:08 +00001//
Mike Kellye2d611e2021-10-14 12:35:58 +01002// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
David Beck93e48982018-09-05 13:05:09 +01003// SPDX-License-Identifier: MIT
telsoa015307bc12018-03-09 13:51:08 +00004//
5
6#define LOG_TAG "ArmnnDriver"
7
8#include "Utils.hpp"
Jim Flynnf2e175c2019-12-12 15:11:30 +00009#include "Half.hpp"
telsoa015307bc12018-03-09 13:51:08 +000010
Sadik Armaganb3021432021-01-13 15:56:51 +000011#include <armnnSerializer/ISerializer.hpp>
Rob Hughes083be702021-07-19 15:29:47 +010012#include <armnnUtils/Filesystem.hpp>
Matteo Martincigh00d6ed12019-11-28 17:13:24 +000013#include <armnnUtils/Permute.hpp>
14
Derek Lambertid00ad912020-01-22 15:55:16 +000015#include <armnn/Utils.hpp>
Colm Donelan08d9a1c2020-09-09 17:56:55 +010016#include <log/log.h>
Derek Lambertid00ad912020-01-22 15:55:16 +000017
Jim Flynn829ad302019-12-13 14:43:24 +000018#include <cerrno>
telsoa015307bc12018-03-09 13:51:08 +000019#include <cinttypes>
Jim Flynn829ad302019-12-13 14:43:24 +000020#include <sstream>
21#include <cstdio>
22#include <time.h>
23
telsoa015307bc12018-03-09 13:51:08 +000024using namespace android;
telsoa01ce3e84a2018-08-31 09:31:35 +010025using namespace android::hardware;
telsoa015307bc12018-03-09 13:51:08 +000026using namespace android::hidl::memory::V1_0;
27
28namespace armnn_driver
29{
30const armnn::PermutationVector g_DontPermute{};
31
Jan Eilersa71c0632021-04-12 13:12:19 +010032void SwizzleAndroidNn4dTensorToArmNn(armnn::TensorInfo& tensorInfo, const void* input, void* output,
telsoa015307bc12018-03-09 13:51:08 +000033 const armnn::PermutationVector& mappings)
34{
Mike Kellye2d611e2021-10-14 12:35:58 +010035 if (tensorInfo.GetNumDimensions() != 4U)
36 {
37 throw armnn::InvalidArgumentException("NumDimensions must be 4");
38 }
Jan Eilersa71c0632021-04-12 13:12:19 +010039 armnn::DataType dataType = tensorInfo.GetDataType();
Matteo Martincighbf19d2a2019-11-29 11:46:50 +000040 switch (dataType)
telsoa015307bc12018-03-09 13:51:08 +000041 {
Mike Kelly3c673942019-07-25 09:26:06 +010042 case armnn::DataType::Float16:
telsoa015307bc12018-03-09 13:51:08 +000043 case armnn::DataType::Float32:
Derek Lamberti1a38cda2020-01-10 17:28:20 +000044 case armnn::DataType::QAsymmU8:
Mike Kellye2d611e2021-10-14 12:35:58 +010045 case armnn::DataType::QSymmS16:
Derek Lambertid00ad912020-01-22 15:55:16 +000046 case armnn::DataType::QSymmS8:
Sadik Armagan1153d1e2020-04-01 15:09:39 +010047 case armnn::DataType::QAsymmS8:
Jan Eilersa71c0632021-04-12 13:12:19 +010048 // First swizzle tensor info
49 tensorInfo = armnnUtils::Permuted(tensorInfo, mappings);
50 // Then swizzle tensor data
51 armnnUtils::Permute(tensorInfo.GetShape(), mappings, input, output, armnn::GetDataTypeSize(dataType));
Aron Virginas-Tar9f0693b2019-11-06 14:32:30 +000052 break;
telsoa015307bc12018-03-09 13:51:08 +000053 default:
Mike Kellye2d611e2021-10-14 12:35:58 +010054 throw armnn::InvalidArgumentException("Unknown DataType for swizzling");
telsoa015307bc12018-03-09 13:51:08 +000055 }
56}
57
Sadik Armagan188675f2021-02-12 17:16:42 +000058void* GetMemoryFromPool(V1_0::DataLocation location, const std::vector<android::nn::RunTimePoolInfo>& memPools)
telsoa015307bc12018-03-09 13:51:08 +000059{
60 // find the location within the pool
Mike Kellye2d611e2021-10-14 12:35:58 +010061 if (location.poolIndex >= memPools.size())
62 {
63 throw armnn::InvalidArgumentException("The poolIndex is greater than the memPools size.");
64 }
telsoa015307bc12018-03-09 13:51:08 +000065
surmeh01deb3bdb2018-07-05 12:06:04 +010066 const android::nn::RunTimePoolInfo& memPool = memPools[location.poolIndex];
67
surmeh01deb3bdb2018-07-05 12:06:04 +010068 uint8_t* memPoolBuffer = memPool.getBuffer();
surmeh01deb3bdb2018-07-05 12:06:04 +010069
70 uint8_t* memory = memPoolBuffer + location.offset;
telsoa015307bc12018-03-09 13:51:08 +000071
72 return memory;
73}
74
Matthew Bentham912b3622019-05-03 15:49:14 +010075armnn::TensorInfo GetTensorInfoForOperand(const V1_0::Operand& operand)
telsoa015307bc12018-03-09 13:51:08 +000076{
Finn Williamsa4983ce2020-07-23 12:55:12 +010077 using namespace armnn;
78 DataType type;
telsoa015307bc12018-03-09 13:51:08 +000079
80 switch (operand.type)
81 {
Matthew Bentham912b3622019-05-03 15:49:14 +010082 case V1_0::OperandType::TENSOR_FLOAT32:
telsoa015307bc12018-03-09 13:51:08 +000083 type = armnn::DataType::Float32;
84 break;
Matthew Bentham912b3622019-05-03 15:49:14 +010085 case V1_0::OperandType::TENSOR_QUANT8_ASYMM:
Derek Lamberti1a38cda2020-01-10 17:28:20 +000086 type = armnn::DataType::QAsymmU8;
telsoa015307bc12018-03-09 13:51:08 +000087 break;
Matthew Bentham912b3622019-05-03 15:49:14 +010088 case V1_0::OperandType::TENSOR_INT32:
telsoa015307bc12018-03-09 13:51:08 +000089 type = armnn::DataType::Signed32;
90 break;
91 default:
Mike Kellyb5fdf382019-06-11 16:35:25 +010092 throw UnsupportedOperand<V1_0::OperandType>(operand.type);
telsoa015307bc12018-03-09 13:51:08 +000093 }
94
Finn Williamsa4983ce2020-07-23 12:55:12 +010095 TensorInfo ret;
96 if (operand.dimensions.size() == 0)
97 {
98 TensorShape tensorShape(Dimensionality::NotSpecified);
99 ret = TensorInfo(tensorShape, type);
100 }
101 else
102 {
103 bool dimensionsSpecificity[5] = { true, true, true, true, true };
104 int count = 0;
105 std::for_each(operand.dimensions.data(),
106 operand.dimensions.data() + operand.dimensions.size(),
107 [&](const unsigned int val)
108 {
109 if (val == 0)
110 {
111 dimensionsSpecificity[count] = false;
112 }
113 count++;
114 });
115
116 TensorShape tensorShape(operand.dimensions.size(), operand.dimensions.data(), dimensionsSpecificity);
117 ret = TensorInfo(tensorShape, type);
118 }
telsoa015307bc12018-03-09 13:51:08 +0000119
120 ret.SetQuantizationScale(operand.scale);
121 ret.SetQuantizationOffset(operand.zeroPoint);
122
123 return ret;
124}
125
Kevin May42477c12020-03-26 13:34:14 +0000126#if defined(ARMNN_ANDROID_NN_V1_2) || defined(ARMNN_ANDROID_NN_V1_3)// Using ::android::hardware::neuralnetworks::V1_2
Mike Kellyb5fdf382019-06-11 16:35:25 +0100127
128armnn::TensorInfo GetTensorInfoForOperand(const V1_2::Operand& operand)
129{
Aron Virginas-Tar9f0693b2019-11-06 14:32:30 +0000130 using namespace armnn;
Derek Lambertid00ad912020-01-22 15:55:16 +0000131 bool perChannel = false;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100132
Aron Virginas-Tar9f0693b2019-11-06 14:32:30 +0000133 DataType type;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100134 switch (operand.type)
135 {
Sadik Armagan793a70c2020-03-19 13:54:04 +0000136 case V1_2::OperandType::TENSOR_BOOL8:
137 type = armnn::DataType::Boolean;
138 break;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100139 case V1_2::OperandType::TENSOR_FLOAT32:
140 type = armnn::DataType::Float32;
141 break;
Mike Kelly3c673942019-07-25 09:26:06 +0100142 case V1_2::OperandType::TENSOR_FLOAT16:
143 type = armnn::DataType::Float16;
144 break;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100145 case V1_2::OperandType::TENSOR_QUANT8_ASYMM:
Derek Lamberti1a38cda2020-01-10 17:28:20 +0000146 type = armnn::DataType::QAsymmU8;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100147 break;
Derek Lambertid00ad912020-01-22 15:55:16 +0000148 case V1_2::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
149 perChannel=true;
150 ARMNN_FALLTHROUGH;
Mike Kelly0e2e31b2019-11-19 09:16:00 +0000151 case V1_2::OperandType::TENSOR_QUANT8_SYMM:
FinnWilliamsArm624fe9f2019-12-06 17:12:42 +0000152 type = armnn::DataType::QSymmS8;
Mike Kelly0e2e31b2019-11-19 09:16:00 +0000153 break;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100154 case V1_2::OperandType::TENSOR_QUANT16_SYMM:
Derek Lamberti1a38cda2020-01-10 17:28:20 +0000155 type = armnn::DataType::QSymmS16;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100156 break;
157 case V1_2::OperandType::TENSOR_INT32:
158 type = armnn::DataType::Signed32;
159 break;
160 default:
161 throw UnsupportedOperand<V1_2::OperandType>(operand.type);
162 }
163
Finn Williamsa4983ce2020-07-23 12:55:12 +0100164 TensorInfo ret;
165 if (operand.dimensions.size() == 0)
166 {
167 TensorShape tensorShape(Dimensionality::NotSpecified);
168 ret = TensorInfo(tensorShape, type);
169 }
170 else
171 {
172 bool dimensionsSpecificity[5] = { true, true, true, true, true };
173 int count = 0;
174 std::for_each(operand.dimensions.data(),
175 operand.dimensions.data() + operand.dimensions.size(),
176 [&](const unsigned int val)
177 {
178 if (val == 0)
179 {
180 dimensionsSpecificity[count] = false;
181 }
182 count++;
183 });
184
185 TensorShape tensorShape(operand.dimensions.size(), operand.dimensions.data(), dimensionsSpecificity);
186 ret = TensorInfo(tensorShape, type);
187 }
188
Derek Lambertid00ad912020-01-22 15:55:16 +0000189 if (perChannel)
Aron Virginas-Tar9f0693b2019-11-06 14:32:30 +0000190 {
Mike Kellye2d611e2021-10-14 12:35:58 +0100191 if (operand.extraParams.getDiscriminator() != V1_2::Operand::ExtraParams::hidl_discriminator::channelQuant)
192 {
193 throw armnn::InvalidArgumentException("ExtraParams is expected to be of type channelQuant");
194 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100195
Aron Virginas-Tar9f0693b2019-11-06 14:32:30 +0000196 auto perAxisQuantParams = operand.extraParams.channelQuant();
197
198 ret.SetQuantizationScales(perAxisQuantParams.scales);
199 ret.SetQuantizationDim(MakeOptional<unsigned int>(perAxisQuantParams.channelDim));
200 }
201 else
202 {
203 ret.SetQuantizationScale(operand.scale);
204 ret.SetQuantizationOffset(operand.zeroPoint);
205 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100206
207 return ret;
208}
209
210#endif
211
Kevin May42477c12020-03-26 13:34:14 +0000212#ifdef ARMNN_ANDROID_NN_V1_3 // Using ::android::hardware::neuralnetworks::V1_3
213
214armnn::TensorInfo GetTensorInfoForOperand(const V1_3::Operand& operand)
215{
216 using namespace armnn;
217 bool perChannel = false;
Teresa Charlin896572b2020-07-15 12:37:51 +0100218 bool isScalar = false;
Kevin May42477c12020-03-26 13:34:14 +0000219
220 DataType type;
221 switch (operand.type)
222 {
Sadik Armagan51ba2c62020-03-31 15:36:25 +0100223 case V1_3::OperandType::TENSOR_BOOL8:
224 type = armnn::DataType::Boolean;
225 break;
Kevin May42477c12020-03-26 13:34:14 +0000226 case V1_3::OperandType::TENSOR_FLOAT32:
227 type = armnn::DataType::Float32;
228 break;
229 case V1_3::OperandType::TENSOR_FLOAT16:
230 type = armnn::DataType::Float16;
231 break;
232 case V1_3::OperandType::TENSOR_QUANT8_ASYMM:
233 type = armnn::DataType::QAsymmU8;
234 break;
235 case V1_3::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
236 perChannel=true;
237 ARMNN_FALLTHROUGH;
238 case V1_3::OperandType::TENSOR_QUANT8_SYMM:
239 type = armnn::DataType::QSymmS8;
240 break;
241 case V1_3::OperandType::TENSOR_QUANT16_SYMM:
242 type = armnn::DataType::QSymmS16;
243 break;
244 case V1_3::OperandType::TENSOR_INT32:
245 type = armnn::DataType::Signed32;
246 break;
Finn Williamsfc884b42020-06-11 17:35:44 +0100247 case V1_3::OperandType::INT32:
248 type = armnn::DataType::Signed32;
Teresa Charlin896572b2020-07-15 12:37:51 +0100249 isScalar = true;
Finn Williamsfc884b42020-06-11 17:35:44 +0100250 break;
Kevin May42477c12020-03-26 13:34:14 +0000251 case V1_3::OperandType::TENSOR_QUANT8_ASYMM_SIGNED:
252 type = armnn::DataType::QAsymmS8;
253 break;
254 default:
255 throw UnsupportedOperand<V1_3::OperandType>(operand.type);
256 }
257
Finn Williamsfc884b42020-06-11 17:35:44 +0100258 TensorInfo ret;
Teresa Charlin896572b2020-07-15 12:37:51 +0100259 if (isScalar)
Finn Williamsfc884b42020-06-11 17:35:44 +0100260 {
Teresa Charlin896572b2020-07-15 12:37:51 +0100261 ret = TensorInfo(TensorShape(armnn::Dimensionality::Scalar), type);
Finn Williamsfc884b42020-06-11 17:35:44 +0100262 }
263 else
264 {
Finn Williamsa4983ce2020-07-23 12:55:12 +0100265 if (operand.dimensions.size() == 0)
266 {
267 TensorShape tensorShape(Dimensionality::NotSpecified);
268 ret = TensorInfo(tensorShape, type);
269 }
270 else
271 {
272 bool dimensionsSpecificity[5] = { true, true, true, true, true };
273 int count = 0;
274 std::for_each(operand.dimensions.data(),
275 operand.dimensions.data() + operand.dimensions.size(),
276 [&](const unsigned int val)
277 {
278 if (val == 0)
279 {
280 dimensionsSpecificity[count] = false;
281 }
282 count++;
283 });
284
285 TensorShape tensorShape(operand.dimensions.size(), operand.dimensions.data(), dimensionsSpecificity);
286 ret = TensorInfo(tensorShape, type);
287 }
Finn Williamsfc884b42020-06-11 17:35:44 +0100288 }
289
Kevin May42477c12020-03-26 13:34:14 +0000290 if (perChannel)
291 {
292 // ExtraParams is expected to be of type channelQuant
Mike Kellye2d611e2021-10-14 12:35:58 +0100293 if (operand.extraParams.getDiscriminator() != V1_2::Operand::ExtraParams::hidl_discriminator::channelQuant)
294 {
295 throw armnn::InvalidArgumentException("ExtraParams is expected to be of type channelQuant");
296 }
Kevin May42477c12020-03-26 13:34:14 +0000297 auto perAxisQuantParams = operand.extraParams.channelQuant();
298
299 ret.SetQuantizationScales(perAxisQuantParams.scales);
300 ret.SetQuantizationDim(MakeOptional<unsigned int>(perAxisQuantParams.channelDim));
301 }
302 else
303 {
304 ret.SetQuantizationScale(operand.scale);
305 ret.SetQuantizationOffset(operand.zeroPoint);
306 }
Kevin May42477c12020-03-26 13:34:14 +0000307 return ret;
308}
309
310#endif
311
Matthew Bentham912b3622019-05-03 15:49:14 +0100312std::string GetOperandSummary(const V1_0::Operand& operand)
telsoa015307bc12018-03-09 13:51:08 +0000313{
314 return android::hardware::details::arrayToString(operand.dimensions, operand.dimensions.size()) + " " +
315 toString(operand.type);
316}
317
Kevin May42477c12020-03-26 13:34:14 +0000318#if defined(ARMNN_ANDROID_NN_V1_2) || defined(ARMNN_ANDROID_NN_V1_3) // Using ::android::hardware::neuralnetworks::V1_2
Mike Kellyb5fdf382019-06-11 16:35:25 +0100319
320std::string GetOperandSummary(const V1_2::Operand& operand)
321{
322 return android::hardware::details::arrayToString(operand.dimensions, operand.dimensions.size()) + " " +
323 toString(operand.type);
324}
325
326#endif
327
Kevin May42477c12020-03-26 13:34:14 +0000328#ifdef ARMNN_ANDROID_NN_V1_3 // Using ::android::hardware::neuralnetworks::V1_3
329
330std::string GetOperandSummary(const V1_3::Operand& operand)
331{
332 return android::hardware::details::arrayToString(operand.dimensions, operand.dimensions.size()) + " " +
333 toString(operand.type);
334}
335
336#endif
337
Mike Kellybc8caca2021-11-09 15:43:37 +0000338template <typename TensorType>
339using DumpElementFunction = void (*)(const TensorType& tensor,
telsoa015307bc12018-03-09 13:51:08 +0000340 unsigned int elementIndex,
341 std::ofstream& fileStream);
342
343namespace
344{
Mike Kellybc8caca2021-11-09 15:43:37 +0000345template <typename TensorType, typename ElementType, typename PrintableType = ElementType>
346void DumpTensorElement(const TensorType& tensor, unsigned int elementIndex, std::ofstream& fileStream)
telsoa015307bc12018-03-09 13:51:08 +0000347{
348 const ElementType* elements = reinterpret_cast<const ElementType*>(tensor.GetMemoryArea());
Teresa Charlin32fe97e2021-03-08 19:28:24 +0000349 fileStream << static_cast<PrintableType>(elements[elementIndex]) << " ";
telsoa015307bc12018-03-09 13:51:08 +0000350}
351
telsoa015307bc12018-03-09 13:51:08 +0000352} // namespace
353
Mike Kellybc8caca2021-11-09 15:43:37 +0000354template <typename TensorType>
telsoa015307bc12018-03-09 13:51:08 +0000355void DumpTensor(const std::string& dumpDir,
356 const std::string& requestName,
357 const std::string& tensorName,
Mike Kellybc8caca2021-11-09 15:43:37 +0000358 const TensorType& tensor)
telsoa015307bc12018-03-09 13:51:08 +0000359{
360 // The dump directory must exist in advance.
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100361 fs::path dumpPath = dumpDir;
362 const fs::path fileName = dumpPath / (requestName + "_" + tensorName + ".dump");
telsoa015307bc12018-03-09 13:51:08 +0000363
364 std::ofstream fileStream;
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100365 fileStream.open(fileName.c_str(), std::ofstream::out | std::ofstream::trunc);
telsoa015307bc12018-03-09 13:51:08 +0000366
367 if (!fileStream.good())
368 {
369 ALOGW("Could not open file %s for writing", fileName.c_str());
370 return;
371 }
372
Mike Kellybc8caca2021-11-09 15:43:37 +0000373 DumpElementFunction<TensorType> dumpElementFunction = nullptr;
telsoa015307bc12018-03-09 13:51:08 +0000374
375 switch (tensor.GetDataType())
376 {
377 case armnn::DataType::Float32:
378 {
Mike Kellybc8caca2021-11-09 15:43:37 +0000379 dumpElementFunction = &DumpTensorElement<TensorType, float>;
telsoa015307bc12018-03-09 13:51:08 +0000380 break;
381 }
Derek Lamberti1a38cda2020-01-10 17:28:20 +0000382 case armnn::DataType::QAsymmU8:
telsoa015307bc12018-03-09 13:51:08 +0000383 {
Mike Kellybc8caca2021-11-09 15:43:37 +0000384 dumpElementFunction = &DumpTensorElement<TensorType, uint8_t, uint32_t>;
telsoa015307bc12018-03-09 13:51:08 +0000385 break;
386 }
387 case armnn::DataType::Signed32:
388 {
Mike Kellybc8caca2021-11-09 15:43:37 +0000389 dumpElementFunction = &DumpTensorElement<TensorType, int32_t>;
telsoa015307bc12018-03-09 13:51:08 +0000390 break;
391 }
Jim Flynnf2e175c2019-12-12 15:11:30 +0000392 case armnn::DataType::Float16:
393 {
Mike Kellybc8caca2021-11-09 15:43:37 +0000394 dumpElementFunction = &DumpTensorElement<TensorType, armnn::Half>;
Jim Flynnf2e175c2019-12-12 15:11:30 +0000395 break;
396 }
Teresa Charlinb248ec12020-04-30 11:06:34 +0100397 case armnn::DataType::QAsymmS8:
398 {
Mike Kellybc8caca2021-11-09 15:43:37 +0000399 dumpElementFunction = &DumpTensorElement<TensorType, int8_t, int32_t>;
Teresa Charlinb248ec12020-04-30 11:06:34 +0100400 break;
401 }
402 case armnn::DataType::Boolean:
403 {
Mike Kellybc8caca2021-11-09 15:43:37 +0000404 dumpElementFunction = &DumpTensorElement<TensorType, bool>;
Teresa Charlinb248ec12020-04-30 11:06:34 +0100405 break;
406 }
telsoa015307bc12018-03-09 13:51:08 +0000407 default:
408 {
409 dumpElementFunction = nullptr;
410 }
411 }
412
413 if (dumpElementFunction != nullptr)
414 {
415 const unsigned int numDimensions = tensor.GetNumDimensions();
Teresa Charlin32fe97e2021-03-08 19:28:24 +0000416 const armnn::TensorShape shape = tensor.GetShape();
telsoa015307bc12018-03-09 13:51:08 +0000417
Mike Kelly7780e602021-04-26 21:54:55 +0100418 if (!shape.AreAllDimensionsSpecified())
419 {
420 fileStream << "Cannot dump tensor elements: not all dimensions are specified" << std::endl;
421 return;
422 }
telsoa015307bc12018-03-09 13:51:08 +0000423 fileStream << "# Number of elements " << tensor.GetNumElements() << std::endl;
Mike Kelly7780e602021-04-26 21:54:55 +0100424
425 if (numDimensions == 0)
426 {
427 fileStream << "# Shape []" << std::endl;
428 return;
429 }
Teresa Charlin32fe97e2021-03-08 19:28:24 +0000430 fileStream << "# Shape [" << shape[0];
431 for (unsigned int d = 1; d < numDimensions; ++d)
telsoa015307bc12018-03-09 13:51:08 +0000432 {
Teresa Charlin32fe97e2021-03-08 19:28:24 +0000433 fileStream << "," << shape[d];
telsoa015307bc12018-03-09 13:51:08 +0000434 }
435 fileStream << "]" << std::endl;
Teresa Charlin32fe97e2021-03-08 19:28:24 +0000436 fileStream << "Each line contains the data of each of the elements of dimension0. In NCHW and NHWC, each line"
437 " will be a batch" << std::endl << std::endl;
telsoa015307bc12018-03-09 13:51:08 +0000438
Teresa Charlin32fe97e2021-03-08 19:28:24 +0000439 // Split will create a new line after all elements of the first dimension
440 // (in a 4, 3, 2, 3 tensor, there will be 4 lines of 18 elements)
441 unsigned int split = 1;
442 if (numDimensions == 1)
telsoa015307bc12018-03-09 13:51:08 +0000443 {
Teresa Charlin32fe97e2021-03-08 19:28:24 +0000444 split = shape[0];
445 }
446 else
447 {
448 for (unsigned int i = 1; i < numDimensions; ++i)
telsoa015307bc12018-03-09 13:51:08 +0000449 {
Teresa Charlin32fe97e2021-03-08 19:28:24 +0000450 split *= shape[i];
telsoa015307bc12018-03-09 13:51:08 +0000451 }
Teresa Charlin32fe97e2021-03-08 19:28:24 +0000452 }
453
454 // Print all elements in the tensor
455 for (unsigned int elementIndex = 0; elementIndex < tensor.GetNumElements(); ++elementIndex)
456 {
457 (*dumpElementFunction)(tensor, elementIndex, fileStream);
458
459 if ( (elementIndex + 1) % split == 0 )
telsoa015307bc12018-03-09 13:51:08 +0000460 {
Teresa Charlin32fe97e2021-03-08 19:28:24 +0000461 fileStream << std::endl;
telsoa015307bc12018-03-09 13:51:08 +0000462 }
telsoa015307bc12018-03-09 13:51:08 +0000463 }
464 fileStream << std::endl;
465 }
466 else
467 {
468 fileStream << "Cannot dump tensor elements: Unsupported data type "
469 << static_cast<unsigned int>(tensor.GetDataType()) << std::endl;
470 }
471
472 if (!fileStream.good())
473 {
474 ALOGW("An error occurred when writing to file %s", fileName.c_str());
475 }
476}
477
Mike Kellybc8caca2021-11-09 15:43:37 +0000478
479template void DumpTensor<armnn::ConstTensor>(const std::string& dumpDir,
480 const std::string& requestName,
481 const std::string& tensorName,
482 const armnn::ConstTensor& tensor);
483
484template void DumpTensor<armnn::Tensor>(const std::string& dumpDir,
485 const std::string& requestName,
486 const std::string& tensorName,
487 const armnn::Tensor& tensor);
488
telsoa01ce3e84a2018-08-31 09:31:35 +0100489void DumpJsonProfilingIfRequired(bool gpuProfilingEnabled,
490 const std::string& dumpDir,
491 armnn::NetworkId networkId,
492 const armnn::IProfiler* profiler)
493{
494 // Check if profiling is required.
495 if (!gpuProfilingEnabled)
496 {
497 return;
498 }
499
500 // The dump directory must exist in advance.
501 if (dumpDir.empty())
502 {
503 return;
504 }
505
Mike Kellye2d611e2021-10-14 12:35:58 +0100506 if (!profiler)
507 {
508 ALOGW("profiler was null");
509 return;
510 }
telsoa01ce3e84a2018-08-31 09:31:35 +0100511
512 // Set the name of the output profiling file.
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100513 fs::path dumpPath = dumpDir;
514 const fs::path fileName = dumpPath / (std::to_string(networkId) + "_profiling.json");
telsoa01ce3e84a2018-08-31 09:31:35 +0100515
516 // Open the ouput file for writing.
517 std::ofstream fileStream;
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100518 fileStream.open(fileName.c_str(), std::ofstream::out | std::ofstream::trunc);
telsoa01ce3e84a2018-08-31 09:31:35 +0100519
520 if (!fileStream.good())
521 {
522 ALOGW("Could not open file %s for writing", fileName.c_str());
523 return;
524 }
525
526 // Write the profiling info to a JSON file.
527 profiler->Print(fileStream);
528}
529
Jim Flynn829ad302019-12-13 14:43:24 +0000530std::string ExportNetworkGraphToDotFile(const armnn::IOptimizedNetwork& optimizedNetwork,
531 const std::string& dumpDir)
532{
533 std::string fileName;
534 // The dump directory must exist in advance.
535 if (dumpDir.empty())
536 {
537 return fileName;
538 }
539
540 std::string timestamp = GetFileTimestamp();
541 if (timestamp.empty())
542 {
543 return fileName;
544 }
545
546 // Set the name of the output .dot file.
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100547 fs::path dumpPath = dumpDir;
548 fs::path tempFilePath = dumpPath / (timestamp + "_networkgraph.dot");
549 fileName = tempFilePath.string();
Jim Flynn829ad302019-12-13 14:43:24 +0000550
551 ALOGV("Exporting the optimized network graph to file: %s", fileName.c_str());
552
553 // Write the network graph to a dot file.
554 std::ofstream fileStream;
555 fileStream.open(fileName, std::ofstream::out | std::ofstream::trunc);
556
557 if (!fileStream.good())
558 {
559 ALOGW("Could not open file %s for writing", fileName.c_str());
560 return fileName;
561 }
562
563 if (optimizedNetwork.SerializeToDot(fileStream) != armnn::Status::Success)
564 {
565 ALOGW("An error occurred when writing to file %s", fileName.c_str());
566 }
567 return fileName;
568}
569
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100570std::string SerializeNetwork(const armnn::INetwork& network,
571 const std::string& dumpDir,
572 std::vector<uint8_t>& dataCacheData,
573 bool dataCachingActive)
Sadik Armaganb3021432021-01-13 15:56:51 +0000574{
575 std::string fileName;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100576 bool bSerializeToFile = true;
Sadik Armaganb3021432021-01-13 15:56:51 +0000577 if (dumpDir.empty())
578 {
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100579 bSerializeToFile = false;
Sadik Armaganb3021432021-01-13 15:56:51 +0000580 }
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100581 else
582 {
583 std::string timestamp = GetFileTimestamp();
584 if (timestamp.empty())
585 {
586 bSerializeToFile = false;
587 }
588 }
589 if (!bSerializeToFile && !dataCachingActive)
Sadik Armaganb3021432021-01-13 15:56:51 +0000590 {
591 return fileName;
592 }
593
594 auto serializer(armnnSerializer::ISerializer::Create());
Sadik Armaganb3021432021-01-13 15:56:51 +0000595 // Serialize the Network
596 serializer->Serialize(network);
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100597 if (dataCachingActive)
Sadik Armaganb3021432021-01-13 15:56:51 +0000598 {
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100599 std::stringstream stream;
600 auto serialized = serializer->SaveSerializedToStream(stream);
601 if (serialized)
602 {
603 std::string const serializedString{stream.str()};
604 std::copy(serializedString.begin(), serializedString.end(), std::back_inserter(dataCacheData));
605 }
606 }
607
608 if (bSerializeToFile)
609 {
610 // Set the name of the output .armnn file.
611 fs::path dumpPath = dumpDir;
612 std::string timestamp = GetFileTimestamp();
613 fs::path tempFilePath = dumpPath / (timestamp + "_network.armnn");
614 fileName = tempFilePath.string();
615
616 // Save serialized network to a file
617 std::ofstream serializedFile(fileName, std::ios::out | std::ios::binary);
618 auto serialized = serializer->SaveSerializedToStream(serializedFile);
619 if (!serialized)
620 {
621 ALOGW("An error occurred when serializing to file %s", fileName.c_str());
622 }
Sadik Armaganb3021432021-01-13 15:56:51 +0000623 }
624 return fileName;
625}
626
Finn Williamsa4983ce2020-07-23 12:55:12 +0100627bool IsDynamicTensor(const armnn::TensorInfo& tensorInfo)
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100628{
Finn Williamsa4983ce2020-07-23 12:55:12 +0100629 if (tensorInfo.GetShape().GetDimensionality() == armnn::Dimensionality::NotSpecified)
630 {
631 return true;
632 }
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100633 // Account for the usage of the TensorShape empty constructor
634 if (tensorInfo.GetNumDimensions() == 0)
635 {
636 return true;
637 }
Finn Williamsa4983ce2020-07-23 12:55:12 +0100638 return !tensorInfo.GetShape().AreAllDimensionsSpecified();
639}
640
641bool AreDynamicTensorsSupported()
642{
643#if defined(ARMNN_ANDROID_NN_V1_3)
644 return true;
645#else
646 return false;
647#endif
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100648}
649
Teresa Charlind3381d52021-06-02 18:35:16 +0100650bool isQuantizedOperand(const V1_0::OperandType& operandType)
651{
652 if (operandType == V1_0::OperandType::TENSOR_QUANT8_ASYMM)
653 {
654 return true;
655 }
656 else
657 {
658 return false;
659 }
660}
661
662#if defined(ARMNN_ANDROID_NN_V1_2) || defined(ARMNN_ANDROID_NN_V1_3)// Using ::android::hardware::neuralnetworks::V1_2
663bool isQuantizedOperand(const V1_2::OperandType& operandType)
664{
665 if (operandType == V1_2::OperandType::TENSOR_QUANT8_ASYMM ||
666 operandType == V1_2::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL ||
667 operandType == V1_2::OperandType::TENSOR_QUANT8_SYMM ||
668 operandType == V1_2::OperandType::TENSOR_QUANT16_SYMM )
669 {
670 return true;
671 }
672 else
673 {
674 return false;
675 }
676}
677#endif
678
679#ifdef ARMNN_ANDROID_NN_V1_3 // Using ::android::hardware::neuralnetworks::V1_3
680bool isQuantizedOperand(const V1_3::OperandType& operandType)
681{
682 if (operandType == V1_3::OperandType::TENSOR_QUANT8_ASYMM ||
683 operandType == V1_3::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL ||
684 operandType == V1_3::OperandType::TENSOR_QUANT8_SYMM ||
685 operandType == V1_3::OperandType::TENSOR_QUANT16_SYMM ||
686 operandType == V1_3::OperandType::TENSOR_QUANT8_ASYMM_SIGNED)
687 {
688 return true;
689 }
690 else
691 {
692 return false;
693 }
694}
695#endif
696
Jim Flynn829ad302019-12-13 14:43:24 +0000697std::string GetFileTimestamp()
698{
699 // used to get a timestamp to name diagnostic files (the ArmNN serialized graph
700 // and getSupportedOperations.txt files)
701 timespec ts;
702 int iRet = clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
703 std::stringstream ss;
704 if (iRet == 0)
705 {
706 ss << std::to_string(ts.tv_sec) << "_" << std::to_string(ts.tv_nsec);
707 }
708 else
709 {
710 ALOGW("clock_gettime failed with errno %s : %s", std::to_string(errno).c_str(), std::strerror(errno));
711 }
712 return ss.str();
713}
714
Sadik Armaganb3021432021-01-13 15:56:51 +0000715void RenameExportedFiles(const std::string& existingSerializedFileName,
716 const std::string& existingDotFileName,
717 const std::string& dumpDir,
718 const armnn::NetworkId networkId)
Jim Flynn829ad302019-12-13 14:43:24 +0000719{
720 if (dumpDir.empty())
721 {
722 return;
723 }
Sadik Armaganb3021432021-01-13 15:56:51 +0000724 RenameFile(existingSerializedFileName, std::string("_network.armnn"), dumpDir, networkId);
725 RenameFile(existingDotFileName, std::string("_networkgraph.dot"), dumpDir, networkId);
726}
727
728void RenameFile(const std::string& existingName,
729 const std::string& extension,
730 const std::string& dumpDir,
731 const armnn::NetworkId networkId)
732{
733 if (existingName.empty() || dumpDir.empty())
Jim Flynn829ad302019-12-13 14:43:24 +0000734 {
735 return;
736 }
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100737
Sadik Armaganb3021432021-01-13 15:56:51 +0000738 fs::path dumpPath = dumpDir;
739 const fs::path newFileName = dumpPath / (std::to_string(networkId) + extension);
740 int iRet = rename(existingName.c_str(), newFileName.c_str());
Jim Flynn829ad302019-12-13 14:43:24 +0000741 if (iRet != 0)
742 {
743 std::stringstream ss;
Sadik Armaganb3021432021-01-13 15:56:51 +0000744 ss << "rename of [" << existingName << "] to [" << newFileName << "] failed with errno "
745 << std::to_string(errno) << " : " << std::strerror(errno);
Jim Flynn829ad302019-12-13 14:43:24 +0000746 ALOGW(ss.str().c_str());
747 }
748}
749
Kevin May42477c12020-03-26 13:34:14 +0000750void CommitPools(std::vector<::android::nn::RunTimePoolInfo>& memPools)
751{
752 if (memPools.empty())
753 {
754 return;
755 }
756 // Commit output buffers.
757 // Note that we update *all* pools, even if they aren't actually used as outputs -
758 // this is simpler and is what the CpuExecutor does.
759 for (auto& pool : memPools)
760 {
761 // Type android::nn::RunTimePoolInfo has changed between Android P & Q and Android R, where
762 // update() has been removed and flush() added.
Sadik Armagan188675f2021-02-12 17:16:42 +0000763#if defined(ARMNN_ANDROID_R) || defined(ARMNN_ANDROID_S) // Use the new Android implementation.
Kevin May42477c12020-03-26 13:34:14 +0000764 pool.flush();
765#else
766 pool.update();
767#endif
768 }
769}
telsoa015307bc12018-03-09 13:51:08 +0000770} // namespace armnn_driver