1 // 2 // Copyright © 2022 Arm Ltd and Contributors. All rights reserved. 3 // SPDX-License-Identifier: MIT 4 // 5 6 #pragma once 7 8 #include <iomanip> 9 10 #include "armnn/Types.hpp" 11 #include "armnn/TypesUtils.hpp" 12 #include "armnn/backends/WorkloadInfo.hpp" 13 14 #include "SerializeLayerParameters.hpp" 15 #include "JsonUtils.hpp" 16 17 namespace armnn 18 { 19 20 /// ProfilingDetails class records any details associated with the operator and passes on for outputting to the user 21 class ProfilingDetails : public JsonUtils 22 { 23 public: 24 /// Constructor ProfilingDetails()25 ProfilingDetails() : JsonUtils(m_ProfilingDetails), m_DetailsExist(false) 26 {} 27 28 /// Destructor ~ProfilingDetails()29 ~ProfilingDetails() noexcept 30 {} 31 32 /// Add to the ProfilingDetails 33 template <typename DescriptorType> AddDetailsToString(const std::string & workloadName,const DescriptorType & desc,const WorkloadInfo & infos,const arm::pipe::ProfilingGuid guid)34 void AddDetailsToString(const std::string& workloadName, 35 const DescriptorType& desc, 36 const WorkloadInfo& infos, 37 const arm::pipe::ProfilingGuid guid) 38 { 39 // Once details exist, we can assume we're on the second iteration of details 40 if (m_DetailsExist) 41 { 42 PrintSeparator(); 43 PrintNewLine(); 44 } 45 46 PrintHeader(); 47 PrintTabs(); 48 m_ProfilingDetails << std::quoted("Name") << ": " << std::quoted(workloadName); 49 PrintSeparator(); 50 PrintNewLine(); 51 PrintTabs(); 52 m_ProfilingDetails << std::quoted("GUID") << ": " << std::quoted(std::to_string(guid)); 53 54 // From this point onwards everything is potentially optional so we must be careful of separators and new lines. 55 56 // Print tensor infos and related data types 57 if (!infos.m_InputTensorInfos.empty()) 58 { 59 PrintSeparator(); 60 PrintNewLine(); 61 // Only add separator and new line if there is an output tensor info. 62 PrintInfos(infos.m_InputTensorInfos, "Input", !infos.m_OutputTensorInfos.empty()); 63 } 64 65 if (!infos.m_OutputTensorInfos.empty()) 66 { 67 // Don't add a separator as we don't know what's next. 68 PrintInfos(infos.m_OutputTensorInfos, "Output", false); 69 } 70 71 if (infos.m_BiasTensorInfo.has_value()) 72 { 73 PrintSeparator(); 74 PrintNewLine(); 75 PrintInfo(infos.m_BiasTensorInfo.value(), "Bias", false); 76 } 77 78 if (infos.m_WeightsTensorInfo.has_value()) 79 { 80 PrintSeparator(); 81 PrintNewLine(); 82 PrintInfo(infos.m_WeightsTensorInfo.value(), "Weights", false); 83 } 84 85 if (infos.m_ConvolutionMethod.has_value()) 86 { 87 PrintSeparator(); 88 PrintNewLine(); 89 PrintTabs(); 90 91 m_ProfilingDetails << std::quoted("Convolution Method") << ": " 92 << std::quoted(infos.m_ConvolutionMethod.value()); 93 } 94 95 ParameterStringifyFunction extractParams = [this](const std::string& name, const std::string& value) { 96 // Always begin with a separator and new line. 97 PrintSeparator(); 98 PrintNewLine(); 99 PrintTabs(); 100 m_ProfilingDetails << std::quoted(name) << " : " << std::quoted(value); 101 }; 102 103 StringifyLayerParameters<DescriptorType>::Serialize(extractParams, desc); 104 105 PrintNewLine(); 106 PrintFooter(); 107 108 m_DetailsExist = true; 109 } 110 111 /// Get the ProfilingDetails 112 /// \return the ProfilingDetails GetProfilingDetails() const113 std::string GetProfilingDetails() const 114 { 115 return m_ProfilingDetails.str(); 116 } 117 DetailsExist()118 bool DetailsExist() 119 { 120 return m_DetailsExist; 121 } 122 123 private: 124 // Print tensor infos and related data types PrintInfo(const TensorInfo & info,const std::string & ioString,bool addSeparator=true)125 void PrintInfo(const TensorInfo& info, const std::string& ioString, bool addSeparator = true) 126 { 127 const std::vector<TensorInfo> infoVect{ info }; 128 PrintInfos(infoVect, ioString, addSeparator); 129 } 130 PrintInfos(const std::vector<TensorInfo> & infos,const std::string & ioString,bool addSeparator=true)131 void PrintInfos(const std::vector<TensorInfo>& infos, const std::string& ioString, bool addSeparator = true) 132 { 133 for ( size_t i = 0; i < infos.size(); i++ ) 134 { 135 auto shape = infos[i].GetShape(); 136 PrintTabs(); 137 138 m_ProfilingDetails << std::quoted(ioString + " " + std::to_string(i)) << ": "; 139 140 PrintHeader(); 141 PrintTabs(); 142 143 // Shape 144 m_ProfilingDetails << std::quoted("Shape") << ": \"["; 145 for ( unsigned int dim = 0; dim < shape.GetNumDimensions(); dim++ ) 146 { 147 shape.GetNumDimensions() == dim + 1 ? 148 m_ProfilingDetails << shape[dim] << "]\"" : // true 149 m_ProfilingDetails << shape[dim] << ","; // false 150 } 151 152 PrintSeparator(); 153 PrintNewLine(); 154 155 // Data Type 156 PrintTabs(); 157 m_ProfilingDetails << std::quoted("DataType") << ": " 158 << std::quoted(GetDataTypeName(infos[i].GetDataType())); 159 160 PrintSeparator(); 161 PrintNewLine(); 162 163 // Number of Dimensions 164 PrintTabs(); 165 m_ProfilingDetails << std::quoted("Num Dims") << ": " 166 << std::quoted(std::to_string(shape.GetNumDimensions())); 167 168 169 // Close out the scope 170 PrintNewLine(); 171 PrintFooter(); 172 // For the last element we will consider the value of addSeparator. 173 if ((i < infos.size() - 1) || (addSeparator)) 174 { 175 PrintSeparator(); 176 PrintNewLine(); 177 } 178 } 179 } 180 181 /// Stores ProfilingDetails 182 std::ostringstream m_ProfilingDetails; 183 bool m_DetailsExist; 184 185 }; 186 187 } // namespace armnn 188