ONE - On-device Neural Engine
Loading...
Searching...
No Matches
MemoryPlanner.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17#include "MemoryPlanner.h"
18
21
22#include <util/logging.h>
23
24#include <cassert>
25
26namespace onert
27{
28namespace backend
29{
30namespace train
31{
32
33template <typename Index> void BumpPlanner<Index>::claim(const Index &ind, size_t size)
34{
35 basic::Block blk{_capacity, size};
36 _mem_plans[ind] = blk;
37 _capacity += size;
38
39 VERBOSE(BP_PLANNER) << "CLAIM(" << ind << "): " << blk.offset << ", " << blk.size << std::endl;
40}
41
42template <typename Index> void BumpPlanner<Index>::release(const Index &ind)
43{
44 VERBOSE(BP_PLANNER) << "RELEASE(" << ind << "): "
45 << "NOTHING does" << std::endl;
46}
47
48// There are some assumptions for claiming memory(== making a reservation for memory).
49// 1. About _claim_table(std::map).
50// - The table's data structure is std::map so that it always sorts
51// value(Index) by key(base_offset).
52// - This claim() inserts key/value into _claim_table and the release() removes the key/value from
53// _claim_table.
54// - _claim_table shows the memory status at a certain point in time. Therefore,
55// - If _claim_table has an offset and a certain size at a certain point in time,
56// it means the place at the offset has been already claimed(== can't claim now. need to find
57// someplace new).
58// - If _claim_table doesn't have any element for an offset and a certain size at a certain
59// point in time, it means the place at the offset can be claimed.
60// 2. In the loop for _claim_table, we can assume the current claim_base_offset value is bigger than
61// the previous claim_base_offset.
62template <typename Index> void FirstFitPlanner<Index>::claim(const Index &ind, size_t size)
63{
64 // Find the right position for claiming
65 uint32_t next_offset = 0;
66 for (const auto &[claimed_base_offset, claimed_index] : _claim_table)
67 {
68 auto claimed_size = _mem_plans[claimed_index].size;
69 if (next_offset + size <= claimed_base_offset)
70 {
71 break;
72 }
73 else
74 {
75 next_offset = claimed_base_offset + claimed_size;
76 }
77 }
78
79 // Now next_offset is set to the proper offset
80 // std::map's operator[] requires default constructor of value
81 // _claim_table[next_offset] = ind;
82 _claim_table.emplace(std::make_pair(next_offset, ind));
83 _mem_plans[ind] = {next_offset, size};
84
85 VERBOSE(FF_PLANNER) << "claim(" << ind << "): [+" << next_offset << ", " << size << "sz]"
86 << std::endl;
87
88 if (_capacity < next_offset + size)
89 {
90 _capacity = next_offset + size;
91 }
92}
93
94template <typename Index> void FirstFitPlanner<Index>::release(const Index &ind)
95{
96 for (auto it = _claim_table.cbegin(); it != _claim_table.cend(); ++it)
97 {
98 if (it->second == ind)
99 {
100 uint32_t offset = it->first;
101 uint32_t size = _mem_plans[ind].size;
102
103 _claim_table.erase(it);
104
105 VERBOSE(FF_PLANNER) << "release(" << ind << "): [+" << offset << ", " << size << "sz]"
106 << std::endl;
107 return;
108 }
109 }
110 assert(!"Cannot release for given index. It has been not claimed or released already.");
111}
112
113template <typename Index>
115 : _initialized(false), _capacity(0), _mem_plans(), _live_indices(), _interference_graph(),
116 _indices()
117{
118 // DO NOTHING
119}
120
121template <typename Index> void WICPlanner<Index>::claim(const Index &ind, size_t size)
122{
123 _indices.emplace(size, ind);
124 _interference_graph[ind].insert(_interference_graph[ind].end(), _live_indices.cbegin(),
125 _live_indices.cend());
126 for (const auto &live_operand : _live_indices)
127 {
128 _interference_graph[live_operand].emplace_back(ind);
129 }
130 _live_indices.emplace(ind);
131
132 VERBOSE(WIC_PLANNER) << "claim(" << ind << "): [" << size << "sz]" << std::endl;
133}
134
135template <typename Index> void WICPlanner<Index>::release(const Index &ind)
136{
137 _live_indices.erase(ind);
138 VERBOSE(WIC_PLANNER) << "release(" << ind << ")" << std::endl;
139}
140
141/*
142 * Build memory plans using liveness and size of operands
143 * 1. Build inference graph at claim
144 * - Two operands interfere if they have overlapped live range
145 * 2. Sort operands in descending order of size
146 * - Use std::multimap to sort operands
147 * 3. Allocate memory block for sorted operands
148 * - Find free memory block which does not overlap with interfered operands
149 */
150
151template <typename Index> void WICPlanner<Index>::buildMemoryPlans()
152{
153 for (const auto &[size, ind] : _indices)
154 {
155 VERBOSE(WIC_PLANNER) << "build_plan(" << ind << "): [" << size << "sz]" << std::endl;
156
157 uint32_t next_offset = 0;
158 if (_interference_graph.count(ind))
159 {
160 // Find interfered memory plans and sort them by offset
161 std::multimap<uint32_t, uint32_t> interfered_plans;
162 for (const auto &interference : _interference_graph[ind])
163 {
164 if (_mem_plans.count(interference))
165 interfered_plans.emplace(_mem_plans[interference].offset, _mem_plans[interference].size);
166 }
167
168 // Find free memory block in first-fit manner
169 for (const auto &[claimed_base_offset, claimed_size] : interfered_plans)
170 {
171 VERBOSE(WIC_PLANNER) << "interfere : [+" << claimed_base_offset << ", " << claimed_size
172 << "sz]" << std::endl;
173 if (next_offset + size <= claimed_base_offset)
174 {
175 break;
176 }
177 else if (next_offset < claimed_base_offset + claimed_size)
178 {
179 next_offset = claimed_base_offset + claimed_size;
180 }
181 }
182 }
183 else
184 {
185 VERBOSE(WIC_PLANNER) << "No interference" << std::endl;
186 }
187
188 _mem_plans[ind] = {next_offset, size};
189 VERBOSE(WIC_PLANNER) << "alloc(" << ind << "): [+" << next_offset << ", " << size << "sz]"
190 << std::endl;
191
192 if (_capacity < next_offset + size)
193 {
194 _capacity = next_offset + size;
195 }
196 }
197 _initialized = true;
198 _interference_graph.clear();
199 _indices.clear();
200}
201
202template <typename Index> typename WICPlanner<Index>::MemoryPlans &WICPlanner<Index>::memory_plans()
203{
204 if (!_initialized)
205 buildMemoryPlans();
206 return _mem_plans;
207}
208
211
214
217
218} // namespace train
219} // namespace backend
220} // namespace onert
Class to plan memory by bump way.
void release(const Index &) override
Release memory for tensor by bump way.
void claim(const Index &, size_t) override
Claim memory for tensor by bump way.
Class to plan memory by firstfit way.
void claim(const Index &, size_t) override
Claim memory for tensor by firstfit way.
void release(const Index &) override
Release memory for tensor by firstfit way.
Class to plan memory by Weighted Interval Color algorithm.
void release(const Index &) override
Release memory for tensor by WIC algorithm.
MemoryPlans & memory_plans() override
Get MemoryPlans.
void claim(const Index &, size_t) override
Claim memory for tensor by WIC algorithm.
__global uchar * offset(const Image *img, int x, int y)
Definition helpers.h:540
#define VERBOSE(name, lv)
Definition Log.h:71
int32_t size[5]
Definition Slice.cpp:35
Structure to have memory offset and size.