summaryrefslogtreecommitdiff
path: root/runtimes/neurun/core/src/dumper/dot/DotDumper.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtimes/neurun/core/src/dumper/dot/DotDumper.cc')
-rw-r--r--runtimes/neurun/core/src/dumper/dot/DotDumper.cc198
1 files changed, 198 insertions, 0 deletions
diff --git a/runtimes/neurun/core/src/dumper/dot/DotDumper.cc b/runtimes/neurun/core/src/dumper/dot/DotDumper.cc
new file mode 100644
index 000000000..d01b472c3
--- /dev/null
+++ b/runtimes/neurun/core/src/dumper/dot/DotDumper.cc
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fstream>
+#include <unordered_map>
+
+#include "DotDumper.h"
+#include "DotBuilder.h"
+#include "DotSubgraphInfo.h"
+#include "model/Subgraph.h"
+#include "model/OperationIndexMap.h"
+#include "backend/Backend.h"
+#include "backend/BackendManager.h"
+#include "backend/IConfig.h"
+
+namespace neurun
+{
+namespace dumper
+{
+namespace dot
+{
+
+using namespace neurun::graph;
+
+void DotDumper::dump(const std::string &tag)
+{
+ if (_level == Level::OFF)
+ {
+ return;
+ }
+
+ neurun::dumper::dot::DotBuilder dot_builder;
+
+ auto &operations = _graph.operations();
+ auto &operands = _graph.operands();
+
+ model::OperationIndexMap<std::unique_ptr<OperationNode>> operation_nodes;
+ std::unordered_map<model::OperandIndex, std::unique_ptr<OperandNode>> operand_nodes;
+
+ operations.iterate([&](const model::OperationIndex &index, const model::Operation &op) {
+ auto node = nnfw::cpp14::make_unique<OperationNode>(index, op);
+
+ for (auto output : op.getOutputs())
+ {
+ using neurun::dumper::dot::OperandNode;
+ auto child = std::make_shared<OperandNode>(output, OperandNode::Type::MODEL_OUTPUT);
+ node->addEdge(child);
+ }
+
+ operation_nodes.emplace(index, std::move(node));
+ });
+
+ auto backend_to_fillcolor = [](const backend::Backend *backend) {
+ static const auto map = []() {
+ std::unordered_map<const backend::Backend *, std::string> ret;
+ uint32_t index = 1; // Start from 1 to avoid 0(red) which is too dark :(
+ for (const auto backend : backend::BackendManager::instance().getAll())
+ {
+ ret.emplace(backend, Node::BG_COLORS[index]);
+ index = (index + 1) % (sizeof(Node::BG_COLORS) / sizeof(Node::BG_COLORS[0]));
+ }
+ return ret;
+ }();
+
+ auto itr = map.find(backend);
+ if (itr == map.end())
+ {
+ return Node::DEFAULT_FILLCOLOR;
+ }
+ else
+ {
+ return itr->second;
+ }
+ };
+
+ util::Set<model::OperandIndex> shown_operand_set;
+
+ operands.iterate([&](const model::OperandIndex &index, const model::Operand &object) {
+ bool showing_cond = false;
+ if (_level == Level::ALL)
+ {
+ showing_cond = true;
+ }
+ else
+ {
+ showing_cond = !object.isConstant();
+ }
+ if (object.isConstant() || _graph.getInputs().contains(index))
+ {
+ showing_cond = showing_cond && (object.getUses().size() > 0);
+ }
+ if (showing_cond)
+ {
+ shown_operand_set.add(index);
+
+ auto type = [&]() {
+ using neurun::dumper::dot::OperandNode;
+ if (_graph.getInputs().contains(index))
+ return OperandNode::Type::MODEL_INPUT;
+ if (_graph.getOutputs().contains(index))
+ return OperandNode::Type::MODEL_OUTPUT;
+ return OperandNode::Type::INTERNAL;
+ }();
+
+ auto lower_info = _graph.getLowerInfo(index);
+ auto node = nnfw::cpp14::make_unique<OperandNode>(index, type);
+
+ {
+ // Display LowerInfo attributes
+ std::string label = std::to_string(index.value());
+ std::string fillcolor = "";
+ if (lower_info)
+ {
+ const auto &def_factors = lower_info->def_factors();
+ label += "\\n[";
+ label += def_factors.getOnlyElement().backend()->config()->id();
+ label += "]";
+
+ fillcolor = backend_to_fillcolor(lower_info->def_factors().getOnlyElement().backend());
+ }
+ node->setAttribute("label", label);
+ node->setAttribute("fillcolor", fillcolor);
+ }
+
+ for (auto operation_index : object.getUses().list())
+ {
+ auto &operation = operations.at(operation_index);
+ auto child = std::make_shared<OperationNode>(operation_index, operation);
+ node->addEdge(child);
+ }
+
+ operand_nodes.emplace(index, std::move(node));
+ }
+ });
+
+ const auto subgraphs = _graph.subgraphs();
+ if (subgraphs)
+ {
+ subgraphs->iterate([&](const model::SubgraphIndex &index, const model::Subgraph &subgraph) {
+ const auto lower_info = _graph.getLowerInfo(index);
+ auto fillcolor = backend_to_fillcolor(lower_info->backend());
+ std::string label =
+ std::to_string(index.value()) + " [" + lower_info->backend()->config()->id() + "]";
+ DotSubgraphInfo subgraph_info{index, subgraph, shown_operand_set};
+ subgraph_info.label(label);
+ subgraph_info.fillcolor(fillcolor);
+ dot_builder.addSubgraph(subgraph_info);
+
+ // Set fillcolor of all operations in the subgraph
+ for (const auto &op : subgraph.operations())
+ {
+ auto found = operation_nodes.find(op.index);
+ if (found != operation_nodes.end())
+ {
+ auto &&op = found->second;
+ op->setAttribute("fillcolor", fillcolor);
+ }
+ }
+ });
+ }
+
+ for (const auto &e : operation_nodes)
+ dot_builder.update(*e.second);
+ for (const auto &e : operand_nodes)
+ dot_builder.update(*e.second);
+
+ // Dump to file
+ {
+ std::string file_name;
+ file_name += tag;
+ file_name += ".dot";
+ std::filebuf fb;
+
+ fb.open(file_name, std::ios::out);
+ std::ostream os(&fb);
+
+ dot_builder.writeDot(os);
+
+ fb.close();
+ }
+}
+
+} // namespace dot
+} // namespace dumper
+} // namespace neurun