blob: 6157b7fecf76915905b3b157a1776f15be9343ba [file] [log] [blame]
Georgios Pinitasd8734b52017-12-22 15:27:52 +00001/*
2 * Copyright (c) 2018 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 */
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"
30#include "arm_compute/graph/backends/BackendRegistry.h"
Georgios Pinitasd8734b52017-12-22 15:27:52 +000031
32namespace arm_compute
33{
Georgios Pinitasd9eb2752018-04-03 13:44:29 +010034namespace graph
Georgios Pinitasd8734b52017-12-22 15:27:52 +000035{
36namespace detail
37{
Georgios Pinitascac13b12018-04-27 19:07:19 +010038void validate_all_nodes(Graph &g)
39{
40 auto &nodes = g.nodes();
41
42 // Create tasks
43 for(auto &node : nodes)
44 {
45 if(node != nullptr)
46 {
47 Target assigned_target = node->assigned_target();
48 auto backend = backends::BackendRegistry::get().find_backend(assigned_target);
49 ARM_COMPUTE_ERROR_ON_MSG(!backend, "Requested backend doesn't exist!");
50 Status status = backend->validate_node(*node);
51 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 {
64 Target target = tensor->desc().target;
65 auto backend = backends::BackendRegistry::get().find_backend(target);
66 ARM_COMPUTE_ERROR_ON_MSG(!backend, "Requested backend doesn't exist!");
67 auto handle = backend->create_tensor(*tensor);
68 ARM_COMPUTE_ERROR_ON_MSG(!backend, "Couldn't create backend handle!");
69 tensor->set_handle(std::move(handle));
70 }
71 }
72}
73
Georgios Pinitase0437672018-05-02 14:07:55 +010074void allocate_all_input_tensors(INode &node)
75{
76 for(unsigned int i = 0; i < node.num_inputs(); ++i)
77 {
78 Tensor *tensor = node.input(i);
79 if(tensor != nullptr && !tensor->bound_edges().empty())
80 {
81 ARM_COMPUTE_ERROR_ON_MSG(!tensor->handle(), "Tensor handle is not configured!");
82 tensor->handle()->allocate();
83 }
84 }
85}
86
87void allocate_all_output_tensors(INode &node)
88{
89 for(unsigned int i = 0; i < node.num_outputs(); ++i)
90 {
91 Tensor *tensor = node.output(i);
92 if(tensor != nullptr && !tensor->bound_edges().empty())
93 {
94 ARM_COMPUTE_ERROR_ON_MSG(!tensor->handle(), "Tensor handle is not configured!");
95 tensor->handle()->allocate();
96 }
97 }
98}
99
100void allocate_const_tensors(Graph &g)
101{
102 for(auto &node : g.nodes())
103 {
104 if(node != nullptr)
105 {
106 switch(node->type())
107 {
108 case NodeType::Const:
109 case NodeType::Input:
110 allocate_all_output_tensors(*node);
111 break;
112 case NodeType::Output:
113 allocate_all_input_tensors(*node);
114 default:
115 break;
116 }
117 }
118 }
119}
120
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000121void allocate_all_tensors(Graph &g)
122{
123 auto &tensors = g.tensors();
124
125 for(auto &tensor : tensors)
126 {
Georgios Pinitase0437672018-05-02 14:07:55 +0100127 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 +0000128 {
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000129 tensor->handle()->allocate();
130 }
131 }
132}
133
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100134ExecutionWorkload configure_all_nodes(Graph &g, GraphContext &ctx, const std::vector<NodeID> &node_order)
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000135{
136 ExecutionWorkload workload;
Georgios Pinitase0437672018-05-02 14:07:55 +0100137 workload.graph = &g;
Georgios Pinitas3d1489d2018-05-03 20:47:16 +0100138 workload.ctx = &ctx;
139
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000140 // Create tasks
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100141 for(auto &node_id : node_order)
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000142 {
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100143 auto node = g.node(node_id);
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000144 if(node != nullptr)
145 {
146 Target assigned_target = node->assigned_target();
147 auto backend = backends::BackendRegistry::get().find_backend(assigned_target);
148 ARM_COMPUTE_ERROR_ON_MSG(!backend, "Requested backend doesn't exist!");
149 auto func = backend->configure_node(*node, ctx);
150 if(func != nullptr)
151 {
152 ExecutionTask task;
153 task.task = std::move(func);
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100154 task.node = node;
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000155 workload.tasks.push_back(std::move(task));
156 }
157 }
158 }
159
160 // Add inputs and outputs
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100161 for(auto &node : g.nodes())
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000162 {
163 if(node != nullptr && node->type() == NodeType::Input)
164 {
165 workload.inputs.push_back(node->output(0));
166 }
167
168 if(node != nullptr && node->type() == NodeType::Output)
169 {
170 workload.outputs.push_back(node->input(0));
171 continue;
172 }
173 }
174
175 return workload;
176}
177
Georgios Pinitas1562be32018-03-08 19:09:19 +0000178void release_unused_tensors(Graph &g)
179{
180 for(auto &tensor : g.tensors())
181 {
182 if(tensor != nullptr && tensor->handle() != nullptr)
183 {
184 tensor->handle()->release_if_unused();
185 }
186 }
187}
188
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000189void call_tensor_accessor(Tensor *tensor)
190{
191 ARM_COMPUTE_ERROR_ON(!tensor);
192 tensor->call_accessor();
193}
194
195void call_all_const_node_accessors(Graph &g)
196{
197 auto &nodes = g.nodes();
198
199 for(auto &node : nodes)
200 {
201 if(node != nullptr && node->type() == NodeType::Const)
202 {
203 call_tensor_accessor(node->output(0));
204 }
205 }
206}
207
Georgios Pinitas12be7ab2018-07-03 12:06:23 +0100208bool call_all_input_node_accessors(ExecutionWorkload &workload)
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000209{
Georgios Pinitas12be7ab2018-07-03 12:06:23 +0100210 return !std::any_of(std::begin(workload.inputs), std::end(workload.inputs), [](Tensor * input_tensor)
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000211 {
Georgios Pinitas12be7ab2018-07-03 12:06:23 +0100212 return (input_tensor == nullptr) || !input_tensor->call_accessor();
213 });
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000214}
215
Georgios Pinitase0437672018-05-02 14:07:55 +0100216void prepare_all_tasks(ExecutionWorkload &workload)
217{
218 ARM_COMPUTE_ERROR_ON(workload.graph == nullptr);
219 for(auto &task : workload.tasks)
220 {
221 task.prepare();
222 release_unused_tensors(*workload.graph);
223 }
224}
225
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000226void call_all_tasks(ExecutionWorkload &workload)
227{
Georgios Pinitas3d1489d2018-05-03 20:47:16 +0100228 ARM_COMPUTE_ERROR_ON(workload.ctx == nullptr);
229
230 // Acquire memory for the transition buffers
231 for(auto &mm_ctx : workload.ctx->memory_managers())
232 {
233 if(mm_ctx.second.cross_group != nullptr)
234 {
235 mm_ctx.second.cross_group->acquire();
236 }
237 }
238
239 // Execute tasks
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000240 for(auto &task : workload.tasks)
241 {
242 task();
243 }
Georgios Pinitas3d1489d2018-05-03 20:47:16 +0100244
245 // Release memory for the transition buffers
246 for(auto &mm_ctx : workload.ctx->memory_managers())
247 {
248 if(mm_ctx.second.cross_group != nullptr)
249 {
250 mm_ctx.second.cross_group->release();
251 }
252 }
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000253}
254
Georgios Pinitas12be7ab2018-07-03 12:06:23 +0100255bool call_all_output_node_accessors(ExecutionWorkload &workload)
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000256{
Georgios Pinitas12be7ab2018-07-03 12:06:23 +0100257 bool is_valid = true;
258 std::for_each(std::begin(workload.outputs), std::end(workload.outputs), [&](Tensor * output_tensor)
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000259 {
Georgios Pinitas12be7ab2018-07-03 12:06:23 +0100260 is_valid = is_valid && (output_tensor != nullptr) && output_tensor->call_accessor();
261 });
262
263 return is_valid;
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000264}
265} // namespace detail
Georgios Pinitasd9eb2752018-04-03 13:44:29 +0100266} // namespace graph
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000267} // namespace arm_compute