blob: 5be3706cfedd6e22e523f9aa66a94f91281bf0ec [file] [log] [blame]
Georgios Pinitasd8734b52017-12-22 15:27:52 +00001/*
Michele Di Giorgiod9eaf612020-07-08 11:12:57 +01002 * Copyright (c) 2018-2020 Arm Limited.
Georgios Pinitasd8734b52017-12-22 15:27:52 +00003 *
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 */
Georgios Pinitasd9eb2752018-04-03 13:44:29 +010024#include "arm_compute/graph/detail/ExecutionHelpers.h"
Georgios Pinitasd8734b52017-12-22 15:27:52 +000025
Georgios Pinitasd9eb2752018-04-03 13:44:29 +010026#include "arm_compute/graph/Graph.h"
27#include "arm_compute/graph/GraphContext.h"
28#include "arm_compute/graph/GraphManager.h"
29#include "arm_compute/graph/Tensor.h"
Giorgio Arena6e9d0e02020-01-03 15:02:04 +000030#include "arm_compute/graph/Utils.h"
Georgios Pinitasd9eb2752018-04-03 13:44:29 +010031#include "arm_compute/graph/backends/BackendRegistry.h"
Georgios Pinitasd8734b52017-12-22 15:27:52 +000032
33namespace arm_compute
34{
Georgios Pinitasd9eb2752018-04-03 13:44:29 +010035namespace graph
Georgios Pinitasd8734b52017-12-22 15:27:52 +000036{
37namespace detail
38{
Georgios Pinitascac13b12018-04-27 19:07:19 +010039void validate_all_nodes(Graph &g)
40{
41 auto &nodes = g.nodes();
42
43 // Create tasks
44 for(auto &node : nodes)
45 {
46 if(node != nullptr)
47 {
Anthony Barbier890ad1b2018-08-22 13:44:36 +010048 Target assigned_target = node->assigned_target();
49 backends::IDeviceBackend &backend = backends::BackendRegistry::get().get_backend(assigned_target);
50 Status status = backend.validate_node(*node);
Georgios Pinitascac13b12018-04-27 19:07:19 +010051 ARM_COMPUTE_ERROR_ON_MSG(!bool(status), status.error_description().c_str());
52 }
53 }
54}
55
Georgios Pinitasd8734b52017-12-22 15:27:52 +000056void configure_all_tensors(Graph &g)
57{
58 auto &tensors = g.tensors();
59
60 for(auto &tensor : tensors)
61 {
Georgios Pinitas2a2db592018-08-15 12:14:46 +010062 if(tensor && tensor->handle() == nullptr)
Georgios Pinitasd8734b52017-12-22 15:27:52 +000063 {
Anthony Barbier890ad1b2018-08-22 13:44:36 +010064 Target target = tensor->desc().target;
65 backends::IDeviceBackend &backend = backends::BackendRegistry::get().get_backend(target);
66 std::unique_ptr<ITensorHandle> handle = backend.create_tensor(*tensor);
67 ARM_COMPUTE_ERROR_ON_MSG(!handle, "Couldn't create backend handle!");
Georgios Pinitasd8734b52017-12-22 15:27:52 +000068 tensor->set_handle(std::move(handle));
69 }
70 }
71}
72
Georgios Pinitase0437672018-05-02 14:07:55 +010073void allocate_all_input_tensors(INode &node)
74{
75 for(unsigned int i = 0; i < node.num_inputs(); ++i)
76 {
77 Tensor *tensor = node.input(i);
78 if(tensor != nullptr && !tensor->bound_edges().empty())
79 {
80 ARM_COMPUTE_ERROR_ON_MSG(!tensor->handle(), "Tensor handle is not configured!");
81 tensor->handle()->allocate();
82 }
83 }
84}
85
86void allocate_all_output_tensors(INode &node)
87{
88 for(unsigned int i = 0; i < node.num_outputs(); ++i)
89 {
90 Tensor *tensor = node.output(i);
91 if(tensor != nullptr && !tensor->bound_edges().empty())
92 {
93 ARM_COMPUTE_ERROR_ON_MSG(!tensor->handle(), "Tensor handle is not configured!");
94 tensor->handle()->allocate();
95 }
96 }
97}
98
99void allocate_const_tensors(Graph &g)
100{
101 for(auto &node : g.nodes())
102 {
103 if(node != nullptr)
104 {
105 switch(node->type())
106 {
107 case NodeType::Const:
108 case NodeType::Input:
109 allocate_all_output_tensors(*node);
110 break;
111 case NodeType::Output:
112 allocate_all_input_tensors(*node);
113 default:
114 break;
115 }
116 }
117 }
118}
119
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000120void allocate_all_tensors(Graph &g)
121{
122 auto &tensors = g.tensors();
123
124 for(auto &tensor : tensors)
125 {
Georgios Pinitase0437672018-05-02 14:07:55 +0100126 if(tensor && !tensor->bound_edges().empty() && tensor->handle() != nullptr && tensor->handle()->tensor().info()->is_resizable() && tensor->handle()->tensor().is_used())
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000127 {
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000128 tensor->handle()->allocate();
129 }
130 }
131}
132
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100133ExecutionWorkload configure_all_nodes(Graph &g, GraphContext &ctx, const std::vector<NodeID> &node_order)
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000134{
135 ExecutionWorkload workload;
Georgios Pinitase0437672018-05-02 14:07:55 +0100136 workload.graph = &g;
Georgios Pinitas3d1489d2018-05-03 20:47:16 +0100137 workload.ctx = &ctx;
138
Georgios Pinitas3ba0ab12018-12-12 19:01:46 +0000139 // Reserve memory for tasks
140 workload.tasks.reserve(node_order.size());
141
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000142 // Create tasks
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100143 for(auto &node_id : node_order)
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000144 {
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100145 auto node = g.node(node_id);
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000146 if(node != nullptr)
147 {
Anthony Barbier890ad1b2018-08-22 13:44:36 +0100148 Target assigned_target = node->assigned_target();
149 backends::IDeviceBackend &backend = backends::BackendRegistry::get().get_backend(assigned_target);
150 std::unique_ptr<IFunction> func = backend.configure_node(*node, ctx);
Giorgio Arena6e9d0e02020-01-03 15:02:04 +0000151 if(func != nullptr || is_utility_node(node))
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000152 {
Georgios Pinitas3ba0ab12018-12-12 19:01:46 +0000153 workload.tasks.emplace_back(ExecutionTask(std::move(func), node));
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000154 }
155 }
156 }
157
158 // Add inputs and outputs
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100159 for(auto &node : g.nodes())
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000160 {
161 if(node != nullptr && node->type() == NodeType::Input)
162 {
163 workload.inputs.push_back(node->output(0));
164 }
165
166 if(node != nullptr && node->type() == NodeType::Output)
167 {
168 workload.outputs.push_back(node->input(0));
169 continue;
170 }
171 }
172
173 return workload;
174}
175
Georgios Pinitas1562be32018-03-08 19:09:19 +0000176void release_unused_tensors(Graph &g)
177{
178 for(auto &tensor : g.tensors())
179 {
180 if(tensor != nullptr && tensor->handle() != nullptr)
181 {
182 tensor->handle()->release_if_unused();
183 }
184 }
185}
186
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000187void call_tensor_accessor(Tensor *tensor)
188{
189 ARM_COMPUTE_ERROR_ON(!tensor);
190 tensor->call_accessor();
191}
192
193void call_all_const_node_accessors(Graph &g)
194{
195 auto &nodes = g.nodes();
196
197 for(auto &node : nodes)
198 {
Sheri Zhang747a2c62020-08-24 14:10:44 +0100199 if(node != nullptr && node->type() == NodeType::Const && node->num_outputs())
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000200 {
Sheri Zhang747a2c62020-08-24 14:10:44 +0100201 if(!node->output(0)->bound_edges().empty())
202 {
203 call_tensor_accessor(node->output(0));
204 }
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000205 }
206 }
207}
208
Georgios Pinitas12be7ab2018-07-03 12:06:23 +0100209bool call_all_input_node_accessors(ExecutionWorkload &workload)
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000210{
Michele Di Giorgioefc4a2d2019-03-12 12:33:29 +0000211 bool is_valid = true;
212 std::for_each(std::begin(workload.inputs), std::end(workload.inputs), [&](Tensor * input_tensor)
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000213 {
Michele Di Giorgioefc4a2d2019-03-12 12:33:29 +0000214 bool valid_input = (input_tensor != nullptr) && input_tensor->call_accessor();
215 is_valid = is_valid && valid_input;
Georgios Pinitas12be7ab2018-07-03 12:06:23 +0100216 });
Michele Di Giorgioefc4a2d2019-03-12 12:33:29 +0000217 return is_valid;
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000218}
219
Georgios Pinitase0437672018-05-02 14:07:55 +0100220void prepare_all_tasks(ExecutionWorkload &workload)
221{
222 ARM_COMPUTE_ERROR_ON(workload.graph == nullptr);
223 for(auto &task : workload.tasks)
224 {
225 task.prepare();
226 release_unused_tensors(*workload.graph);
227 }
228}
229
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000230void call_all_tasks(ExecutionWorkload &workload)
231{
Georgios Pinitas3d1489d2018-05-03 20:47:16 +0100232 ARM_COMPUTE_ERROR_ON(workload.ctx == nullptr);
233
234 // Acquire memory for the transition buffers
235 for(auto &mm_ctx : workload.ctx->memory_managers())
236 {
237 if(mm_ctx.second.cross_group != nullptr)
238 {
239 mm_ctx.second.cross_group->acquire();
240 }
241 }
242
243 // Execute tasks
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000244 for(auto &task : workload.tasks)
245 {
246 task();
247 }
Georgios Pinitas3d1489d2018-05-03 20:47:16 +0100248
249 // Release memory for the transition buffers
250 for(auto &mm_ctx : workload.ctx->memory_managers())
251 {
252 if(mm_ctx.second.cross_group != nullptr)
253 {
254 mm_ctx.second.cross_group->release();
255 }
256 }
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000257}
258
Georgios Pinitas12be7ab2018-07-03 12:06:23 +0100259bool call_all_output_node_accessors(ExecutionWorkload &workload)
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000260{
Georgios Pinitas12be7ab2018-07-03 12:06:23 +0100261 bool is_valid = true;
262 std::for_each(std::begin(workload.outputs), std::end(workload.outputs), [&](Tensor * output_tensor)
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000263 {
Pablo Tello32521432018-11-15 14:43:10 +0000264 bool valid_output = (output_tensor != nullptr) && output_tensor->call_accessor();
265 is_valid = is_valid && valid_output;
Georgios Pinitas12be7ab2018-07-03 12:06:23 +0100266 });
267
268 return is_valid;
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000269}
270} // namespace detail
Georgios Pinitasd9eb2752018-04-03 13:44:29 +0100271} // namespace graph
Anthony Barbier890ad1b2018-08-22 13:44:36 +0100272} // namespace arm_compute