1663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross/* 2663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross * Copyright (C) 2017 The Android Open Source Project 3663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross * 4663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross * Licensed under the Apache License, Version 2.0 (the "License"); 5663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross * you may not use this file except in compliance with the License. 6663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross * You may obtain a copy of the License at 7663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross * 8663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross * http://www.apache.org/licenses/LICENSE-2.0 9663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross * 10663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross * Unless required by applicable law or agreed to in writing, software 11663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross * distributed under the License is distributed on an "AS IS" BASIS, 12663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross * See the License for the specific language governing permissions and 14663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross * limitations under the License. 15663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross */ 16663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross 17663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross#include "GraphDump.h" 18663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross 19663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross#include "HalInterfaces.h" 20663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross 21663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross#include <set> 22663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross#include <iostream> 23663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross 24663155d58ca1e1eb42e01495e236258e0c00d40fDavid Grossnamespace android { 25663155d58ca1e1eb42e01495e236258e0c00d40fDavid Grossnamespace nn { 26663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross 27663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross// Provide short name for OperandType value. 28663155d58ca1e1eb42e01495e236258e0c00d40fDavid Grossstatic std::string translate(OperandType type) { 29663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross switch (type) { 30663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross case OperandType::FLOAT32: return "F32"; 31663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross case OperandType::INT32: return "I32"; 32663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross case OperandType::UINT32: return "U32"; 33663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross case OperandType::TENSOR_FLOAT32: return "TF32"; 34663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross case OperandType::TENSOR_INT32: return "TI32"; 35663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross case OperandType::TENSOR_QUANT8_ASYMM: return "TQ8A"; 36663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross case OperandType::OEM: return "OEM"; 37663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross case OperandType::TENSOR_OEM_BYTE: return "TOEMB"; 38663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross default: return toString(type); 39663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 40663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross} 41663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross 42663155d58ca1e1eb42e01495e236258e0c00d40fDavid Grossvoid graphDump(const char* name, const Model& model, std::ostream& outStream) { 43663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross // Operand nodes are named "d" (operanD) followed by operand index. 44663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross // Operation nodes are named "n" (operatioN) followed by operation index. 45663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross // (These names are not the names that are actually displayed -- those 46663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross // names are given by the "label" attribute.) 47663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross 48663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << "// " << name << std::endl; 49663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << "digraph {" << std::endl; 50663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross 51663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross // model inputs and outputs 52663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross std::set<uint32_t> modelIO; 53663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross for (unsigned i = 0, e = model.inputIndexes.size(); i < e; i++) { 54663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross modelIO.insert(model.inputIndexes[i]); 55663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 56663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross for (unsigned i = 0, e = model.outputIndexes.size(); i < e; i++) { 57663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross modelIO.insert(model.outputIndexes[i]); 58663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 59663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross 60663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross // model operands 61663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross for (unsigned i = 0, e = model.operands.size(); i < e; i++) { 62663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << " d" << i << " ["; 63663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross if (modelIO.count(i)) { 64663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << "style=filled fillcolor=black fontcolor=white "; 65663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 66663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << "label=\"" << i; 67663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross const Operand& opnd = model.operands[i]; 68663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross const char* kind = nullptr; 69663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross switch (opnd.lifetime) { 70663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross case OperandLifeTime::CONSTANT_COPY: 71663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross kind = "COPY"; 72663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross break; 73663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross case OperandLifeTime::CONSTANT_REFERENCE: 74663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross kind = "REF"; 75663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross break; 76663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross case OperandLifeTime::NO_VALUE: 77663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross kind = "NO"; 78663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross break; 79663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross default: 80663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross // nothing interesting 81663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross break; 82663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 83663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross if (kind) { 84663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << ": " << kind; 85663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 86663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << "\\n" << translate(opnd.type); 87663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross if (opnd.dimensions.size()) { 88663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << "("; 89663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross for (unsigned i = 0, e = opnd.dimensions.size(); i < e; i++) { 90663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross if (i > 0) { 91663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << "x"; 92663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 93663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << opnd.dimensions[i]; 94663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 95663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << ")"; 96663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 97663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << "\"]" << std::endl; 98663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 99663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross 100663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross // model operations 101663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross for (unsigned i = 0, e = model.operations.size(); i < e; i++) { 102663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross const Operation& operation = model.operations[i]; 103663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << " n" << i << " [shape=box"; 104663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross const uint32_t maxArity = std::max(operation.inputs.size(), operation.outputs.size()); 105663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross if (maxArity > 1) { 106663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross if (maxArity == operation.inputs.size()) { 107663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << " ordering=in"; 108663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } else { 109663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << " ordering=out"; 110663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 111663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 112663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << " label=\"" << i << ": " 113663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross << toString(operation.type) << "\"]" << std::endl; 114663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross { 115663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross // operation inputs 116663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross for (unsigned in = 0, inE = operation.inputs.size(); in < inE; in++) { 117663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << " d" << operation.inputs[in] << " -> n" << i; 118663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross if (inE > 1) { 119663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << " [label=" << in << "]"; 120663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 121663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << std::endl; 122663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 123663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 124663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross 125663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross { 126663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross // operation outputs 127663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross for (unsigned out = 0, outE = operation.outputs.size(); out < outE; out++) { 128663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << " n" << i << " -> d" << operation.outputs[out]; 129663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross if (outE > 1) { 130663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << " [label=" << out << "]"; 131663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 132663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << std::endl; 133663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 134663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 135663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross } 136663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross outStream << "}" << std::endl; 137663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross} 138663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross 139663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross} // namespace nn 140663155d58ca1e1eb42e01495e236258e0c00d40fDavid Gross} // namespace android 141