Imported Upstream version 1.7.0
[platform/core/ml/nnfw.git] / runtime / onert / core / src / dumper / dot / DotDumper.cc
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <fstream>
18 #include <unordered_map>
19
20 #include "DotDumper.h"
21 #include "DotBuilder.h"
22 #include "DotSubgraphInfo.h"
23 #include "ir/OpSequence.h"
24 #include "ir/OperationIndexMap.h"
25 #include "backend/Backend.h"
26 #include "backend/IConfig.h"
27 #include "compiler/BackendManager.h"
28
29 namespace onert
30 {
31 namespace dumper
32 {
33 namespace dot
34 {
35
36 void DotDumper::dump(const std::string &tag)
37 {
38   if (_level == Level::OFF)
39   {
40     return;
41   }
42
43   onert::dumper::dot::DotBuilder dot_builder;
44
45   auto &operations = _graph.operations();
46   auto &operands = _graph.operands();
47
48   ir::OperationIndexMap<std::unique_ptr<Operation>> operation_nodes;
49   std::unordered_map<ir::OperandIndex, std::unique_ptr<Operand>> operand_nodes;
50
51   auto backend_to_fillcolor = [](const backend::Backend *backend) {
52     static const auto map = []() {
53       std::unordered_map<const backend::Backend *, std::string> ret;
54       uint32_t index = 1; // Start from 1 to avoid 0(red) which is too dark :(
55       for (const auto backend : compiler::BackendManager::get().getAll())
56       {
57         ret.emplace(backend, Node::BG_COLORS[index]);
58         index = (index + 1) % (sizeof(Node::BG_COLORS) / sizeof(Node::BG_COLORS[0]));
59       }
60       return ret;
61     }();
62
63     auto itr = map.find(backend);
64     if (itr == map.end())
65     {
66       return Node::DEFAULT_FILLCOLOR;
67     }
68     else
69     {
70       return itr->second;
71     }
72   };
73
74   util::Set<ir::OperandIndex> shown_operand_set;
75
76   operands.iterate([&](const ir::OperandIndex &index, const ir::Operand &object) {
77     bool showing_cond = false;
78     if (_level == Level::ALL)
79     {
80       showing_cond = true;
81     }
82     else
83     {
84       showing_cond = !object.isConstant();
85     }
86     if (object.isConstant() || _graph.getInputs().contains(index))
87     {
88       showing_cond = showing_cond && (object.getUses().size() > 0);
89     }
90     if (showing_cond)
91     {
92       shown_operand_set.add(index);
93
94       auto type = [&]() {
95         using onert::dumper::dot::Operand;
96         if (_graph.getInputs().contains(index))
97           return Operand::Type::MODEL_INPUT;
98         if (_graph.getOutputs().contains(index))
99           return Operand::Type::MODEL_OUTPUT;
100         return Operand::Type::INTERNAL;
101       }();
102
103       auto node = std::make_unique<Operand>(index, type);
104
105       {
106         // Display LowerInfo attributes
107         std::string label = std::to_string(index.value());
108         std::string fillcolor = "";
109         if (_lowered_graph)
110         {
111           auto lower_info = _lowered_graph->getLowerInfo(index);
112           const auto &def_factors = lower_info->def_factors();
113           if (def_factors.size() > 0)
114           {
115             label += "\\n[";
116             label += def_factors.getOnlyElement().backend()->config()->id();
117             label += "]";
118
119             fillcolor = backend_to_fillcolor(lower_info->def_factors().getOnlyElement().backend());
120           }
121         }
122         node->setAttribute("label", label);
123         node->setAttribute("fillcolor", fillcolor);
124       }
125
126       operand_nodes.emplace(index, std::move(node));
127     }
128   });
129
130   operations.iterate([&](const ir::OperationIndex &index, const ir::Operation &op) {
131     auto node = std::make_unique<Operation>(index, op);
132
133     for (auto input : op.getInputs())
134     {
135       using onert::dumper::dot::Operand;
136
137       // Constant input and dump level is ALL_BUT_CONSTANTS
138       if (operand_nodes.find(input) == operand_nodes.end())
139         continue;
140
141       auto &input_node = operand_nodes.at(input);
142       input_node->addOutEdge(node.get());
143     }
144
145     for (auto output : op.getOutputs())
146     {
147       using onert::dumper::dot::Operand;
148       auto &output_node = operand_nodes.at(output);
149       node->addOutEdge(output_node.get());
150     }
151
152     operation_nodes.emplace(index, std::move(node));
153   });
154
155   if (_lowered_graph)
156   {
157     const auto &op_seqs = _lowered_graph->op_seqs();
158     op_seqs.iterate([&](const ir::OpSequenceIndex &index, const ir::OpSequence &op_seq) {
159       const auto lower_info = _lowered_graph->getLowerInfo(index);
160       auto fillcolor = backend_to_fillcolor(lower_info->backend());
161       std::string label =
162           std::to_string(index.value()) + " [" + lower_info->backend()->config()->id() + "]";
163       DotSubgraphInfo subgraph_info{index, op_seq, shown_operand_set, _graph.operations()};
164       subgraph_info.label(label);
165       subgraph_info.fillcolor(fillcolor);
166       dot_builder.addOpSequence(subgraph_info);
167
168       // Set fillcolor of all operations in the op_seq
169       for (const auto &op_idx : op_seq.operations())
170       {
171         auto found = operation_nodes.find(op_idx);
172         if (found != operation_nodes.end())
173         {
174           auto &&op = found->second;
175           op->setAttribute("fillcolor", fillcolor);
176         }
177       }
178     });
179   }
180
181   for (const auto &e : operation_nodes)
182     dot_builder.update(*e.second);
183   for (const auto &e : operand_nodes)
184     dot_builder.update(*e.second);
185
186   // Dump to file
187   {
188     std::string file_name;
189     file_name += tag;
190     file_name += ".dot";
191     std::filebuf fb;
192
193     fb.open(file_name, std::ios::out);
194     std::ostream os(&fb);
195
196     dot_builder.writeDot(os);
197
198     fb.close();
199   }
200 }
201
202 } // namespace dot
203 } // namespace dumper
204 } // namespace onert