Imported Upstream version 1.25.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 "ir/OperandIndexMap.h"
23 #include "ir/OperationIndexMap.h"
24 #include "backend/Backend.h"
25 #include "backend/IConfig.h"
26 #include "compiler/BackendManager.h"
27
28 namespace onert
29 {
30 namespace dumper
31 {
32 namespace dot
33 {
34
35 namespace
36 {
37 std::string backend_to_fillcolor(const backend::Backend *backend)
38 {
39   static const auto map = []() {
40     std::unordered_map<const backend::Backend *, std::string> ret;
41     uint32_t index = 1; // Start from 1 to avoid 0(red) which is too dark :(
42     for (const auto backend : compiler::BackendManager::get().getAll())
43     {
44       ret.emplace(backend, Node::BG_COLORS[index]);
45       index = (index + 1) % (sizeof(Node::BG_COLORS) / sizeof(Node::BG_COLORS[0]));
46     }
47     return ret;
48   }();
49   auto itr = map.find(backend);
50   if (itr == map.end())
51   {
52     return Node::DEFAULT_FILLCOLOR;
53   }
54   else
55   {
56     return itr->second;
57   }
58 }
59
60 std::unordered_map<ir::OperandIndex, std::unique_ptr<Operand>>
61 generate_dot_operands(const ir::Graph &graph, const DotDumper::Level level)
62 {
63   std::unordered_map<ir::OperandIndex, std::unique_ptr<Operand>> dot_operands;
64
65   const auto &operands = graph.operands();
66   operands.iterate([&](const ir::OperandIndex &index, const ir::Operand &object) {
67     bool showing_cond =
68       level == DotDumper::Level::ALL
69         ? true
70         : !object.isConstant() || (graph.getInputs() + graph.getOutputs()).contains(index);
71     if (showing_cond)
72     {
73       auto type = [&]() {
74         using onert::dumper::dot::Operand;
75         if (graph.getInputs().contains(index))
76           return Operand::Type::MODEL_INPUT;
77         if (graph.getOutputs().contains(index))
78           return Operand::Type::MODEL_OUTPUT;
79         return Operand::Type::INTERNAL;
80       }();
81
82       auto node = std::make_unique<Operand>(index, type);
83       std::string label = std::to_string(index.value());
84       std::string fillcolor = "";
85       node->setAttribute("label", label);
86       node->setAttribute("fillcolor", fillcolor);
87
88       dot_operands.emplace(index, std::move(node));
89     }
90   });
91
92   return dot_operands;
93 }
94
95 ir::OperationIndexMap<std::unique_ptr<Operation>>
96 generate_dot_operations(const ir::Graph &graph,
97                         const ir::OperandIndexMap<std::unique_ptr<Operand>> &dot_operands)
98 {
99   ir::OperationIndexMap<std::unique_ptr<Operation>> dot_operations;
100   const auto &operations = graph.operations();
101   operations.iterate([&](const ir::OperationIndex &index, const ir::IOperation &op) {
102     auto node = std::make_unique<Operation>(index, op);
103
104     for (auto &&input : op.getInputs())
105     {
106       using onert::dumper::dot::Operand;
107
108       // Constant input and dump level is ALL_BUT_CONSTANTS
109       if (dot_operands.find(input) == dot_operands.end())
110         continue;
111
112       auto &input_node = dot_operands.at(input);
113       input_node->addOutEdge(node.get());
114     }
115
116     for (auto &&output : op.getOutputs() | ir::Remove::UNDEFINED)
117     {
118       using onert::dumper::dot::Operand;
119       auto &output_node = dot_operands.at(output);
120       node->addOutEdge(output_node.get());
121     }
122
123     dot_operations.emplace(index, std::move(node));
124   });
125
126   return dot_operations;
127 }
128
129 void update_lower_info(const compiler::ILoweredGraph &lowered_graph,
130                        ir::OperandIndexMap<std::unique_ptr<Operand>> *dot_operands)
131 {
132   const auto &operands = lowered_graph.graph().operands();
133   operands.iterate([&](const ir::OperandIndex &index, const ir::Operand &) {
134     auto itr = dot_operands->find(index);
135     if (itr != dot_operands->end())
136     {
137       auto &node = itr->second;
138       // Display LowerInfo attributes
139       std::string label = node->getAttribute("label");
140       std::string fillcolor = node->getAttribute("fillcolor");
141       auto lower_info = lowered_graph.lower_info().operand.getRawPtr(index);
142       const auto &def_factors = lower_info->def_factors();
143       if (def_factors.size() > 0)
144       {
145         label += "\\n[";
146         label += def_factors.getOnlyElement().backend()->config()->id();
147         label += "]";
148         fillcolor = backend_to_fillcolor(lower_info->def_factors().getOnlyElement().backend());
149       }
150       node->setAttribute("label", label);
151       node->setAttribute("fillcolor", fillcolor);
152     }
153   });
154 }
155
156 void update_lower_info(const compiler::ILoweredGraph &lowered_graph,
157                        ir::OperationIndexMap<std::unique_ptr<Operation>> *dot_operations)
158 {
159   const auto &operations = lowered_graph.graph().operations();
160   operations.iterate([&](const ir::OperationIndex &index, const ir::IOperation &) {
161     const auto lower_info = lowered_graph.lower_info().operation.getRawPtr(index);
162     if (lower_info)
163     {
164       auto fillcolor = backend_to_fillcolor(lower_info->backend());
165       std::string backend_label = "[" + lower_info->backend()->config()->id() + "]";
166       auto itr = dot_operations->find(index);
167       if (itr != dot_operations->end())
168       {
169         auto &node = itr->second;
170         node->setAttribute("label", node->getAttribute("label") + "\n" + backend_label);
171         node->setAttribute("fillcolor", fillcolor);
172       }
173     }
174   });
175 }
176
177 void dump_to_file(const ir::OperandIndexMap<std::unique_ptr<Operand>> &operand_nodes,
178                   const ir::OperationIndexMap<std::unique_ptr<Operation>> &operation_nodes,
179                   const std::string &tag)
180 {
181   onert::dumper::dot::DotBuilder dot_builder;
182   for (const auto &e : operation_nodes)
183     dot_builder.update(*e.second);
184   for (const auto &e : operand_nodes)
185     dot_builder.update(*e.second);
186
187   // Dump to file
188   {
189     std::string file_name;
190     file_name += tag;
191     file_name += ".dot";
192     std::filebuf fb;
193
194     fb.open(file_name, std::ios::out);
195     std::ostream os(&fb);
196
197     dot_builder.writeDot(os);
198
199     fb.close();
200   }
201 }
202 } // namespace
203
204 void DotDumper::dump(const ir::Graph &graph, const std::string &tag)
205 {
206   if (_level == Level::OFF)
207   {
208     return;
209   }
210
211   const auto dot_operands = generate_dot_operands(graph, _level);
212   const auto dot_operations = generate_dot_operations(graph, dot_operands);
213   dump_to_file(dot_operands, dot_operations, tag);
214 }
215
216 // TODO Support derivative tensors
217 void DotDumper::dump(const compiler::ILoweredGraph &lowered_graph, const std::string &tag)
218 {
219   if (_level == Level::OFF)
220   {
221     return;
222   }
223
224   auto dot_operands = generate_dot_operands(lowered_graph.graph(), _level);
225   auto dot_operations = generate_dot_operations(lowered_graph.graph(), dot_operands);
226   update_lower_info(lowered_graph, &dot_operands);
227   update_lower_info(lowered_graph, &dot_operations);
228   dump_to_file(dot_operands, dot_operations, tag);
229 }
230
231 } // namespace dot
232 } // namespace dumper
233 } // namespace onert