// // Copyright © 2022 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // #pragma once #include #include "armnn/Types.hpp" #include "armnn/TypesUtils.hpp" #include "armnn/backends/WorkloadInfo.hpp" #include "SerializeLayerParameters.hpp" #include "JsonUtils.hpp" namespace armnn { /// ProfilingDetails class records any details associated with the operator and passes on for outputting to the user class ProfilingDetails : public JsonUtils { public: /// Constructor ProfilingDetails() : JsonUtils(m_ProfilingDetails), m_DetailsExist(false) {} /// Destructor ~ProfilingDetails() noexcept {} /// Add to the ProfilingDetails template void AddDetailsToString(const std::string& workloadName, const DescriptorType& desc, const WorkloadInfo& infos, const arm::pipe::ProfilingGuid guid) { // Once details exist, we can assume we're on the second iteration of details if (m_DetailsExist) { PrintSeparator(); PrintNewLine(); } PrintHeader(); PrintTabs(); m_ProfilingDetails << std::quoted("Name") << ": " << std::quoted(workloadName); PrintSeparator(); PrintNewLine(); PrintTabs(); m_ProfilingDetails << std::quoted("GUID") << ": " << std::quoted(std::to_string(guid)); // From this point onwards everything is potentially optional so we must be careful of separators and new lines. // Print tensor infos and related data types if (!infos.m_InputTensorInfos.empty()) { PrintSeparator(); PrintNewLine(); // Only add separator and new line if there is an output tensor info. PrintInfos(infos.m_InputTensorInfos, "Input", !infos.m_OutputTensorInfos.empty()); } if (!infos.m_OutputTensorInfos.empty()) { // Don't add a separator as we don't know what's next. PrintInfos(infos.m_OutputTensorInfos, "Output", false); } if (infos.m_BiasTensorInfo.has_value()) { PrintSeparator(); PrintNewLine(); PrintInfo(infos.m_BiasTensorInfo.value(), "Bias", false); } if (infos.m_WeightsTensorInfo.has_value()) { PrintSeparator(); PrintNewLine(); PrintInfo(infos.m_WeightsTensorInfo.value(), "Weights", false); } if (infos.m_ConvolutionMethod.has_value()) { PrintSeparator(); PrintNewLine(); PrintTabs(); m_ProfilingDetails << std::quoted("Convolution Method") << ": " << std::quoted(infos.m_ConvolutionMethod.value()); } ParameterStringifyFunction extractParams = [this](const std::string& name, const std::string& value) { // Always begin with a separator and new line. PrintSeparator(); PrintNewLine(); PrintTabs(); m_ProfilingDetails << std::quoted(name) << " : " << std::quoted(value); }; StringifyLayerParameters::Serialize(extractParams, desc); PrintNewLine(); PrintFooter(); m_DetailsExist = true; } /// Get the ProfilingDetails /// \return the ProfilingDetails std::string GetProfilingDetails() const { return m_ProfilingDetails.str(); } bool DetailsExist() { return m_DetailsExist; } private: // Print tensor infos and related data types void PrintInfo(const TensorInfo& info, const std::string& ioString, bool addSeparator = true) { const std::vector infoVect{ info }; PrintInfos(infoVect, ioString, addSeparator); } void PrintInfos(const std::vector& infos, const std::string& ioString, bool addSeparator = true) { for ( size_t i = 0; i < infos.size(); i++ ) { auto shape = infos[i].GetShape(); PrintTabs(); m_ProfilingDetails << std::quoted(ioString + " " + std::to_string(i)) << ": "; PrintHeader(); PrintTabs(); // Shape m_ProfilingDetails << std::quoted("Shape") << ": \"["; for ( unsigned int dim = 0; dim < shape.GetNumDimensions(); dim++ ) { shape.GetNumDimensions() == dim + 1 ? m_ProfilingDetails << shape[dim] << "]\"" : // true m_ProfilingDetails << shape[dim] << ","; // false } PrintSeparator(); PrintNewLine(); // Data Type PrintTabs(); m_ProfilingDetails << std::quoted("DataType") << ": " << std::quoted(GetDataTypeName(infos[i].GetDataType())); PrintSeparator(); PrintNewLine(); // Number of Dimensions PrintTabs(); m_ProfilingDetails << std::quoted("Num Dims") << ": " << std::quoted(std::to_string(shape.GetNumDimensions())); // Close out the scope PrintNewLine(); PrintFooter(); // For the last element we will consider the value of addSeparator. if ((i < infos.size() - 1) || (addSeparator)) { PrintSeparator(); PrintNewLine(); } } } /// Stores ProfilingDetails std::ostringstream m_ProfilingDetails; bool m_DetailsExist; }; } // namespace armnn