blob: 930c2b241296afd09e76c4eed3030ff40c5bb075 [file] [log] [blame]
telsoa015307bc12018-03-09 13:51:08 +00001//
2// Copyright © 2017 Arm Ltd. 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>
Matteo Martincigh00d6ed12019-11-28 17:13:24 +000012#include <armnnUtils/Permute.hpp>
13
Derek Lambertid00ad912020-01-22 15:55:16 +000014#include <armnn/Utils.hpp>
Narumol Prangnawarat4d07e5e2020-04-06 16:46:21 +010015#include <armnn/utility/Assert.hpp>
Colm Donelan08d9a1c2020-09-09 17:56:55 +010016#include <Filesystem.hpp>
17#include <log/log.h>
Derek Lambertid00ad912020-01-22 15:55:16 +000018
telsoa015307bc12018-03-09 13:51:08 +000019#include <cassert>
Jim Flynn829ad302019-12-13 14:43:24 +000020#include <cerrno>
telsoa015307bc12018-03-09 13:51:08 +000021#include <cinttypes>
Jim Flynn829ad302019-12-13 14:43:24 +000022#include <sstream>
23#include <cstdio>
24#include <time.h>
25
telsoa015307bc12018-03-09 13:51:08 +000026using namespace android;
telsoa01ce3e84a2018-08-31 09:31:35 +010027using namespace android::hardware;
telsoa015307bc12018-03-09 13:51:08 +000028using namespace android::hidl::memory::V1_0;
29
30namespace armnn_driver
31{
32const armnn::PermutationVector g_DontPermute{};
33
34namespace
35{
36
telsoa015307bc12018-03-09 13:51:08 +000037void SwizzleAndroidNn4dTensorToArmNn(const armnn::TensorShape& inTensorShape, const void* input,
Matteo Martincighbf19d2a2019-11-29 11:46:50 +000038 void* output, size_t dataTypeSize, const armnn::PermutationVector& mappings)
telsoa015307bc12018-03-09 13:51:08 +000039{
Matteo Martincighbf19d2a2019-11-29 11:46:50 +000040 assert(inTensorShape.GetNumDimensions() == 4U);
telsoa015307bc12018-03-09 13:51:08 +000041
Matteo Martincighbf19d2a2019-11-29 11:46:50 +000042 armnnUtils::Permute(armnnUtils::Permuted(inTensorShape, mappings), mappings, input, output, dataTypeSize);
telsoa015307bc12018-03-09 13:51:08 +000043}
44
45} // anonymous namespace
46
47void SwizzleAndroidNn4dTensorToArmNn(const armnn::TensorInfo& tensor, const void* input, void* output,
48 const armnn::PermutationVector& mappings)
49{
50 assert(tensor.GetNumDimensions() == 4U);
51
Matteo Martincighbf19d2a2019-11-29 11:46:50 +000052 armnn::DataType dataType = tensor.GetDataType();
53 switch (dataType)
telsoa015307bc12018-03-09 13:51:08 +000054 {
Mike Kelly3c673942019-07-25 09:26:06 +010055 case armnn::DataType::Float16:
telsoa015307bc12018-03-09 13:51:08 +000056 case armnn::DataType::Float32:
Derek Lamberti1a38cda2020-01-10 17:28:20 +000057 case armnn::DataType::QAsymmU8:
Derek Lambertid00ad912020-01-22 15:55:16 +000058 case armnn::DataType::QSymmS8:
Sadik Armagan1153d1e2020-04-01 15:09:39 +010059 case armnn::DataType::QAsymmS8:
Matteo Martincighbf19d2a2019-11-29 11:46:50 +000060 SwizzleAndroidNn4dTensorToArmNn(tensor.GetShape(), input, output, armnn::GetDataTypeSize(dataType), mappings);
Aron Virginas-Tar9f0693b2019-11-06 14:32:30 +000061 break;
telsoa015307bc12018-03-09 13:51:08 +000062 default:
63 ALOGW("Unknown armnn::DataType for swizzling");
64 assert(0);
65 }
66}
67
Sadik Armagan188675f2021-02-12 17:16:42 +000068void* GetMemoryFromPool(V1_0::DataLocation location, const std::vector<android::nn::RunTimePoolInfo>& memPools)
telsoa015307bc12018-03-09 13:51:08 +000069{
70 // find the location within the pool
71 assert(location.poolIndex < memPools.size());
72
surmeh01deb3bdb2018-07-05 12:06:04 +010073 const android::nn::RunTimePoolInfo& memPool = memPools[location.poolIndex];
74
surmeh01deb3bdb2018-07-05 12:06:04 +010075 uint8_t* memPoolBuffer = memPool.getBuffer();
surmeh01deb3bdb2018-07-05 12:06:04 +010076
77 uint8_t* memory = memPoolBuffer + location.offset;
telsoa015307bc12018-03-09 13:51:08 +000078
79 return memory;
80}
81
Matthew Bentham912b3622019-05-03 15:49:14 +010082armnn::TensorInfo GetTensorInfoForOperand(const V1_0::Operand& operand)
telsoa015307bc12018-03-09 13:51:08 +000083{
Finn Williamsa4983ce2020-07-23 12:55:12 +010084 using namespace armnn;
85 DataType type;
telsoa015307bc12018-03-09 13:51:08 +000086
87 switch (operand.type)
88 {
Matthew Bentham912b3622019-05-03 15:49:14 +010089 case V1_0::OperandType::TENSOR_FLOAT32:
telsoa015307bc12018-03-09 13:51:08 +000090 type = armnn::DataType::Float32;
91 break;
Matthew Bentham912b3622019-05-03 15:49:14 +010092 case V1_0::OperandType::TENSOR_QUANT8_ASYMM:
Derek Lamberti1a38cda2020-01-10 17:28:20 +000093 type = armnn::DataType::QAsymmU8;
telsoa015307bc12018-03-09 13:51:08 +000094 break;
Matthew Bentham912b3622019-05-03 15:49:14 +010095 case V1_0::OperandType::TENSOR_INT32:
telsoa015307bc12018-03-09 13:51:08 +000096 type = armnn::DataType::Signed32;
97 break;
98 default:
Mike Kellyb5fdf382019-06-11 16:35:25 +010099 throw UnsupportedOperand<V1_0::OperandType>(operand.type);
telsoa015307bc12018-03-09 13:51:08 +0000100 }
101
Finn Williamsa4983ce2020-07-23 12:55:12 +0100102 TensorInfo ret;
103 if (operand.dimensions.size() == 0)
104 {
105 TensorShape tensorShape(Dimensionality::NotSpecified);
106 ret = TensorInfo(tensorShape, type);
107 }
108 else
109 {
110 bool dimensionsSpecificity[5] = { true, true, true, true, true };
111 int count = 0;
112 std::for_each(operand.dimensions.data(),
113 operand.dimensions.data() + operand.dimensions.size(),
114 [&](const unsigned int val)
115 {
116 if (val == 0)
117 {
118 dimensionsSpecificity[count] = false;
119 }
120 count++;
121 });
122
123 TensorShape tensorShape(operand.dimensions.size(), operand.dimensions.data(), dimensionsSpecificity);
124 ret = TensorInfo(tensorShape, type);
125 }
telsoa015307bc12018-03-09 13:51:08 +0000126
127 ret.SetQuantizationScale(operand.scale);
128 ret.SetQuantizationOffset(operand.zeroPoint);
129
130 return ret;
131}
132
Kevin May42477c12020-03-26 13:34:14 +0000133#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 +0100134
135armnn::TensorInfo GetTensorInfoForOperand(const V1_2::Operand& operand)
136{
Aron Virginas-Tar9f0693b2019-11-06 14:32:30 +0000137 using namespace armnn;
Derek Lambertid00ad912020-01-22 15:55:16 +0000138 bool perChannel = false;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100139
Aron Virginas-Tar9f0693b2019-11-06 14:32:30 +0000140 DataType type;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100141 switch (operand.type)
142 {
Sadik Armagan793a70c2020-03-19 13:54:04 +0000143 case V1_2::OperandType::TENSOR_BOOL8:
144 type = armnn::DataType::Boolean;
145 break;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100146 case V1_2::OperandType::TENSOR_FLOAT32:
147 type = armnn::DataType::Float32;
148 break;
Mike Kelly3c673942019-07-25 09:26:06 +0100149 case V1_2::OperandType::TENSOR_FLOAT16:
150 type = armnn::DataType::Float16;
151 break;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100152 case V1_2::OperandType::TENSOR_QUANT8_ASYMM:
Derek Lamberti1a38cda2020-01-10 17:28:20 +0000153 type = armnn::DataType::QAsymmU8;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100154 break;
Derek Lambertid00ad912020-01-22 15:55:16 +0000155 case V1_2::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
156 perChannel=true;
157 ARMNN_FALLTHROUGH;
Mike Kelly0e2e31b2019-11-19 09:16:00 +0000158 case V1_2::OperandType::TENSOR_QUANT8_SYMM:
FinnWilliamsArm624fe9f2019-12-06 17:12:42 +0000159 type = armnn::DataType::QSymmS8;
Mike Kelly0e2e31b2019-11-19 09:16:00 +0000160 break;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100161 case V1_2::OperandType::TENSOR_QUANT16_SYMM:
Derek Lamberti1a38cda2020-01-10 17:28:20 +0000162 type = armnn::DataType::QSymmS16;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100163 break;
164 case V1_2::OperandType::TENSOR_INT32:
165 type = armnn::DataType::Signed32;
166 break;
167 default:
168 throw UnsupportedOperand<V1_2::OperandType>(operand.type);
169 }
170
Finn Williamsa4983ce2020-07-23 12:55:12 +0100171 TensorInfo ret;
172 if (operand.dimensions.size() == 0)
173 {
174 TensorShape tensorShape(Dimensionality::NotSpecified);
175 ret = TensorInfo(tensorShape, type);
176 }
177 else
178 {
179 bool dimensionsSpecificity[5] = { true, true, true, true, true };
180 int count = 0;
181 std::for_each(operand.dimensions.data(),
182 operand.dimensions.data() + operand.dimensions.size(),
183 [&](const unsigned int val)
184 {
185 if (val == 0)
186 {
187 dimensionsSpecificity[count] = false;
188 }
189 count++;
190 });
191
192 TensorShape tensorShape(operand.dimensions.size(), operand.dimensions.data(), dimensionsSpecificity);
193 ret = TensorInfo(tensorShape, type);
194 }
195
Derek Lambertid00ad912020-01-22 15:55:16 +0000196 if (perChannel)
Aron Virginas-Tar9f0693b2019-11-06 14:32:30 +0000197 {
198 // ExtraParams is expected to be of type channelQuant
Narumol Prangnawarat4d07e5e2020-04-06 16:46:21 +0100199 ARMNN_ASSERT(operand.extraParams.getDiscriminator() ==
Aron Virginas-Tar9f0693b2019-11-06 14:32:30 +0000200 V1_2::Operand::ExtraParams::hidl_discriminator::channelQuant);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100201
Aron Virginas-Tar9f0693b2019-11-06 14:32:30 +0000202 auto perAxisQuantParams = operand.extraParams.channelQuant();
203
204 ret.SetQuantizationScales(perAxisQuantParams.scales);
205 ret.SetQuantizationDim(MakeOptional<unsigned int>(perAxisQuantParams.channelDim));
206 }
207 else
208 {
209 ret.SetQuantizationScale(operand.scale);
210 ret.SetQuantizationOffset(operand.zeroPoint);
211 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100212
213 return ret;
214}
215
216#endif
217
Kevin May42477c12020-03-26 13:34:14 +0000218#ifdef ARMNN_ANDROID_NN_V1_3 // Using ::android::hardware::neuralnetworks::V1_3
219
220armnn::TensorInfo GetTensorInfoForOperand(const V1_3::Operand& operand)
221{
222 using namespace armnn;
223 bool perChannel = false;
Teresa Charlin896572b2020-07-15 12:37:51 +0100224 bool isScalar = false;
Kevin May42477c12020-03-26 13:34:14 +0000225
226 DataType type;
227 switch (operand.type)
228 {
Sadik Armagan51ba2c62020-03-31 15:36:25 +0100229 case V1_3::OperandType::TENSOR_BOOL8:
230 type = armnn::DataType::Boolean;
231 break;
Kevin May42477c12020-03-26 13:34:14 +0000232 case V1_3::OperandType::TENSOR_FLOAT32:
233 type = armnn::DataType::Float32;
234 break;
235 case V1_3::OperandType::TENSOR_FLOAT16:
236 type = armnn::DataType::Float16;
237 break;
238 case V1_3::OperandType::TENSOR_QUANT8_ASYMM:
239 type = armnn::DataType::QAsymmU8;
240 break;
241 case V1_3::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
242 perChannel=true;
243 ARMNN_FALLTHROUGH;
244 case V1_3::OperandType::TENSOR_QUANT8_SYMM:
245 type = armnn::DataType::QSymmS8;
246 break;
247 case V1_3::OperandType::TENSOR_QUANT16_SYMM:
248 type = armnn::DataType::QSymmS16;
249 break;
250 case V1_3::OperandType::TENSOR_INT32:
251 type = armnn::DataType::Signed32;
252 break;
Finn Williamsfc884b42020-06-11 17:35:44 +0100253 case V1_3::OperandType::INT32:
254 type = armnn::DataType::Signed32;
Teresa Charlin896572b2020-07-15 12:37:51 +0100255 isScalar = true;
Finn Williamsfc884b42020-06-11 17:35:44 +0100256 break;
Kevin May42477c12020-03-26 13:34:14 +0000257 case V1_3::OperandType::TENSOR_QUANT8_ASYMM_SIGNED:
258 type = armnn::DataType::QAsymmS8;
259 break;
260 default:
261 throw UnsupportedOperand<V1_3::OperandType>(operand.type);
262 }
263
Finn Williamsfc884b42020-06-11 17:35:44 +0100264 TensorInfo ret;
Teresa Charlin896572b2020-07-15 12:37:51 +0100265 if (isScalar)
Finn Williamsfc884b42020-06-11 17:35:44 +0100266 {
Teresa Charlin896572b2020-07-15 12:37:51 +0100267 ret = TensorInfo(TensorShape(armnn::Dimensionality::Scalar), type);
Finn Williamsfc884b42020-06-11 17:35:44 +0100268 }
269 else
270 {
Finn Williamsa4983ce2020-07-23 12:55:12 +0100271 if (operand.dimensions.size() == 0)
272 {
273 TensorShape tensorShape(Dimensionality::NotSpecified);
274 ret = TensorInfo(tensorShape, type);
275 }
276 else
277 {
278 bool dimensionsSpecificity[5] = { true, true, true, true, true };
279 int count = 0;
280 std::for_each(operand.dimensions.data(),
281 operand.dimensions.data() + operand.dimensions.size(),
282 [&](const unsigned int val)
283 {
284 if (val == 0)
285 {
286 dimensionsSpecificity[count] = false;
287 }
288 count++;
289 });
290
291 TensorShape tensorShape(operand.dimensions.size(), operand.dimensions.data(), dimensionsSpecificity);
292 ret = TensorInfo(tensorShape, type);
293 }
Finn Williamsfc884b42020-06-11 17:35:44 +0100294 }
295
Kevin May42477c12020-03-26 13:34:14 +0000296 if (perChannel)
297 {
298 // ExtraParams is expected to be of type channelQuant
Narumol Prangnawarat4d07e5e2020-04-06 16:46:21 +0100299 ARMNN_ASSERT(operand.extraParams.getDiscriminator() ==
Kevin May352d8382020-03-31 15:03:42 +0100300 V1_2::Operand::ExtraParams::hidl_discriminator::channelQuant);
Kevin May42477c12020-03-26 13:34:14 +0000301
302 auto perAxisQuantParams = operand.extraParams.channelQuant();
303
304 ret.SetQuantizationScales(perAxisQuantParams.scales);
305 ret.SetQuantizationDim(MakeOptional<unsigned int>(perAxisQuantParams.channelDim));
306 }
307 else
308 {
309 ret.SetQuantizationScale(operand.scale);
310 ret.SetQuantizationOffset(operand.zeroPoint);
311 }
Kevin May42477c12020-03-26 13:34:14 +0000312 return ret;
313}
314
315#endif
316
Matthew Bentham912b3622019-05-03 15:49:14 +0100317std::string GetOperandSummary(const V1_0::Operand& operand)
telsoa015307bc12018-03-09 13:51:08 +0000318{
319 return android::hardware::details::arrayToString(operand.dimensions, operand.dimensions.size()) + " " +
320 toString(operand.type);
321}
322
Kevin May42477c12020-03-26 13:34:14 +0000323#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 +0100324
325std::string GetOperandSummary(const V1_2::Operand& operand)
326{
327 return android::hardware::details::arrayToString(operand.dimensions, operand.dimensions.size()) + " " +
328 toString(operand.type);
329}
330
331#endif
332
Kevin May42477c12020-03-26 13:34:14 +0000333#ifdef ARMNN_ANDROID_NN_V1_3 // Using ::android::hardware::neuralnetworks::V1_3
334
335std::string GetOperandSummary(const V1_3::Operand& operand)
336{
337 return android::hardware::details::arrayToString(operand.dimensions, operand.dimensions.size()) + " " +
338 toString(operand.type);
339}
340
341#endif
342
telsoa015307bc12018-03-09 13:51:08 +0000343using DumpElementFunction = void (*)(const armnn::ConstTensor& tensor,
344 unsigned int elementIndex,
345 std::ofstream& fileStream);
346
347namespace
348{
349template <typename ElementType, typename PrintableType = ElementType>
350void DumpTensorElement(const armnn::ConstTensor& tensor, unsigned int elementIndex, std::ofstream& fileStream)
351{
352 const ElementType* elements = reinterpret_cast<const ElementType*>(tensor.GetMemoryArea());
353 fileStream << static_cast<PrintableType>(elements[elementIndex]) << ",";
354}
355
356constexpr const char* MemoryLayoutString(const armnn::ConstTensor& tensor)
357{
358 const char* str = "";
359
360 switch (tensor.GetNumDimensions())
361 {
362 case 4: { str = "(BHWC) "; break; }
363 case 3: { str = "(HWC) "; break; }
364 case 2: { str = "(HW) "; break; }
365 default: { str = ""; break; }
366 }
367
368 return str;
369}
370} // namespace
371
372void DumpTensor(const std::string& dumpDir,
373 const std::string& requestName,
374 const std::string& tensorName,
375 const armnn::ConstTensor& tensor)
376{
377 // The dump directory must exist in advance.
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100378 fs::path dumpPath = dumpDir;
379 const fs::path fileName = dumpPath / (requestName + "_" + tensorName + ".dump");
telsoa015307bc12018-03-09 13:51:08 +0000380
381 std::ofstream fileStream;
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100382 fileStream.open(fileName.c_str(), std::ofstream::out | std::ofstream::trunc);
telsoa015307bc12018-03-09 13:51:08 +0000383
384 if (!fileStream.good())
385 {
386 ALOGW("Could not open file %s for writing", fileName.c_str());
387 return;
388 }
389
390 DumpElementFunction dumpElementFunction = nullptr;
391
392 switch (tensor.GetDataType())
393 {
394 case armnn::DataType::Float32:
395 {
396 dumpElementFunction = &DumpTensorElement<float>;
397 break;
398 }
Derek Lamberti1a38cda2020-01-10 17:28:20 +0000399 case armnn::DataType::QAsymmU8:
telsoa015307bc12018-03-09 13:51:08 +0000400 {
401 dumpElementFunction = &DumpTensorElement<uint8_t, uint32_t>;
402 break;
403 }
404 case armnn::DataType::Signed32:
405 {
406 dumpElementFunction = &DumpTensorElement<int32_t>;
407 break;
408 }
Jim Flynnf2e175c2019-12-12 15:11:30 +0000409 case armnn::DataType::Float16:
410 {
411 dumpElementFunction = &DumpTensorElement<armnn::Half>;
412 break;
413 }
Teresa Charlinb248ec12020-04-30 11:06:34 +0100414 case armnn::DataType::QAsymmS8:
415 {
416 dumpElementFunction = &DumpTensorElement<int8_t, int32_t>;
417 break;
418 }
419 case armnn::DataType::Boolean:
420 {
421 dumpElementFunction = &DumpTensorElement<bool>;
422 break;
423 }
telsoa015307bc12018-03-09 13:51:08 +0000424 default:
425 {
426 dumpElementFunction = nullptr;
427 }
428 }
429
430 if (dumpElementFunction != nullptr)
431 {
432 const unsigned int numDimensions = tensor.GetNumDimensions();
433
434 const unsigned int batch = (numDimensions == 4) ? tensor.GetShape()[numDimensions - 4] : 1;
435
436 const unsigned int height = (numDimensions >= 3)
437 ? tensor.GetShape()[numDimensions - 3]
438 : (numDimensions >= 2) ? tensor.GetShape()[numDimensions - 2] : 1;
439
440 const unsigned int width = (numDimensions >= 3)
441 ? tensor.GetShape()[numDimensions - 2]
442 : (numDimensions >= 1) ? tensor.GetShape()[numDimensions - 1] : 0;
443
444 const unsigned int channels = (numDimensions >= 3) ? tensor.GetShape()[numDimensions - 1] : 1;
445
446 fileStream << "# Number of elements " << tensor.GetNumElements() << std::endl;
447 fileStream << "# Dimensions " << MemoryLayoutString(tensor);
448 fileStream << "[" << tensor.GetShape()[0];
449 for (unsigned int d = 1; d < numDimensions; d++)
450 {
451 fileStream << "," << tensor.GetShape()[d];
452 }
453 fileStream << "]" << std::endl;
454
455 for (unsigned int e = 0, b = 0; b < batch; ++b)
456 {
457 if (numDimensions >= 4)
458 {
459 fileStream << "# Batch " << b << std::endl;
460 }
461 for (unsigned int c = 0; c < channels; c++)
462 {
463 if (numDimensions >= 3)
464 {
465 fileStream << "# Channel " << c << std::endl;
466 }
467 for (unsigned int h = 0; h < height; h++)
468 {
469 for (unsigned int w = 0; w < width; w++, e += channels)
470 {
471 (*dumpElementFunction)(tensor, e, fileStream);
472 }
473 fileStream << std::endl;
474 }
475 e -= channels - 1;
476 if (c < channels)
477 {
478 e -= ((height * width) - 1) * channels;
479 }
480 }
481 fileStream << std::endl;
482 }
483 fileStream << std::endl;
484 }
485 else
486 {
487 fileStream << "Cannot dump tensor elements: Unsupported data type "
488 << static_cast<unsigned int>(tensor.GetDataType()) << std::endl;
489 }
490
491 if (!fileStream.good())
492 {
493 ALOGW("An error occurred when writing to file %s", fileName.c_str());
494 }
495}
496
telsoa01ce3e84a2018-08-31 09:31:35 +0100497void DumpJsonProfilingIfRequired(bool gpuProfilingEnabled,
498 const std::string& dumpDir,
499 armnn::NetworkId networkId,
500 const armnn::IProfiler* profiler)
501{
502 // Check if profiling is required.
503 if (!gpuProfilingEnabled)
504 {
505 return;
506 }
507
508 // The dump directory must exist in advance.
509 if (dumpDir.empty())
510 {
511 return;
512 }
513
Narumol Prangnawarat4d07e5e2020-04-06 16:46:21 +0100514 ARMNN_ASSERT(profiler);
telsoa01ce3e84a2018-08-31 09:31:35 +0100515
516 // Set the name of the output profiling file.
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100517 fs::path dumpPath = dumpDir;
518 const fs::path fileName = dumpPath / (std::to_string(networkId) + "_profiling.json");
telsoa01ce3e84a2018-08-31 09:31:35 +0100519
520 // Open the ouput file for writing.
521 std::ofstream fileStream;
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100522 fileStream.open(fileName.c_str(), std::ofstream::out | std::ofstream::trunc);
telsoa01ce3e84a2018-08-31 09:31:35 +0100523
524 if (!fileStream.good())
525 {
526 ALOGW("Could not open file %s for writing", fileName.c_str());
527 return;
528 }
529
530 // Write the profiling info to a JSON file.
531 profiler->Print(fileStream);
532}
533
Jim Flynn829ad302019-12-13 14:43:24 +0000534std::string ExportNetworkGraphToDotFile(const armnn::IOptimizedNetwork& optimizedNetwork,
535 const std::string& dumpDir)
536{
537 std::string fileName;
538 // The dump directory must exist in advance.
539 if (dumpDir.empty())
540 {
541 return fileName;
542 }
543
544 std::string timestamp = GetFileTimestamp();
545 if (timestamp.empty())
546 {
547 return fileName;
548 }
549
550 // Set the name of the output .dot file.
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100551 fs::path dumpPath = dumpDir;
552 fs::path tempFilePath = dumpPath / (timestamp + "_networkgraph.dot");
553 fileName = tempFilePath.string();
Jim Flynn829ad302019-12-13 14:43:24 +0000554
555 ALOGV("Exporting the optimized network graph to file: %s", fileName.c_str());
556
557 // Write the network graph to a dot file.
558 std::ofstream fileStream;
559 fileStream.open(fileName, std::ofstream::out | std::ofstream::trunc);
560
561 if (!fileStream.good())
562 {
563 ALOGW("Could not open file %s for writing", fileName.c_str());
564 return fileName;
565 }
566
567 if (optimizedNetwork.SerializeToDot(fileStream) != armnn::Status::Success)
568 {
569 ALOGW("An error occurred when writing to file %s", fileName.c_str());
570 }
571 return fileName;
572}
573
Sadik Armaganb3021432021-01-13 15:56:51 +0000574std::string SerializeNetwork(const armnn::INetwork& network, const std::string& dumpDir)
575{
576 std::string fileName;
577 // The dump directory must exist in advance.
578 if (dumpDir.empty())
579 {
580 return fileName;
581 }
582
583 std::string timestamp = GetFileTimestamp();
584 if (timestamp.empty())
585 {
586 return fileName;
587 }
588
589 auto serializer(armnnSerializer::ISerializer::Create());
590
591 // Serialize the Network
592 serializer->Serialize(network);
593
594 // Set the name of the output .armnn file.
595 fs::path dumpPath = dumpDir;
596 fs::path tempFilePath = dumpPath / (timestamp + "_network.armnn");
597 fileName = tempFilePath.string();
598
599 // Save serialized network to a file
600 std::ofstream serializedFile(fileName, std::ios::out | std::ios::binary);
601 bool serialized = serializer->SaveSerializedToStream(serializedFile);
602 if (!serialized)
603 {
604 ALOGW("An error occurred when serializing to file %s", fileName.c_str());
605 }
606 return fileName;
607}
608
Finn Williamsa4983ce2020-07-23 12:55:12 +0100609bool IsDynamicTensor(const armnn::TensorInfo& tensorInfo)
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100610{
Finn Williamsa4983ce2020-07-23 12:55:12 +0100611 if (tensorInfo.GetShape().GetDimensionality() == armnn::Dimensionality::NotSpecified)
612 {
613 return true;
614 }
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100615 // Account for the usage of the TensorShape empty constructor
616 if (tensorInfo.GetNumDimensions() == 0)
617 {
618 return true;
619 }
Finn Williamsa4983ce2020-07-23 12:55:12 +0100620 return !tensorInfo.GetShape().AreAllDimensionsSpecified();
621}
622
623bool AreDynamicTensorsSupported()
624{
625#if defined(ARMNN_ANDROID_NN_V1_3)
626 return true;
627#else
628 return false;
629#endif
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100630}
631
Jim Flynn829ad302019-12-13 14:43:24 +0000632std::string GetFileTimestamp()
633{
634 // used to get a timestamp to name diagnostic files (the ArmNN serialized graph
635 // and getSupportedOperations.txt files)
636 timespec ts;
637 int iRet = clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
638 std::stringstream ss;
639 if (iRet == 0)
640 {
641 ss << std::to_string(ts.tv_sec) << "_" << std::to_string(ts.tv_nsec);
642 }
643 else
644 {
645 ALOGW("clock_gettime failed with errno %s : %s", std::to_string(errno).c_str(), std::strerror(errno));
646 }
647 return ss.str();
648}
649
Sadik Armaganb3021432021-01-13 15:56:51 +0000650void RenameExportedFiles(const std::string& existingSerializedFileName,
651 const std::string& existingDotFileName,
652 const std::string& dumpDir,
653 const armnn::NetworkId networkId)
Jim Flynn829ad302019-12-13 14:43:24 +0000654{
655 if (dumpDir.empty())
656 {
657 return;
658 }
Sadik Armaganb3021432021-01-13 15:56:51 +0000659 RenameFile(existingSerializedFileName, std::string("_network.armnn"), dumpDir, networkId);
660 RenameFile(existingDotFileName, std::string("_networkgraph.dot"), dumpDir, networkId);
661}
662
663void RenameFile(const std::string& existingName,
664 const std::string& extension,
665 const std::string& dumpDir,
666 const armnn::NetworkId networkId)
667{
668 if (existingName.empty() || dumpDir.empty())
Jim Flynn829ad302019-12-13 14:43:24 +0000669 {
670 return;
671 }
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100672
Sadik Armaganb3021432021-01-13 15:56:51 +0000673 fs::path dumpPath = dumpDir;
674 const fs::path newFileName = dumpPath / (std::to_string(networkId) + extension);
675 int iRet = rename(existingName.c_str(), newFileName.c_str());
Jim Flynn829ad302019-12-13 14:43:24 +0000676 if (iRet != 0)
677 {
678 std::stringstream ss;
Sadik Armaganb3021432021-01-13 15:56:51 +0000679 ss << "rename of [" << existingName << "] to [" << newFileName << "] failed with errno "
680 << std::to_string(errno) << " : " << std::strerror(errno);
Jim Flynn829ad302019-12-13 14:43:24 +0000681 ALOGW(ss.str().c_str());
682 }
683}
684
Kevin May42477c12020-03-26 13:34:14 +0000685void CommitPools(std::vector<::android::nn::RunTimePoolInfo>& memPools)
686{
687 if (memPools.empty())
688 {
689 return;
690 }
691 // Commit output buffers.
692 // Note that we update *all* pools, even if they aren't actually used as outputs -
693 // this is simpler and is what the CpuExecutor does.
694 for (auto& pool : memPools)
695 {
696 // Type android::nn::RunTimePoolInfo has changed between Android P & Q and Android R, where
697 // update() has been removed and flush() added.
Sadik Armagan188675f2021-02-12 17:16:42 +0000698#if defined(ARMNN_ANDROID_R) || defined(ARMNN_ANDROID_S) // Use the new Android implementation.
Kevin May42477c12020-03-26 13:34:14 +0000699 pool.flush();
700#else
701 pool.update();
702#endif
703 }
704}
telsoa015307bc12018-03-09 13:51:08 +0000705} // namespace armnn_driver