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