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