Compute Library
 21.05
InPlaceOperationMutator.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-2020 Arm Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
25 
28 
29 namespace arm_compute
30 {
31 namespace graph
32 {
33 namespace
34 {
35 // Check if the output edges of the parent node are separate tensors. If not,
36 // it means the same output is connected to multiple nodes and computations on
37 // these nodes cannot be done in-place.
38 bool output_edges_are_separate_tensors(Graph &g, const Edge *input_edge)
39 {
40  const auto parent_node = input_edge->producer();
41  const auto input_tensor = input_edge->tensor();
42  const auto input_edge_id = input_edge->id();
43 
44  if(parent_node == nullptr)
45  {
46  return false;
47  }
48 
49  const auto output_edges = parent_node->output_edges();
50 
51  // If the output is connected to only one edge, then computations can
52  // be done in-place.
53  if(output_edges.size() == 1)
54  {
55  return true;
56  }
57 
58  return std::all_of(output_edges.begin(),
59  output_edges.end(),
60  [&](const EdgeID & edge_id)
61  {
62  // Skip check on current input edge
63  if(edge_id == input_edge_id)
64  {
65  return true;
66  }
67 
68  auto edge = g.edge(edge_id);
69  return edge->tensor() != input_tensor;
70  });
71 }
72 } // namespace
73 
75 {
76  return "InPlaceOperationMutator";
77 }
78 
80 {
82 }
83 
85 {
86  std::set<NodeType> in_place_nodes =
87  {
93  };
94 
95  // Not interested in the order of nodes
96  for(auto &node : g.nodes())
97  {
98  if(node && in_place_nodes.find(node->type()) != std::end(in_place_nodes))
99  {
100  // Get input edge
101  Edge *input_edge = node->input_edge(0);
102 
103  // Check if parent has a single output if yes then force in place calculation else not
104  if((input_edge != nullptr) && output_edges_are_separate_tensors(g, input_edge))
105  {
106  // Get current and new output tensors
107  auto current_output_tensor = node->output(0);
108  auto new_output_tensor = input_edge->tensor();
109 
110  ARM_COMPUTE_ERROR_ON(current_output_tensor == nullptr || new_output_tensor == nullptr);
111 
112  // Prevent in-place operation if there is an accessor bound to the in-place tensor or quantization info are different
113  if(new_output_tensor->accessor() != nullptr || current_output_tensor->desc().quant_info != new_output_tensor->desc().quant_info)
114  {
115  ARM_COMPUTE_LOG_GRAPH_VERBOSE("Prevented in-place operation as there is an accessor bound to the input tensor or the quantization info are different.\n");
116  }
117  else
118  {
119  ARM_COMPUTE_LOG_GRAPH_VERBOSE("Switching to in-place computation for the node with ID : "
120  << node->id() << " and name : " << node->name() << std::endl);
121  // Update accessor
122  new_output_tensor->set_accessor(current_output_tensor->extract_accessor());
123  // Update output
124  node->set_output_tensor(new_output_tensor->id(), 0);
125  }
126  }
127  }
128  }
129 }
130 } // namespace graph
131 } // namespace arm_compute
Tensor * tensor() const
Returns the tensor associated with this edge.
Definition: Edge.h:116
#define ARM_COMPUTE_ERROR_ON(cond)
If the condition is true then an error message is printed and an exception thrown.
Definition: Error.h:466
Copyright (c) 2017-2021 Arm Limited.
void end(TokenStream &in, bool &valid)
Definition: MLGOParser.cpp:290
unsigned int EdgeID
Definition: Types.h:69
Graph class.
Definition: Graph.h:53
MutationType type() const override
Returns mutation type.
const std::vector< NodeID > & nodes(NodeType type)
Returns graph input nodes.
Definition: Graph.cpp:174
Graph Edge.
Definition: Edge.h:39
const char * name() override
Returns mutator name.
#define ARM_COMPUTE_LOG_GRAPH_VERBOSE(x)
Definition: Logger.h:50
virtual void mutate(Graph &g) override
Walk the graph and perform a specific mutation.