blob: 7dddb1cd9a1e9770a4d866fc4b3cd596d417b7aa [file] [log] [blame]
Anthony Barbier2a07e182017-08-04 18:20:27 +01001/*
2 * Copyright (c) 2017 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 */
24#include "arm_compute/graph/Graph.h"
25
26#include "arm_compute/graph/CL/CLMap.h"
27#include "arm_compute/graph/CL/CLUnmap.h"
28#include "arm_compute/graph/INode.h"
29#include "arm_compute/graph/Tensor.h"
30#include "arm_compute/runtime/CL/CLTensor.h"
31#include "arm_compute/runtime/Tensor.h"
32
33using namespace arm_compute::graph;
34
35struct Stage
36{
37 Tensor *_input;
38 Tensor *_output;
39 std::unique_ptr<arm_compute::IFunction> _function;
40};
41
42struct Graph::Private
43{
44public:
45 /** Finalizes the current node's configuration
46 *
47 * @param _next_hint Device execution hint
48 */
Georgios Pinitasff421f22017-10-04 16:53:58 +010049 void configure(GraphHints _next_hints);
Anthony Barbier2a07e182017-08-04 18:20:27 +010050
Georgios Pinitasff421f22017-10-04 16:53:58 +010051 GraphContext _ctx{};
Anthony Barbier2a07e182017-08-04 18:20:27 +010052 std::vector<Stage> _pipeline{};
53 std::vector<std::unique_ptr<Tensor>> _tensors{};
54 std::vector<std::unique_ptr<INode>> _nodes{};
Georgios Pinitasff421f22017-10-04 16:53:58 +010055 GraphHints _current_hints{};
56 GraphHints _next_hints{};
Anthony Barbier2a07e182017-08-04 18:20:27 +010057 std::unique_ptr<Tensor> _graph_input{ nullptr };
58 std::unique_ptr<Tensor> _graph_output{ nullptr };
59 std::unique_ptr<INode> _current_node{ nullptr };
60 Tensor *_current_output{ nullptr };
Anthony Barbier2a07e182017-08-04 18:20:27 +010061
62private:
Georgios Pinitasff421f22017-10-04 16:53:58 +010063 Tensor *_current_input{ nullptr };
64 GraphHints _previous_hints{};
Anthony Barbier2a07e182017-08-04 18:20:27 +010065};
66
67Graph::~Graph() //NOLINT
68{
69 //Can't use =default because the destructor must be defined after Graph::Private's definition
70}
71
72Graph::Graph()
73 : _pimpl{ new Private() }
74{
75}
76
77void Graph::run()
78{
79 while(true)
80 {
81 if(!_pimpl->_graph_input->call_accessor())
82 {
83 return;
84 }
85
86 for(auto &stage : _pimpl->_pipeline)
87 {
88 stage._function->run();
89 }
90
91 if(!_pimpl->_graph_output->call_accessor())
92 {
93 return;
94 }
95 }
96}
97
98//Finalize current node's configuration
Georgios Pinitasff421f22017-10-04 16:53:58 +010099void Graph::Private::configure(GraphHints _next_hints)
Anthony Barbier2a07e182017-08-04 18:20:27 +0100100{
101 ARM_COMPUTE_ERROR_ON(_current_node == nullptr);
102 ARM_COMPUTE_ERROR_ON(_graph_input == nullptr);
103
104 // Is it the first node of the graph ?
105 if(_current_input == nullptr)
106 {
Georgios Pinitasff421f22017-10-04 16:53:58 +0100107 _graph_input->set_target(_current_hints.target_hint());
108 _current_input = _graph_input.get();
109 _previous_hints = _current_hints; // For the first node just assume the previous node was of the same type as this one
Anthony Barbier2a07e182017-08-04 18:20:27 +0100110 }
111
112 //Automatic output configuration ?
113 if(_current_output == nullptr)
114 {
115 _tensors.push_back(arm_compute::support::cpp14::make_unique<Tensor>(TensorInfo()));
116 _current_output = _tensors.back().get();
117 }
118
119 // If either the writer or reader node needs OpenCL then use OpenCL memory:
Georgios Pinitasff421f22017-10-04 16:53:58 +0100120 if((_next_hints.target_hint() == TargetHint::OPENCL || _current_hints.target_hint() == TargetHint::OPENCL))
Anthony Barbier2a07e182017-08-04 18:20:27 +0100121 {
Georgios Pinitasff421f22017-10-04 16:53:58 +0100122 _current_output->set_target(TargetHint::OPENCL);
Anthony Barbier2a07e182017-08-04 18:20:27 +0100123 }
124 else
125 {
Georgios Pinitasff421f22017-10-04 16:53:58 +0100126 _current_output->set_target(TargetHint::NEON);
Anthony Barbier2a07e182017-08-04 18:20:27 +0100127 }
128
Georgios Pinitasff421f22017-10-04 16:53:58 +0100129 // Update ctx and instantiate node
130 _ctx.hints() = _current_hints;
131 std::unique_ptr<arm_compute::IFunction> func = _current_node->instantiate_node(_ctx, _current_input->tensor(), _current_output->tensor());
Anthony Barbier2a07e182017-08-04 18:20:27 +0100132 _current_input->allocate();
133
Georgios Pinitasff421f22017-10-04 16:53:58 +0100134 // Map input if needed
135 if(_current_input->target() == TargetHint::OPENCL)
Anthony Barbier2a07e182017-08-04 18:20:27 +0100136 {
Georgios Pinitasff421f22017-10-04 16:53:58 +0100137 if(_previous_hints.target_hint() == TargetHint::NEON)
Anthony Barbier2a07e182017-08-04 18:20:27 +0100138 {
Georgios Pinitasff421f22017-10-04 16:53:58 +0100139 ARM_COMPUTE_ERROR_ON(_current_hints.target_hint() == TargetHint::NEON);
Anthony Barbier2a07e182017-08-04 18:20:27 +0100140 _pipeline.push_back({ _current_input, _current_input, arm_compute::support::cpp14::make_unique<CLUnmap>(_current_input) });
141 }
Georgios Pinitasff421f22017-10-04 16:53:58 +0100142 if(_current_hints.target_hint() == TargetHint::NEON)
Anthony Barbier2a07e182017-08-04 18:20:27 +0100143 {
Georgios Pinitasff421f22017-10-04 16:53:58 +0100144 ARM_COMPUTE_ERROR_ON(_previous_hints.target_hint() == TargetHint::NEON);
Anthony Barbier2a07e182017-08-04 18:20:27 +0100145 _pipeline.push_back({ _current_input, _current_input, arm_compute::support::cpp14::make_unique<CLMap>(_current_input, true) });
146 }
147 }
148
149 _pipeline.push_back({ _current_input, _current_output, std::move(func) });
150
151 _current_input = _current_output;
152 _current_output = nullptr;
Georgios Pinitasff421f22017-10-04 16:53:58 +0100153 std::swap(_previous_hints, _current_hints);
154 std::swap(_current_hints, _next_hints);
Anthony Barbier2a07e182017-08-04 18:20:27 +0100155}
156
Anthony Barbier2a07e182017-08-04 18:20:27 +0100157void Graph::add_node(std::unique_ptr<INode> node)
158{
159 ARM_COMPUTE_ERROR_ON_MSG(_pimpl->_graph_input == nullptr, "The graph's input must be set before the first node is added");
160 ARM_COMPUTE_ERROR_ON_MSG(_pimpl->_graph_output != nullptr, "Nothing can be added after the output tensor");
161 //Trigger the creation of the current Node:
162
Georgios Pinitasff421f22017-10-04 16:53:58 +0100163 GraphHints _next_hints = _pimpl->_next_hints;
164 _next_hints.set_target_hint(node->override_target_hint(_pimpl->_next_hints.target_hint()));
165 ARM_COMPUTE_ERROR_ON(_next_hints.target_hint() == TargetHint::DONT_CARE);
Anthony Barbier2a07e182017-08-04 18:20:27 +0100166 if(_pimpl->_current_node)
167 {
168 //Finalize the previous Node:
Georgios Pinitasff421f22017-10-04 16:53:58 +0100169 _pimpl->configure(_pimpl->_next_hints);
Anthony Barbier2a07e182017-08-04 18:20:27 +0100170 }
171 else
172 {
Georgios Pinitasff421f22017-10-04 16:53:58 +0100173 // If that's the first node then use the same TargetHint before and after the node.
174 _pimpl->_current_hints = _next_hints;
Anthony Barbier2a07e182017-08-04 18:20:27 +0100175 }
176 if(_pimpl->_current_node)
177 {
178 _pimpl->_nodes.push_back(std::move(_pimpl->_current_node));
179 }
180 _pimpl->_current_node = std::move(node);
181}
Anthony Barbier2a07e182017-08-04 18:20:27 +0100182
183//Add a tensor with an Accessor (i.e either the input or output of the graph)
184void Graph::add_tensor(std::unique_ptr<Tensor> tensor)
185{
186 // If it's the first Tensor added then it will be the input of the Graph.
187 if(_pimpl->_graph_input == nullptr)
188 {
189 ARM_COMPUTE_ERROR_ON(_pimpl->_graph_output != nullptr);
190 ARM_COMPUTE_ERROR_ON(_pimpl->_current_node != nullptr);
191 _pimpl->_graph_input = std::move(tensor);
192 }
193 else
194 {
195 // Else it will be the output of the Graph
196 ARM_COMPUTE_ERROR_ON(_pimpl->_graph_output != nullptr);
197 ARM_COMPUTE_ERROR_ON(_pimpl->_current_node == nullptr);
198 _pimpl->_graph_output = std::move(tensor);
199 _pimpl->_current_output = _pimpl->_graph_output.get();
200
201 // Finalize the graph by configuring the last Node of the graph:
Georgios Pinitasff421f22017-10-04 16:53:58 +0100202 _pimpl->configure(_pimpl->_current_hints); // Ignore _next_hint as this is the last node, and just use the same hint as before this node.
Anthony Barbier2a07e182017-08-04 18:20:27 +0100203 _pimpl->_graph_output->allocate();
204 }
205}
206
207void Graph::set_temp(TensorInfo &&tmp)
208{
209 ARM_COMPUTE_ERROR_ON(_pimpl->_graph_input == nullptr);
210 ARM_COMPUTE_ERROR_ON(_pimpl->_graph_output != nullptr);
211 ARM_COMPUTE_ERROR_ON_MSG(_pimpl->_current_output != nullptr, "TensorInfo for temporary tensor already set");
212
213 _pimpl->_tensors.push_back(arm_compute::support::cpp14::make_unique<Tensor>(std::move(tmp)));
214 _pimpl->_current_output = _pimpl->_tensors.back().get();
215}
216
Georgios Pinitasff421f22017-10-04 16:53:58 +0100217GraphHints &Graph::hints()
218{
219 return _pimpl->_next_hints;
220}
221
Anthony Barbier2a07e182017-08-04 18:20:27 +0100222Graph &arm_compute::graph::operator<<(Graph &graph, TensorInfo &&info)
223{
224 graph.set_temp(std::move(info));
225 return graph;
226}
227
228Graph &arm_compute::graph::operator<<(Graph &graph, Tensor &&tensor)
229{
230 graph.add_tensor(arm_compute::support::cpp14::make_unique<Tensor>(std::move(tensor)));
231 return graph;
232}
233
Georgios Pinitasff421f22017-10-04 16:53:58 +0100234Graph &arm_compute::graph::operator<<(Graph &graph, TargetHint target_hint)
Anthony Barbier2a07e182017-08-04 18:20:27 +0100235{
Georgios Pinitasff421f22017-10-04 16:53:58 +0100236 graph.hints().set_target_hint(target_hint);
237 return graph;
238}
239
240Graph &arm_compute::graph::operator<<(Graph &graph, ConvolutionMethodHint conv_method_hint)
241{
242 graph.hints().set_convolution_method_hint(conv_method_hint);
Anthony Barbier2a07e182017-08-04 18:20:27 +0100243 return graph;
244}