xref: /aosp_15_r20/external/intel-media-driver/media_softlet/agnostic/common/heap_manager/heap_manager.cpp (revision ba62d9d3abf0e404f2022b4cd7a85e107f48596f)
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 &params,
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