1 /*
2 * Copyright (c) 2017-2021, Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22 //!
23 //! \file heap_manager.cpp
24 //! \brief Implements functionalities pertaining to the heap manager.
25 //!
26
27 #include "heap_manager.h"
28
~HeapManager()29 HeapManager::~HeapManager()
30 {
31 HEAP_FUNCTION_ENTER;
32 m_currHeapId = 0;
33 m_currHeapSize = 0;
34 m_extendHeapSize = 0;
35 m_osInterface = nullptr;
36 }
37
AcquireSpace(MemoryBlockManager::AcquireParams & params,std::vector<MemoryBlock> & blocks,uint32_t & spaceNeeded)38 MOS_STATUS HeapManager::AcquireSpace(
39 MemoryBlockManager::AcquireParams ¶ms,
40 std::vector<MemoryBlock> &blocks,
41 uint32_t &spaceNeeded)
42 {
43 HEAP_FUNCTION_ENTER;
44
45 // first time space is being acquired, allocate the first heap
46 if (m_heapIds.empty())
47 {
48 HEAP_CHK_STATUS(AllocateHeap(m_currHeapSize));
49 }
50
51 if (m_behavior != Behavior::clientControlled)
52 {
53 if (params.m_staticBlock)
54 {
55 HEAP_ASSERTMESSAGE("Static blocks are only allowed when the client controls behavior");
56 return MOS_STATUS_INVALID_PARAMETER;
57 }
58 if (!m_blockManager.IsTrackerDataValid())
59 {
60 HEAP_ASSERTMESSAGE("A tracker must be registered before acquiring space if client does not control behavior");
61 return MOS_STATUS_INVALID_PARAMETER;
62 }
63 }
64
65 spaceNeeded = 0;
66 MOS_STATUS acquireSpaceResult = m_blockManager.AcquireSpace(params, blocks, spaceNeeded);
67 if (acquireSpaceResult == MOS_STATUS_CLIENT_AR_NO_SPACE)
68 {
69 bool blocksUpdated = false;
70 // no need to refresh the block states for every space acquisition
71 // attempt for first AcquireSpace failure
72 HEAP_CHK_STATUS(m_blockManager.RefreshBlockStates(blocksUpdated));
73 if (blocksUpdated)
74 {
75 if ((m_blockManager.AcquireSpace(params, blocks, spaceNeeded)) ==
76 MOS_STATUS_CLIENT_AR_NO_SPACE)
77 {
78 // if space may not be acquired after refreshing block states, execute behavior
79 HEAP_CHK_STATUS(BehaveWhenNoSpace());
80 HEAP_CHK_STATUS(m_blockManager.AcquireSpace(params, blocks, spaceNeeded));
81 }
82 }
83 else
84 {
85 // if no blocks updated after refresh, execute behavior
86 HEAP_CHK_STATUS(BehaveWhenNoSpace());
87 HEAP_CHK_STATUS(m_blockManager.AcquireSpace(params, blocks, spaceNeeded));
88 }
89 }
90 else
91 {
92 HEAP_CHK_STATUS(acquireSpaceResult);
93 }
94
95 return MOS_STATUS_SUCCESS;
96 }
97
ClearSpace(MemoryBlock & block)98 MOS_STATUS HeapManager::ClearSpace(MemoryBlock &block)
99 {
100 HEAP_FUNCTION_ENTER;
101
102 if (m_behavior != clientControlled)
103 {
104 HEAP_ASSERTMESSAGE("Only client controlled behavior allows for clients to clear space");
105 return MOS_STATUS_INVALID_PARAMETER;
106 }
107
108 HEAP_CHK_STATUS(m_blockManager.ClearSpace(block))
109
110 return MOS_STATUS_SUCCESS;
111 }
112
RegisterTrackerResource(uint32_t * trackerData)113 MOS_STATUS HeapManager::RegisterTrackerResource(uint32_t *trackerData)
114 {
115 HEAP_FUNCTION_ENTER;
116 return m_blockManager.RegisterTrackerResource(trackerData);
117 }
118
RegisterTrackerProducer(FrameTrackerProducer * trackerProducer)119 MOS_STATUS HeapManager::RegisterTrackerProducer(FrameTrackerProducer *trackerProducer)
120 {
121 HEAP_FUNCTION_ENTER;
122 return m_blockManager.RegisterTrackerProducer(trackerProducer);
123 }
124
SetInitialHeapSize(uint32_t size)125 MOS_STATUS HeapManager::SetInitialHeapSize(uint32_t size)
126 {
127 HEAP_FUNCTION_ENTER;
128
129 if (size == 0)
130 {
131 HEAP_ASSERTMESSAGE("0 is an invalid size for heap extension");
132 return MOS_STATUS_INVALID_PARAMETER;
133 }
134
135 m_currHeapSize = MOS_ALIGN_CEIL(size, m_heapAlignment);
136
137 return MOS_STATUS_SUCCESS;
138 }
139
140
SetExtendHeapSize(uint32_t size)141 MOS_STATUS HeapManager::SetExtendHeapSize(uint32_t size)
142 {
143 HEAP_FUNCTION_ENTER;
144
145 if (size == 0)
146 {
147 HEAP_ASSERTMESSAGE("0 is an invalid size for heap extension");
148 return MOS_STATUS_INVALID_PARAMETER;
149 }
150
151 if (m_behavior == Behavior::wait)
152 {
153 HEAP_ASSERTMESSAGE("The heap may not be extended in the case of wait behavior");
154 return MOS_STATUS_INVALID_PARAMETER;
155 }
156
157 m_extendHeapSize = MOS_ALIGN_CEIL(size, m_heapAlignment);
158
159 return MOS_STATUS_SUCCESS;
160 }
161
RegisterOsInterface(PMOS_INTERFACE osInterface)162 MOS_STATUS HeapManager::RegisterOsInterface(PMOS_INTERFACE osInterface)
163 {
164 HEAP_FUNCTION_ENTER;
165 HEAP_CHK_NULL(osInterface);
166 m_osInterface = osInterface;
167 HEAP_CHK_STATUS(m_blockManager.RegisterOsInterface(m_osInterface));
168 return MOS_STATUS_SUCCESS;
169 }
170
GetTotalSize()171 uint32_t HeapManager::GetTotalSize()
172 {
173 HEAP_FUNCTION_ENTER;
174
175 uint32_t totalSize = m_blockManager.GetSize();
176
177 // Since allocation is delayed to when space is acquired, it is possible
178 // for manager to be in a valid state if a size of 0 is returned.
179 if (totalSize == 0 && m_currHeapId == Heap::m_invalidId)
180 {
181 totalSize = m_currHeapSize;
182 }
183
184 return totalSize;
185 }
186
AllocateHeap(uint32_t size)187 MOS_STATUS HeapManager::AllocateHeap(uint32_t size)
188 {
189 HEAP_FUNCTION_ENTER;
190
191 HEAP_CHK_NULL(m_osInterface);
192
193 if (size == 0)
194 {
195 HEAP_ASSERTMESSAGE("0 is an invalid size for heap allocation");
196 return MOS_STATUS_INVALID_PARAMETER;
197 }
198
199 ++m_currHeapId;
200 m_heapIds.push_back(m_currHeapId);
201
202 HEAP_CHK_STATUS(m_blockManager.RegisterHeap(m_currHeapId, size, m_hwWriteOnlyHeap));
203
204 return MOS_STATUS_SUCCESS;
205 }
206
FreeHeap()207 void HeapManager::FreeHeap()
208 {
209 // Free oldest heap
210 auto heapId = m_heapIds.front();
211 m_heapIds.pop_front();
212 m_blockManager.UnregisterHeap(heapId);
213 }
214
Wait()215 MOS_STATUS HeapManager::Wait()
216 {
217 HEAP_FUNCTION_ENTER_VERBOSE;
218
219 bool blocksUpdated = false;
220
221 for (auto waitMs = m_waitTimeout; waitMs > 0; waitMs -= m_waitIncrement)
222 {
223 MosUtilities::MosSleep(m_waitIncrement);
224 HEAP_CHK_STATUS(m_blockManager.RefreshBlockStates(blocksUpdated));
225 if (blocksUpdated)
226 {
227 break;
228 }
229 }
230
231 return (blocksUpdated) ? MOS_STATUS_SUCCESS : MOS_STATUS_CLIENT_AR_NO_SPACE;
232 }
233
BehaveWhenNoSpace()234 MOS_STATUS HeapManager::BehaveWhenNoSpace()
235 {
236 HEAP_FUNCTION_ENTER_VERBOSE;
237
238 switch (m_behavior)
239 {
240 case wait:
241 HEAP_CHK_STATUS(Wait());
242 break;
243 case extend:
244 m_currHeapSize += m_extendHeapSize;
245 HEAP_CHK_STATUS(AllocateHeap(m_currHeapSize));
246 break;
247 case destructiveExtend:
248 FreeHeap();
249 m_currHeapSize += m_extendHeapSize;
250 HEAP_CHK_STATUS(AllocateHeap(m_currHeapSize));
251 break;
252 case waitAndExtend:
253 if (Wait() == MOS_STATUS_CLIENT_AR_NO_SPACE)
254 {
255 m_currHeapSize += m_extendHeapSize;
256 HEAP_CHK_STATUS(AllocateHeap(m_currHeapSize));
257 }
258 break;
259 case clientControlled:
260 // heap manager gives control back to the client
261 return MOS_STATUS_CLIENT_AR_NO_SPACE;
262 default:
263 HEAP_ASSERTMESSAGE("The requested behavior is not yet implemented");
264 return MOS_STATUS_UNIMPLEMENTED;
265 }
266
267 return MOS_STATUS_SUCCESS;
268 }
269