2 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "core/RuntimeGraph.h"
19 #include "core/RuntimeModule.h"
22 #include <unordered_map>
24 namespace luci_interpreter
27 class RuntimeGraph::TensorAllocPlan
29 std::vector<std::vector<Tensor *>> _alloc_plan;
30 std::vector<std::vector<Tensor *>> _dealloc_plan;
32 IMemoryManager *_memory_manager;
35 explicit TensorAllocPlan(IMemoryManager *memory_manager);
36 void invalidate() { _valid = false; }
37 bool isValid() const { return _valid; }
38 void build(const RuntimeGraph &graph);
39 void allocate(size_t kernel_index) const;
40 void deallocate(size_t kernel_index) const;
43 RuntimeGraph::TensorAllocPlan::TensorAllocPlan(IMemoryManager *memory_manager)
44 : _memory_manager(memory_manager)
48 void RuntimeGraph::TensorAllocPlan::build(const RuntimeGraph &graph)
51 using Lifetime = std::pair<size_t, size_t>;
52 std::unordered_map<Tensor *, Lifetime> lifetimes;
53 const size_t num_kernels = graph._kernels.size();
54 for (size_t index = 0; index < num_kernels; ++index)
56 const auto &kernel = graph._kernels[index];
57 for (const Tensor *tensor : kernel->getInputTensors())
59 auto nc_tensor = const_cast<Tensor *>(tensor);
60 if (lifetimes.count(nc_tensor) > 0)
61 lifetimes.at(nc_tensor).second = index;
63 for (Tensor *tensor : kernel->getOutputTensors())
65 assert(lifetimes.count(tensor) == 0);
66 lifetimes[tensor] = Lifetime(index, index);
69 for (const Tensor *tensor : graph.getOutputTensors())
71 auto nc_tensor = const_cast<Tensor *>(tensor);
72 if (lifetimes.count(nc_tensor) > 0)
73 lifetimes.at(nc_tensor).second = num_kernels;
75 _alloc_plan.assign(num_kernels, std::vector<Tensor *>());
76 _dealloc_plan.assign(num_kernels + 1, std::vector<Tensor *>());
77 for (const auto &item : lifetimes)
79 _alloc_plan[item.second.first].push_back(item.first);
80 _dealloc_plan[item.second.second].push_back(item.first);
85 void RuntimeGraph::TensorAllocPlan::allocate(size_t kernel_index) const
87 assert(_valid && kernel_index < _alloc_plan.size());
88 for (Tensor *tensor : _alloc_plan[kernel_index])
90 _memory_manager->allocate_memory(*tensor);
94 void RuntimeGraph::TensorAllocPlan::deallocate(size_t kernel_index) const
96 assert(_valid && kernel_index < _dealloc_plan.size());
97 for (Tensor *tensor : _dealloc_plan[kernel_index])
99 _memory_manager->release_memory(*tensor);
103 RuntimeGraph::RuntimeGraph(RuntimeModule *owning_module, IMemoryManager *memory_manager)
104 : _owning_module(owning_module), _memory_manager(memory_manager),
105 _tensor_alloc_plan(std::make_unique<TensorAllocPlan>(memory_manager))
109 RuntimeGraph::~RuntimeGraph()
111 for (auto &tensor : _tensors)
113 if (tensor->is_data_allocated())
114 _memory_manager->release_memory(*tensor);
118 Tensor *RuntimeGraph::addTensor(std::unique_ptr<Tensor> &&tensor)
120 assert(tensor != nullptr);
121 _tensors.push_back(std::move(tensor));
122 return _tensors.back().get();
125 void RuntimeGraph::setInputTensors(const std::vector<Tensor *> &input_tensors)
127 assert(std::all_of(input_tensors.cbegin(), input_tensors.cend(),
128 [](Tensor *tensor) { return tensor != nullptr; }));
129 _input_tensors = input_tensors;
132 void RuntimeGraph::setOutputTensors(const std::vector<Tensor *> &output_tensors)
134 assert(std::all_of(output_tensors.cbegin(), output_tensors.cend(),
135 [](Tensor *tensor) { return tensor != nullptr; }));
136 _output_tensors = output_tensors;
139 void RuntimeGraph::configureAllocations(Tensor *tensor)
141 _memory_manager->allocate_memory(*tensor);
144 void RuntimeGraph::addKernel(std::unique_ptr<Kernel> &&kernel)
146 assert(kernel != nullptr);
147 _kernels.push_back(std::move(kernel));
148 _tensor_alloc_plan->invalidate();
151 void RuntimeGraph::execute() const
153 if (!_tensor_alloc_plan->isValid())
154 _tensor_alloc_plan->build(*this);
156 EventNotifier *event_notifier = _owning_module->getEventNotifier();
158 // Notify the observers that the input tensors have changed.
159 if (event_notifier != nullptr)
161 for (const Tensor *input_tensor : getInputTensors())
163 if (input_tensor->is_observable())
164 event_notifier->postTensorWrite(input_tensor);
168 for (size_t index = 0; index < _kernels.size(); ++index)
170 const auto &kernel = _kernels[index];
171 if (event_notifier != nullptr)
173 event_notifier->preOperatorExecute(kernel.get());
176 // TODO The `configure` method should only be called if the outputs of an operator need to be
180 // Preallocate outputs in advance instead of relying on automatic allocation
181 _tensor_alloc_plan->allocate(index);
185 if (event_notifier != nullptr)
187 event_notifier->postOperatorExecute(kernel.get());
190 for (const Tensor *tensor : kernel->getOutputTensors())
192 if (event_notifier != nullptr && tensor->is_observable())
194 event_notifier->postTensorWrite(tensor);
197 _tensor_alloc_plan->deallocate(index);
201 } // namespace luci_interpreter