blob: 1517b2a7ead51c1ffb8c857e8a9e7bf355fdc807 [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
Matteo Martincigh00d6ed12019-11-28 17:13:24 +000011#include <armnnUtils/Permute.hpp>
12
Derek Lambertid00ad912020-01-22 15:55:16 +000013#include <armnn/Utils.hpp>
Narumol Prangnawarat4d07e5e2020-04-06 16:46:21 +010014#include <armnn/utility/Assert.hpp>
Colm Donelan08d9a1c2020-09-09 17:56:55 +010015#include <Filesystem.hpp>
16#include <log/log.h>
Derek Lambertid00ad912020-01-22 15:55:16 +000017
telsoa015307bc12018-03-09 13:51:08 +000018#include <cassert>
Jim Flynn829ad302019-12-13 14:43:24 +000019#include <cerrno>
telsoa015307bc12018-03-09 13:51:08 +000020#include <cinttypes>
Jim Flynn829ad302019-12-13 14:43:24 +000021#include <sstream>
22#include <cstdio>
23#include <time.h>
Guus Sliepen39a90142023-06-27 15:20:19 +000024#include <string>
Jim Flynn829ad302019-12-13 14:43:24 +000025
26
telsoa015307bc12018-03-09 13:51:08 +000027
28using namespace android;
telsoa01ce3e84a2018-08-31 09:31:35 +010029using namespace android::hardware;
telsoa015307bc12018-03-09 13:51:08 +000030using namespace android::hidl::memory::V1_0;
31
32namespace armnn_driver
33{
34const armnn::PermutationVector g_DontPermute{};
35
36namespace
37{
38
telsoa015307bc12018-03-09 13:51:08 +000039void SwizzleAndroidNn4dTensorToArmNn(const armnn::TensorShape& inTensorShape, const void* input,
Matteo Martincighbf19d2a2019-11-29 11:46:50 +000040 void* output, size_t dataTypeSize, const armnn::PermutationVector& mappings)
telsoa015307bc12018-03-09 13:51:08 +000041{
Matteo Martincighbf19d2a2019-11-29 11:46:50 +000042 assert(inTensorShape.GetNumDimensions() == 4U);
telsoa015307bc12018-03-09 13:51:08 +000043
Matteo Martincighbf19d2a2019-11-29 11:46:50 +000044 armnnUtils::Permute(armnnUtils::Permuted(inTensorShape, mappings), mappings, input, output, dataTypeSize);
telsoa015307bc12018-03-09 13:51:08 +000045}
46
Guus Sliepen39a90142023-06-27 15:20:19 +000047template<typename Dimensions>
48auto GetDimensionsSpecificity(const Dimensions& dimensions)
49{
50 // We can't use std::vector<bool> since that is a specialization that packs
51 // bits, so use a string of bools instead. This also has the benefit of
52 // using small string optimization.
53 std::basic_string<bool> specificity(dimensions.size(), false);
54
55 for (std::size_t i = 0; i < dimensions.size(); ++i)
56 {
57 specificity[i] = dimensions.data()[i] != 0;
58 }
59
60 return specificity;
61}
62
telsoa015307bc12018-03-09 13:51:08 +000063} // anonymous namespace
64
65void SwizzleAndroidNn4dTensorToArmNn(const armnn::TensorInfo& tensor, const void* input, void* output,
66 const armnn::PermutationVector& mappings)
67{
68 assert(tensor.GetNumDimensions() == 4U);
69
Matteo Martincighbf19d2a2019-11-29 11:46:50 +000070 armnn::DataType dataType = tensor.GetDataType();
71 switch (dataType)
telsoa015307bc12018-03-09 13:51:08 +000072 {
Mike Kelly3c673942019-07-25 09:26:06 +010073 case armnn::DataType::Float16:
telsoa015307bc12018-03-09 13:51:08 +000074 case armnn::DataType::Float32:
Derek Lamberti1a38cda2020-01-10 17:28:20 +000075 case armnn::DataType::QAsymmU8:
Derek Lambertid00ad912020-01-22 15:55:16 +000076 case armnn::DataType::QSymmS8:
Sadik Armagan1153d1e2020-04-01 15:09:39 +010077 case armnn::DataType::QAsymmS8:
Matteo Martincighbf19d2a2019-11-29 11:46:50 +000078 SwizzleAndroidNn4dTensorToArmNn(tensor.GetShape(), input, output, armnn::GetDataTypeSize(dataType), mappings);
Aron Virginas-Tar9f0693b2019-11-06 14:32:30 +000079 break;
telsoa015307bc12018-03-09 13:51:08 +000080 default:
81 ALOGW("Unknown armnn::DataType for swizzling");
82 assert(0);
83 }
84}
Kevin DuBois30c34ae2020-08-26 13:53:41 -070085void* GetMemoryFromPool(V1_0::DataLocation location, const std::vector<android::nn::RunTimePoolInfo>& memPools)
telsoa015307bc12018-03-09 13:51:08 +000086{
87 // find the location within the pool
88 assert(location.poolIndex < memPools.size());
89
surmeh01deb3bdb2018-07-05 12:06:04 +010090 const android::nn::RunTimePoolInfo& memPool = memPools[location.poolIndex];
91
surmeh01deb3bdb2018-07-05 12:06:04 +010092 uint8_t* memPoolBuffer = memPool.getBuffer();
surmeh01deb3bdb2018-07-05 12:06:04 +010093
94 uint8_t* memory = memPoolBuffer + location.offset;
telsoa015307bc12018-03-09 13:51:08 +000095
96 return memory;
97}
98
Matthew Bentham912b3622019-05-03 15:49:14 +010099armnn::TensorInfo GetTensorInfoForOperand(const V1_0::Operand& operand)
telsoa015307bc12018-03-09 13:51:08 +0000100{
Finn Williamsa4983ce2020-07-23 12:55:12 +0100101 using namespace armnn;
102 DataType type;
telsoa015307bc12018-03-09 13:51:08 +0000103
104 switch (operand.type)
105 {
Matthew Bentham912b3622019-05-03 15:49:14 +0100106 case V1_0::OperandType::TENSOR_FLOAT32:
telsoa015307bc12018-03-09 13:51:08 +0000107 type = armnn::DataType::Float32;
108 break;
Matthew Bentham912b3622019-05-03 15:49:14 +0100109 case V1_0::OperandType::TENSOR_QUANT8_ASYMM:
Derek Lamberti1a38cda2020-01-10 17:28:20 +0000110 type = armnn::DataType::QAsymmU8;
telsoa015307bc12018-03-09 13:51:08 +0000111 break;
Matthew Bentham912b3622019-05-03 15:49:14 +0100112 case V1_0::OperandType::TENSOR_INT32:
telsoa015307bc12018-03-09 13:51:08 +0000113 type = armnn::DataType::Signed32;
114 break;
115 default:
Mike Kellyb5fdf382019-06-11 16:35:25 +0100116 throw UnsupportedOperand<V1_0::OperandType>(operand.type);
telsoa015307bc12018-03-09 13:51:08 +0000117 }
118
Finn Williamsa4983ce2020-07-23 12:55:12 +0100119 TensorInfo ret;
120 if (operand.dimensions.size() == 0)
121 {
122 TensorShape tensorShape(Dimensionality::NotSpecified);
123 ret = TensorInfo(tensorShape, type);
124 }
125 else
126 {
Guus Sliepen39a90142023-06-27 15:20:19 +0000127 auto dimensionsSpecificity = GetDimensionsSpecificity(operand.dimensions);
128 TensorShape tensorShape(operand.dimensions.size(), operand.dimensions.data(), dimensionsSpecificity.data());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100129 ret = TensorInfo(tensorShape, type);
130 }
telsoa015307bc12018-03-09 13:51:08 +0000131
132 ret.SetQuantizationScale(operand.scale);
133 ret.SetQuantizationOffset(operand.zeroPoint);
134
135 return ret;
136}
137
Kevin May42477c12020-03-26 13:34:14 +0000138#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 +0100139
140armnn::TensorInfo GetTensorInfoForOperand(const V1_2::Operand& operand)
141{
Aron Virginas-Tar9f0693b2019-11-06 14:32:30 +0000142 using namespace armnn;
Derek Lambertid00ad912020-01-22 15:55:16 +0000143 bool perChannel = false;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100144
Aron Virginas-Tar9f0693b2019-11-06 14:32:30 +0000145 DataType type;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100146 switch (operand.type)
147 {
Sadik Armagan793a70c2020-03-19 13:54:04 +0000148 case V1_2::OperandType::TENSOR_BOOL8:
149 type = armnn::DataType::Boolean;
150 break;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100151 case V1_2::OperandType::TENSOR_FLOAT32:
152 type = armnn::DataType::Float32;
153 break;
Mike Kelly3c673942019-07-25 09:26:06 +0100154 case V1_2::OperandType::TENSOR_FLOAT16:
155 type = armnn::DataType::Float16;
156 break;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100157 case V1_2::OperandType::TENSOR_QUANT8_ASYMM:
Derek Lamberti1a38cda2020-01-10 17:28:20 +0000158 type = armnn::DataType::QAsymmU8;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100159 break;
Derek Lambertid00ad912020-01-22 15:55:16 +0000160 case V1_2::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
161 perChannel=true;
162 ARMNN_FALLTHROUGH;
Mike Kelly0e2e31b2019-11-19 09:16:00 +0000163 case V1_2::OperandType::TENSOR_QUANT8_SYMM:
FinnWilliamsArm624fe9f2019-12-06 17:12:42 +0000164 type = armnn::DataType::QSymmS8;
Mike Kelly0e2e31b2019-11-19 09:16:00 +0000165 break;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100166 case V1_2::OperandType::TENSOR_QUANT16_SYMM:
Derek Lamberti1a38cda2020-01-10 17:28:20 +0000167 type = armnn::DataType::QSymmS16;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100168 break;
169 case V1_2::OperandType::TENSOR_INT32:
170 type = armnn::DataType::Signed32;
171 break;
172 default:
173 throw UnsupportedOperand<V1_2::OperandType>(operand.type);
174 }
175
Finn Williamsa4983ce2020-07-23 12:55:12 +0100176 TensorInfo ret;
177 if (operand.dimensions.size() == 0)
178 {
179 TensorShape tensorShape(Dimensionality::NotSpecified);
180 ret = TensorInfo(tensorShape, type);
181 }
182 else
183 {
Guus Sliepen39a90142023-06-27 15:20:19 +0000184 auto dimensionsSpecificity = GetDimensionsSpecificity(operand.dimensions);
185 TensorShape tensorShape(operand.dimensions.size(), operand.dimensions.data(), dimensionsSpecificity.data());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100186 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 {
191 // ExtraParams is expected to be of type channelQuant
Narumol Prangnawarat4d07e5e2020-04-06 16:46:21 +0100192 ARMNN_ASSERT(operand.extraParams.getDiscriminator() ==
Aron Virginas-Tar9f0693b2019-11-06 14:32:30 +0000193 V1_2::Operand::ExtraParams::hidl_discriminator::channelQuant);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100194
Aron Virginas-Tar9f0693b2019-11-06 14:32:30 +0000195 auto perAxisQuantParams = operand.extraParams.channelQuant();
196
197 ret.SetQuantizationScales(perAxisQuantParams.scales);
198 ret.SetQuantizationDim(MakeOptional<unsigned int>(perAxisQuantParams.channelDim));
199 }
200 else
201 {
202 ret.SetQuantizationScale(operand.scale);
203 ret.SetQuantizationOffset(operand.zeroPoint);
204 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100205
206 return ret;
207}
208
209#endif
210
Kevin May42477c12020-03-26 13:34:14 +0000211#ifdef ARMNN_ANDROID_NN_V1_3 // Using ::android::hardware::neuralnetworks::V1_3
212
213armnn::TensorInfo GetTensorInfoForOperand(const V1_3::Operand& operand)
214{
215 using namespace armnn;
216 bool perChannel = false;
Teresa Charlin896572b2020-07-15 12:37:51 +0100217 bool isScalar = false;
Kevin May42477c12020-03-26 13:34:14 +0000218
219 DataType type;
220 switch (operand.type)
221 {
Sadik Armagan51ba2c62020-03-31 15:36:25 +0100222 case V1_3::OperandType::TENSOR_BOOL8:
223 type = armnn::DataType::Boolean;
224 break;
Kevin May42477c12020-03-26 13:34:14 +0000225 case V1_3::OperandType::TENSOR_FLOAT32:
226 type = armnn::DataType::Float32;
227 break;
228 case V1_3::OperandType::TENSOR_FLOAT16:
229 type = armnn::DataType::Float16;
230 break;
231 case V1_3::OperandType::TENSOR_QUANT8_ASYMM:
232 type = armnn::DataType::QAsymmU8;
233 break;
234 case V1_3::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
235 perChannel=true;
236 ARMNN_FALLTHROUGH;
237 case V1_3::OperandType::TENSOR_QUANT8_SYMM:
238 type = armnn::DataType::QSymmS8;
239 break;
240 case V1_3::OperandType::TENSOR_QUANT16_SYMM:
241 type = armnn::DataType::QSymmS16;
242 break;
243 case V1_3::OperandType::TENSOR_INT32:
244 type = armnn::DataType::Signed32;
245 break;
Finn Williamsfc884b42020-06-11 17:35:44 +0100246 case V1_3::OperandType::INT32:
247 type = armnn::DataType::Signed32;
Teresa Charlin896572b2020-07-15 12:37:51 +0100248 isScalar = true;
Finn Williamsfc884b42020-06-11 17:35:44 +0100249 break;
Kevin May42477c12020-03-26 13:34:14 +0000250 case V1_3::OperandType::TENSOR_QUANT8_ASYMM_SIGNED:
251 type = armnn::DataType::QAsymmS8;
252 break;
253 default:
254 throw UnsupportedOperand<V1_3::OperandType>(operand.type);
255 }
256
Finn Williamsfc884b42020-06-11 17:35:44 +0100257 TensorInfo ret;
Teresa Charlin896572b2020-07-15 12:37:51 +0100258 if (isScalar)
Finn Williamsfc884b42020-06-11 17:35:44 +0100259 {
Teresa Charlin896572b2020-07-15 12:37:51 +0100260 ret = TensorInfo(TensorShape(armnn::Dimensionality::Scalar), type);
Finn Williamsfc884b42020-06-11 17:35:44 +0100261 }
262 else
263 {
Finn Williamsa4983ce2020-07-23 12:55:12 +0100264 if (operand.dimensions.size() == 0)
265 {
266 TensorShape tensorShape(Dimensionality::NotSpecified);
267 ret = TensorInfo(tensorShape, type);
268 }
269 else
270 {
Guus Sliepen39a90142023-06-27 15:20:19 +0000271 auto dimensionsSpecificity = GetDimensionsSpecificity(operand.dimensions);
272 TensorShape tensorShape(operand.dimensions.size(), operand.dimensions.data(), dimensionsSpecificity.data());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100273 ret = TensorInfo(tensorShape, type);
274 }
Finn Williamsfc884b42020-06-11 17:35:44 +0100275 }
276
Kevin May42477c12020-03-26 13:34:14 +0000277 if (perChannel)
278 {
279 // ExtraParams is expected to be of type channelQuant
Narumol Prangnawarat4d07e5e2020-04-06 16:46:21 +0100280 ARMNN_ASSERT(operand.extraParams.getDiscriminator() ==
Kevin May352d8382020-03-31 15:03:42 +0100281 V1_2::Operand::ExtraParams::hidl_discriminator::channelQuant);
Kevin May42477c12020-03-26 13:34:14 +0000282
283 auto perAxisQuantParams = operand.extraParams.channelQuant();
284
285 ret.SetQuantizationScales(perAxisQuantParams.scales);
286 ret.SetQuantizationDim(MakeOptional<unsigned int>(perAxisQuantParams.channelDim));
287 }
288 else
289 {
290 ret.SetQuantizationScale(operand.scale);
291 ret.SetQuantizationOffset(operand.zeroPoint);
292 }
Kevin May42477c12020-03-26 13:34:14 +0000293 return ret;
294}
295
296#endif
297
Matthew Bentham912b3622019-05-03 15:49:14 +0100298std::string GetOperandSummary(const V1_0::Operand& operand)
telsoa015307bc12018-03-09 13:51:08 +0000299{
300 return android::hardware::details::arrayToString(operand.dimensions, operand.dimensions.size()) + " " +
301 toString(operand.type);
302}
303
Kevin May42477c12020-03-26 13:34:14 +0000304#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 +0100305
306std::string GetOperandSummary(const V1_2::Operand& operand)
307{
308 return android::hardware::details::arrayToString(operand.dimensions, operand.dimensions.size()) + " " +
309 toString(operand.type);
310}
311
312#endif
313
Kevin May42477c12020-03-26 13:34:14 +0000314#ifdef ARMNN_ANDROID_NN_V1_3 // Using ::android::hardware::neuralnetworks::V1_3
315
316std::string GetOperandSummary(const V1_3::Operand& operand)
317{
318 return android::hardware::details::arrayToString(operand.dimensions, operand.dimensions.size()) + " " +
319 toString(operand.type);
320}
321
322#endif
323
telsoa015307bc12018-03-09 13:51:08 +0000324using DumpElementFunction = void (*)(const armnn::ConstTensor& tensor,
325 unsigned int elementIndex,
326 std::ofstream& fileStream);
327
328namespace
329{
330template <typename ElementType, typename PrintableType = ElementType>
331void DumpTensorElement(const armnn::ConstTensor& tensor, unsigned int elementIndex, std::ofstream& fileStream)
332{
333 const ElementType* elements = reinterpret_cast<const ElementType*>(tensor.GetMemoryArea());
334 fileStream << static_cast<PrintableType>(elements[elementIndex]) << ",";
335}
336
337constexpr const char* MemoryLayoutString(const armnn::ConstTensor& tensor)
338{
339 const char* str = "";
340
341 switch (tensor.GetNumDimensions())
342 {
343 case 4: { str = "(BHWC) "; break; }
344 case 3: { str = "(HWC) "; break; }
345 case 2: { str = "(HW) "; break; }
346 default: { str = ""; break; }
347 }
348
349 return str;
350}
351} // namespace
352
353void DumpTensor(const std::string& dumpDir,
354 const std::string& requestName,
355 const std::string& tensorName,
356 const armnn::ConstTensor& tensor)
357{
358 // The dump directory must exist in advance.
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100359 fs::path dumpPath = dumpDir;
360 const fs::path fileName = dumpPath / (requestName + "_" + tensorName + ".dump");
telsoa015307bc12018-03-09 13:51:08 +0000361
362 std::ofstream fileStream;
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100363 fileStream.open(fileName.c_str(), std::ofstream::out | std::ofstream::trunc);
telsoa015307bc12018-03-09 13:51:08 +0000364
365 if (!fileStream.good())
366 {
367 ALOGW("Could not open file %s for writing", fileName.c_str());
368 return;
369 }
370
371 DumpElementFunction dumpElementFunction = nullptr;
372
373 switch (tensor.GetDataType())
374 {
375 case armnn::DataType::Float32:
376 {
377 dumpElementFunction = &DumpTensorElement<float>;
378 break;
379 }
Derek Lamberti1a38cda2020-01-10 17:28:20 +0000380 case armnn::DataType::QAsymmU8:
telsoa015307bc12018-03-09 13:51:08 +0000381 {
382 dumpElementFunction = &DumpTensorElement<uint8_t, uint32_t>;
383 break;
384 }
385 case armnn::DataType::Signed32:
386 {
387 dumpElementFunction = &DumpTensorElement<int32_t>;
388 break;
389 }
Jim Flynnf2e175c2019-12-12 15:11:30 +0000390 case armnn::DataType::Float16:
391 {
392 dumpElementFunction = &DumpTensorElement<armnn::Half>;
393 break;
394 }
Teresa Charlinb248ec12020-04-30 11:06:34 +0100395 case armnn::DataType::QAsymmS8:
396 {
397 dumpElementFunction = &DumpTensorElement<int8_t, int32_t>;
398 break;
399 }
400 case armnn::DataType::Boolean:
401 {
402 dumpElementFunction = &DumpTensorElement<bool>;
403 break;
404 }
telsoa015307bc12018-03-09 13:51:08 +0000405 default:
406 {
407 dumpElementFunction = nullptr;
408 }
409 }
410
411 if (dumpElementFunction != nullptr)
412 {
413 const unsigned int numDimensions = tensor.GetNumDimensions();
414
415 const unsigned int batch = (numDimensions == 4) ? tensor.GetShape()[numDimensions - 4] : 1;
416
417 const unsigned int height = (numDimensions >= 3)
418 ? tensor.GetShape()[numDimensions - 3]
419 : (numDimensions >= 2) ? tensor.GetShape()[numDimensions - 2] : 1;
420
421 const unsigned int width = (numDimensions >= 3)
422 ? tensor.GetShape()[numDimensions - 2]
423 : (numDimensions >= 1) ? tensor.GetShape()[numDimensions - 1] : 0;
424
425 const unsigned int channels = (numDimensions >= 3) ? tensor.GetShape()[numDimensions - 1] : 1;
426
427 fileStream << "# Number of elements " << tensor.GetNumElements() << std::endl;
428 fileStream << "# Dimensions " << MemoryLayoutString(tensor);
429 fileStream << "[" << tensor.GetShape()[0];
430 for (unsigned int d = 1; d < numDimensions; d++)
431 {
432 fileStream << "," << tensor.GetShape()[d];
433 }
434 fileStream << "]" << std::endl;
435
436 for (unsigned int e = 0, b = 0; b < batch; ++b)
437 {
438 if (numDimensions >= 4)
439 {
440 fileStream << "# Batch " << b << std::endl;
441 }
442 for (unsigned int c = 0; c < channels; c++)
443 {
444 if (numDimensions >= 3)
445 {
446 fileStream << "# Channel " << c << std::endl;
447 }
448 for (unsigned int h = 0; h < height; h++)
449 {
450 for (unsigned int w = 0; w < width; w++, e += channels)
451 {
452 (*dumpElementFunction)(tensor, e, fileStream);
453 }
454 fileStream << std::endl;
455 }
456 e -= channels - 1;
457 if (c < channels)
458 {
459 e -= ((height * width) - 1) * channels;
460 }
461 }
462 fileStream << std::endl;
463 }
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
telsoa01ce3e84a2018-08-31 09:31:35 +0100478void DumpJsonProfilingIfRequired(bool gpuProfilingEnabled,
479 const std::string& dumpDir,
480 armnn::NetworkId networkId,
481 const armnn::IProfiler* profiler)
482{
483 // Check if profiling is required.
484 if (!gpuProfilingEnabled)
485 {
486 return;
487 }
488
489 // The dump directory must exist in advance.
490 if (dumpDir.empty())
491 {
492 return;
493 }
494
Narumol Prangnawarat4d07e5e2020-04-06 16:46:21 +0100495 ARMNN_ASSERT(profiler);
telsoa01ce3e84a2018-08-31 09:31:35 +0100496
497 // Set the name of the output profiling file.
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100498 fs::path dumpPath = dumpDir;
499 const fs::path fileName = dumpPath / (std::to_string(networkId) + "_profiling.json");
telsoa01ce3e84a2018-08-31 09:31:35 +0100500
501 // Open the ouput file for writing.
502 std::ofstream fileStream;
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100503 fileStream.open(fileName.c_str(), std::ofstream::out | std::ofstream::trunc);
telsoa01ce3e84a2018-08-31 09:31:35 +0100504
505 if (!fileStream.good())
506 {
507 ALOGW("Could not open file %s for writing", fileName.c_str());
508 return;
509 }
510
511 // Write the profiling info to a JSON file.
512 profiler->Print(fileStream);
513}
514
Jim Flynn829ad302019-12-13 14:43:24 +0000515std::string ExportNetworkGraphToDotFile(const armnn::IOptimizedNetwork& optimizedNetwork,
516 const std::string& dumpDir)
517{
518 std::string fileName;
519 // The dump directory must exist in advance.
520 if (dumpDir.empty())
521 {
522 return fileName;
523 }
524
525 std::string timestamp = GetFileTimestamp();
526 if (timestamp.empty())
527 {
528 return fileName;
529 }
530
531 // Set the name of the output .dot file.
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100532 fs::path dumpPath = dumpDir;
533 fs::path tempFilePath = dumpPath / (timestamp + "_networkgraph.dot");
534 fileName = tempFilePath.string();
Jim Flynn829ad302019-12-13 14:43:24 +0000535
536 ALOGV("Exporting the optimized network graph to file: %s", fileName.c_str());
537
538 // Write the network graph to a dot file.
539 std::ofstream fileStream;
540 fileStream.open(fileName, std::ofstream::out | std::ofstream::trunc);
541
542 if (!fileStream.good())
543 {
544 ALOGW("Could not open file %s for writing", fileName.c_str());
545 return fileName;
546 }
547
548 if (optimizedNetwork.SerializeToDot(fileStream) != armnn::Status::Success)
549 {
550 ALOGW("An error occurred when writing to file %s", fileName.c_str());
551 }
552 return fileName;
553}
554
Finn Williamsa4983ce2020-07-23 12:55:12 +0100555bool IsDynamicTensor(const armnn::TensorInfo& tensorInfo)
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100556{
Finn Williamsa4983ce2020-07-23 12:55:12 +0100557 if (tensorInfo.GetShape().GetDimensionality() == armnn::Dimensionality::NotSpecified)
558 {
559 return true;
560 }
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100561 // Account for the usage of the TensorShape empty constructor
562 if (tensorInfo.GetNumDimensions() == 0)
563 {
564 return true;
565 }
Finn Williamsa4983ce2020-07-23 12:55:12 +0100566 return !tensorInfo.GetShape().AreAllDimensionsSpecified();
567}
568
569bool AreDynamicTensorsSupported()
570{
571#if defined(ARMNN_ANDROID_NN_V1_3)
572 return true;
573#else
574 return false;
575#endif
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100576}
577
Jim Flynn829ad302019-12-13 14:43:24 +0000578std::string GetFileTimestamp()
579{
580 // used to get a timestamp to name diagnostic files (the ArmNN serialized graph
581 // and getSupportedOperations.txt files)
582 timespec ts;
583 int iRet = clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
584 std::stringstream ss;
585 if (iRet == 0)
586 {
587 ss << std::to_string(ts.tv_sec) << "_" << std::to_string(ts.tv_nsec);
588 }
589 else
590 {
591 ALOGW("clock_gettime failed with errno %s : %s", std::to_string(errno).c_str(), std::strerror(errno));
592 }
593 return ss.str();
594}
595
596void RenameGraphDotFile(const std::string& oldName, const std::string& dumpDir, const armnn::NetworkId networkId)
597{
598 if (dumpDir.empty())
599 {
600 return;
601 }
602 if (oldName.empty())
603 {
604 return;
605 }
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100606 fs::path dumpPath = dumpDir;
607 const fs::path newFileName = dumpPath / (std::to_string(networkId) + "_networkgraph.dot");
608
Jim Flynn829ad302019-12-13 14:43:24 +0000609 int iRet = rename(oldName.c_str(), newFileName.c_str());
610 if (iRet != 0)
611 {
612 std::stringstream ss;
613 ss << "rename of [" << oldName << "] to [" << newFileName << "] failed with errno " << std::to_string(errno)
614 << " : " << std::strerror(errno);
615 ALOGW(ss.str().c_str());
616 }
617}
618
Kevin May42477c12020-03-26 13:34:14 +0000619void CommitPools(std::vector<::android::nn::RunTimePoolInfo>& memPools)
620{
621 if (memPools.empty())
622 {
623 return;
624 }
625 // Commit output buffers.
626 // Note that we update *all* pools, even if they aren't actually used as outputs -
627 // this is simpler and is what the CpuExecutor does.
628 for (auto& pool : memPools)
629 {
630 // Type android::nn::RunTimePoolInfo has changed between Android P & Q and Android R, where
631 // update() has been removed and flush() added.
632#if defined(ARMNN_ANDROID_R) // Use the new Android implementation.
633 pool.flush();
634#else
635 pool.update();
636#endif
637 }
638}
telsoa015307bc12018-03-09 13:51:08 +0000639} // namespace armnn_driver