summaryrefslogtreecommitdiff
path: root/runtime/neurun/core/src/ir/Graph.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/neurun/core/src/ir/Graph.cc')
-rw-r--r--runtime/neurun/core/src/ir/Graph.cc551
1 files changed, 0 insertions, 551 deletions
diff --git a/runtime/neurun/core/src/ir/Graph.cc b/runtime/neurun/core/src/ir/Graph.cc
deleted file mode 100644
index a84ebb68b..000000000
--- a/runtime/neurun/core/src/ir/Graph.cc
+++ /dev/null
@@ -1,551 +0,0 @@
-/*
- * 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 "ir/Graph.h"
-
-#include <algorithm>
-#include <bitset>
-#include <sstream>
-
-#include "util/logging.h"
-#include "verifier/Verifier.h"
-#include "cpp14/memory.h"
-#include "ir/operation/LowerInfo.h"
-#include "ir/operand/LowerInfo.h"
-#include "ir/operand/PermuteFactor.h"
-#include "ir/GraphIterator.h"
-#include "operand/Shape4DConvert.h"
-#include "compiler/BackendResolver.h"
-#include "backend/IConfig.h"
-#include "pass/ConstantInsertionPass.h"
-#include "pass/PermutationInsertionPass.h"
-#include "pass/PermutationEliminationPass.h"
-#include "pass/PermutationOperationPass.h"
-
-namespace neurun
-{
-namespace ir
-{
-
-Graph::Graph() = default;
-
-Graph::~Graph(void) = default;
-
-OperandIndex Graph::addOperand(const Shape &shape, const TypeInfo &type)
-{
- return _operands.emplace(shape, type);
-}
-
-OperationIndex Graph::addOperation(std::unique_ptr<Operation> &&node)
-{
- assert(isBuildingPhase());
- return _operations.push(std::move(node));
-}
-
-void Graph::setOperandValue(const OperandIndex &ind, std::unique_ptr<Data> &&data)
-{
- assert(isBuildingPhase());
- assert(_operands.exist(ind));
- _operands.at(ind).data(std::move(data));
-}
-
-void Graph::addInput(const OperandIndex &ind)
-{
- assert(isBuildingPhase());
- _inputs.append(ind);
-}
-
-void Graph::addOutput(const OperandIndex &ind)
-{
- assert(isBuildingPhase());
- _outputs.append(ind);
-}
-
-void Graph::finishBuilding(void)
-{
- assert(isBuildingPhase());
- _phase = Phase::MODEL;
-
- // Initialize operand use-def
- initializeUseDef();
-
- // Call graph verifications for the MODEL phase
- {
- assert(verifier::DAGChecker().verify(*this));
- assert(verifier::EdgeConsistencyChecker().verify(*this));
- }
-}
-
-void Graph::lower(void)
-{
- assert(_phase == Phase::MODEL);
-
- _op_seqs = nnfw::cpp14::make_unique<Subgraphs>();
-
- // Lower
- {
- // operand::LowerInfo holder
- OperandIndexMap<std::unique_ptr<operand::LowerInfo>> operands_lower_info;
-
- _operands.iterate([&](const OperandIndex &index, const Operand &object) {
- operands_lower_info[index] =
- nnfw::cpp14::make_unique<operand::LowerInfo>(operand::asShape4D(object.shape()));
- });
-
- _lower_info_map = nnfw::cpp14::make_unique<LowerInfoMap>();
-
- // Make subgraphs while checking whether a node can be merged into a op_seq.
- makeSubgraphs(operands_lower_info);
-
- _op_seqs->iterate([&](const SubgraphIndex &, OpSequence &subg) {
- assert(subg.operations().size() > 0);
- std::reverse(std::begin(subg.operations()), std::end(subg.operations()));
- });
-
- _op_seqs->dump("merged and sorted operations without permutation");
-
- pass::ConstantInsertionPass ci_pass(*this);
- ci_pass.run();
-
- // Set LowerInfo for each operand from the operand::LowerInfo holder
- manipulateLowerInfo(operands_lower_info);
-
- dumpLowerInfo();
- }
-
- // Run Permutation Passes
- {
- pass::PermutationOperationPass po_pass(*this);
- po_pass.run();
-
- pass::PermutationInsertionPass pi_pass(*this);
- pi_pass.run();
- // Implemented code no longer works.
- // pass::PermutationEliminationPass pe_pass(*this);
- // pe_pass.run();
-
- // TODO merge perm subgraphs if possible
- _op_seqs->dump("merged and sorted operations with permutation");
- }
-
- // Graph verifications for the LOWERED phase
- {
- assert(verifier::DAGChecker().verify(*this));
- assert(verifier::EdgeConsistencyChecker().verify(*this));
- }
-}
-
-void Graph::initializeUseDef()
-{
- operations().iterate([&](const OperationIndex &index, const Operation &node) -> void {
- auto outputs = node.getOutputs();
- for (auto output : outputs)
- {
- operands().at(output).appendDef(index);
- }
-
- auto inputs = node.getInputs();
- for (auto input : inputs)
- {
- operands().at(input).appendUse(index);
- }
- });
-}
-
-const operation::LowerInfo *Graph::getLowerInfo(const SubgraphIndex &subg_index) const
-{
- if (!_lower_info_map)
- return nullptr;
- auto itr = _lower_info_map->operation.find(subg_index);
- if (itr == _lower_info_map->operation.end())
- return nullptr;
- return itr->second.get();
-}
-
-void Graph::setLowerInfo(const SubgraphIndex &subg_index,
- std::unique_ptr<operation::LowerInfo> &&lower_info)
-{
- assert(_lower_info_map);
- _lower_info_map->operation.insert(std::make_pair(subg_index, std::move(lower_info)));
-}
-
-void Graph::removeLowerInfo(const SubgraphIndex &subg_index)
-{
- auto &subg_lower_info = _lower_info_map->operation;
- assert(subg_lower_info.find(subg_index) != subg_lower_info.end());
- for (auto it = subg_lower_info.begin(); it != subg_lower_info.end(); ++it)
- {
- if (it->first == subg_index)
- {
- subg_lower_info.erase(it);
- break;
- }
- }
-}
-
-const operand::LowerInfo *Graph::getLowerInfo(const OperandIndex &index) const
-{
- if (!_lower_info_map)
- return nullptr;
- auto itr = _lower_info_map->operand.find(index);
- if (itr == _lower_info_map->operand.end())
- return nullptr;
- return itr->second.get();
-}
-
-operand::LowerInfo *Graph::getLowerInfo(const OperandIndex &index)
-{
- if (!_lower_info_map)
- return nullptr;
- auto itr = _lower_info_map->operand.find(index);
- if (itr == _lower_info_map->operand.end())
- return nullptr;
- return itr->second.get();
-}
-
-void Graph::setLowerInfo(const OperandIndex &index,
- std::unique_ptr<operand::LowerInfo> &&lower_info)
-{
- assert(_lower_info_map);
- _lower_info_map->operand.insert(std::make_pair(index, std::move(lower_info)));
-}
-
-void Graph::removeLowerInfo(const OperandIndex &index) { _lower_info_map->operand.erase(index); }
-
-void Graph::makeSubgraphs(OperandIndexMap<std::unique_ptr<operand::LowerInfo>> &operands_lower_info)
-{
- // if SUBG_MAX_NODE == 0, no limit on nodes of a op_seq
- const int subg_max_node = util::getConfigInt(util::config::SUBG_MAX_NODE);
- assert(subg_max_node >= 0);
-
- bool is_profiling = util::getConfigBool(util::config::PROFILING_MODE);
- OpSequence *subg = nullptr;
- SubgraphIndex subg_index;
-
- // NOTE: The below method appends nodes while making one op_seq if needed. If something better
- // ways, happy to update this code.
- PostDfsConstIterator{}.iterate(*this, [&](const OperationIndex &node_index,
- const Operation &node) {
- // LowerInfo for in/output operands
- auto backend = _backend_resolver->getBackend(node_index);
-
- // TODO How to get frontend layout of this node from IR
- auto frontend_layout = Layout::NHWC;
- auto backend_layout = frontend_layout;
-
- // The layout of each backend should be set at another place
- // TODO Change setting layout of each backend at another place
- // TODO Remove getting id of backend
- if (backend->config()->id() == "acl_cl" || backend->config()->id() == "acl_neon")
- {
- const std::string acl_layout_str = util::getConfigString(util::config::ACL_LAYOUT);
- if (acl_layout_str == "NHWC")
- {
- backend_layout = Layout::NHWC;
- }
- else if (acl_layout_str == "NCHW")
- {
- backend_layout = Layout::NCHW;
- }
- }
- else if (backend->config()->id() == "srcn")
- {
- const std::string ncnn_layout_str = util::getConfigString(util::config::NCNN_LAYOUT);
- if (ncnn_layout_str == "NHWC")
- {
- backend_layout = Layout::NHWC;
- }
- else if (ncnn_layout_str == "NCHW")
- {
- backend_layout = Layout::NCHW;
- }
- }
- else if (backend->config()->id() == "cpu")
- {
- backend_layout = Layout::NHWC;
- }
-
- for (auto operand : node.getInputs())
- {
- auto &&lower_info = operands_lower_info.at(operand);
- lower_info->addUsePermuteFactor(operand::PermuteFactor{backend, backend_layout});
- }
- for (auto operand : node.getOutputs())
- {
- auto &&lower_info = operands_lower_info.at(operand);
- lower_info->addDefPermuteFactor(operand::PermuteFactor{backend, backend_layout});
- }
-
- bool new_subg =
- (subg == nullptr ||
- (subg_max_node != 0 && subg->operations().size() >= static_cast<size_t>(subg_max_node)));
-
- // for profiling each op_seq must contain just one node,
- // so that we can measure a node separately
- if (new_subg || is_profiling || !mergeable(subg_index, node_index, backend_layout))
- {
- auto new_subg_index = appendFreshSingleOpSubgraph(node_index, node, frontend_layout);
-
- // OpSequence LowerInfo
- setLowerInfo(new_subg_index,
- nnfw::cpp14::make_unique<operation::LowerInfo>(backend, backend_layout));
-
- subg_index = new_subg_index;
- subg = &(_op_seqs->at(new_subg_index));
-
- VERBOSE(Lower) << "SUBG#" << subg_index.value() << " is created for "
- << "NODE#" << node_index.value() << "(" << node.name() << ")" << std::endl;
- }
- else
- {
- subg->appendOperation(node_index, node);
- subg->setInputs(node.getInputs());
-
- VERBOSE(Lower) << "SUBG#" << subg_index.value() << " merges "
- << "NODE#" << node_index.value() << "(" << node.name() << ")" << std::endl;
- }
- });
-}
-
-void Graph::manipulateLowerInfo(
- OperandIndexMap<std::unique_ptr<operand::LowerInfo>> &operands_lower_info)
-{
- const auto default_backend = backend::BackendManager::get().getDefault();
- for (auto index : _inputs)
- {
- // Pick just any one from the uses, here the first one is chosen
- // For the other uses, Permute operations will be inserted later
- auto &&lower_info = operands_lower_info.at(index);
- assert(lower_info->use_factors().size() > 0);
- lower_info->addDefPermuteFactor(*lower_info->use_factors().begin());
- }
- for (auto index : _outputs)
- {
- auto &&lower_info = operands_lower_info.at(index);
- if (_operands.at(index).isConstant())
- {
- lower_info->addDefPermuteFactor(operand::PermuteFactor{
- default_backend,
- Layout::NHWC // TODO Get frontend layout of this node from IR
- });
- }
- }
-
- // Set LowerInfo for each operand from the operand::LowerInfo holder
- _operands.iterate([&](const OperandIndex &index, Operand &) {
- setLowerInfo(index, std::move(operands_lower_info[index]));
- });
-}
-
-void Graph::dumpLowerInfo()
-{
- if (::neurun::util::logging::ctx.enabled() == false)
- return;
-
- std::map<uint32_t, std::string> dumps;
-
- _operands.iterate([&](const OperandIndex &index, Operand &object) {
- std::stringstream sstream;
- if (!getLowerInfo(index)->def_factors().empty() || !getLowerInfo(index)->use_factors().empty())
- {
- auto factors_to_string = [](const operand::PermuteFactorSet &factors) {
- std::string str;
- for (auto factor : factors)
- {
- str += factor.backend()->config()->id();
- str += "(" + to_string(factor.layout()) + ")";
- str += " ";
- }
- return "{ " + str + "}";
- };
-
- auto operation_index_to_string = [](const OperationIndexList &operations) {
- std::string str;
- for (auto op : operations.list())
- {
- str += std::to_string(op.value());
- str += " ";
- }
- return "{ " + str + "}";
- };
-
- const auto lower_info = getLowerInfo(index);
- const auto &shape = object.shape();
- const auto &lower_shape = lower_info->shape();
- std::string def_ops = operation_index_to_string(object.getDef());
- std::string use_ops = operation_index_to_string(object.getUses());
- std::string def_layouts = factors_to_string(lower_info->def_factors());
- std::string use_layouts = factors_to_string(lower_info->use_factors());
- sstream << "Operand #" << index.value() << " LowerInfo" << std::endl;
- sstream << " - Shape : { " << (shape.rank() > 0 ? shape.dim(0) : 0) << " "
- << (shape.rank() > 1 ? shape.dim(1) : 0) << " "
- << (shape.rank() > 2 ? shape.dim(2) : 0) << " "
- << (shape.rank() > 3 ? shape.dim(3) : 0) << " "
- << "}" << std::endl;
- sstream << " - Def Operations : " << def_ops << std::endl;
- sstream << " - Use Operations : " << use_ops << std::endl;
- sstream << " - Lower Info" << std::endl;
- sstream << " - 4D Shape (NHWC) : { " << lower_shape.n() << " " << lower_shape.h() << " "
- << lower_shape.w() << " " << lower_shape.c() << " "
- << "}" << std::endl;
- sstream << " - Def Backends : " << def_layouts << std::endl;
- sstream << " - Use Backends : " << use_layouts << std::endl;
- }
- dumps.emplace(index.value(), sstream.str());
- });
-
- for (const auto &e : dumps)
- {
- if (!e.second.empty())
- {
- VERBOSE(Lower) << e.second;
- }
- }
-}
-
-bool Graph::mergeable(const SubgraphIndex &subg_index, const OperationIndex &node_index,
- Layout layout)
-{
- // Are they mergeable?
- // 1. the same backend id and layout?
- // 2. Is op_seq or node branched?
- // 3. if 1 is true, the subg and a node are connected?
- const auto &subg = _op_seqs->at(subg_index);
- const auto &node = _operations.at(node_index);
-
- // The same backend id and layout?
- {
- const auto subg_backend_layout = getLowerInfo(subg_index)->layout();
- const auto &subg_backend_id = getLowerInfo(subg_index)->backend()->config()->id();
- const auto &node_backend_id = _backend_resolver->getBackend(node_index)->config()->id();
- VERBOSE(Lower) << "SUBG#" << subg_index.value() << " { " << subg_backend_id << "("
- << to_string(subg_backend_layout) << ") } "
- << " NODE#" << node_index.value() << " (" << node.name() << ") { "
- << node_backend_id << "(" << to_string(layout) << ") } " << std::endl;
- if (subg_backend_id != node_backend_id || subg_backend_layout != layout)
- return false;
- }
-
- // Branched?
- {
- std::unordered_set<OperationIndex> branched_set;
-
- // Check for branching up
- const auto &inputs = subg.getInputs();
- for (const auto &input : inputs)
- {
- const auto &input_obj = _operands.at(input);
- for (const auto &def : input_obj.getDef().list())
- {
- branched_set.insert(def);
- if (branched_set.size() > 1)
- {
- return false;
- }
- }
- }
- branched_set.clear();
-
- // Check for branching down
- const auto &outputs = node.getOutputs();
- for (const auto &output : outputs)
- {
- const auto &output_obj = _operands.at(output);
- for (const auto &use : output_obj.getUses().list())
- {
- branched_set.insert(use);
- if (branched_set.size() > 1)
- {
- return false;
- }
- }
- }
- }
-
- // Connected?
- // an input of one node is an output of the other node? or vice-versa?
- {
- const auto &node_inputs = node.getInputs();
- const auto &node_outputs = node.getOutputs();
-
- // subg's operations are in order so that we just check the first and the last
- std::vector<Element> subg_ops{subg.operations()[0]};
- if (subg.operations().size() > 1)
- subg_ops.emplace_back(subg.operations()[subg.operations().size() - 1]);
-
- for (const auto &elem : subg_ops)
- {
- const auto &n_index = elem.index;
- const auto &n = *elem.node;
-
- // node's output == subg's input?
- const auto &n_inputs = n.getInputs();
- for (auto input : n_inputs)
- {
- if (node_outputs.contains(input))
- {
- VERBOSE(Lower) << "SUBG#" << subg_index.value() << " 's NODE#" << n_index.value() << "("
- << n.name() << ") is connected to NODE#" << node_index.value() << "("
- << node.name() << ")" << std::endl;
- return true;
- }
- }
-
- // node's input == subg's output?
- const auto &n_outputs = n.getOutputs();
- for (auto output : n_outputs)
- {
- if (node_inputs.contains(output))
- {
- VERBOSE(Lower) << "SUBG#" << subg_index.value() << " 's NODE#" << n_index.value() << " ("
- << n.name() << ") is connected to NODE#" << node_index.value()
- << std::endl;
- return true;
- }
- }
- }
-
- VERBOSE(Lower) << "SUBG#" << subg_index.value() << " is not connected to NODE#"
- << node_index.value() << "(" << node.name() << ")" << std::endl;
- }
-
- return false;
-}
-
-SubgraphIndex Graph::appendFreshSingleOpSubgraph(const OperationIndex &node_index,
- const Operation &node, Layout layout)
-{
- // Create a fresh op_seq with one operation, and append it to subgraphs
- // Create a fresh op_seq
- auto subg = nnfw::cpp14::make_unique<OpSequence>(layout);
-
- // Add an operation
- subg->appendOperation(node_index, node);
-
- // Update input/output
- subg->setOutputs(node.getOutputs());
- subg->setInputs(node.getInputs());
-
- return _op_seqs->emplace(std::move(subg));
-}
-
-void Graph::setBackendResolver(std::unique_ptr<compiler::BackendResolver> &&br)
-{
- _backend_resolver = std::move(br);
-}
-
-} // namespace ir
-} // namespace neurun