diff options
Diffstat (limited to 'runtimes/neurun/core/src/dumper/dot/DotDumper.cc')
-rw-r--r-- | runtimes/neurun/core/src/dumper/dot/DotDumper.cc | 198 |
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 |