1 /* 2 * Copyright (c) 2017, 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 memory_block_manager.h 24 //! \brief Manages the memory blocks belonging to all heaps. 25 //! \details Ensures that all memory is accounted for per heap for each block. 26 //! Determines when blocks are no longer being processed and automatically 27 //! reclaims free space in the state heap. Manages the state transitions of 28 //! the memory blocks. The client has not direct access to the memory block 29 //! manager. 30 //! 31 32 #ifndef __MEMORY_BLOCK_MANAGER_H__ 33 #define __MEMORY_BLOCK_MANAGER_H__ 34 35 #include <list> 36 #include <vector> 37 #include <memory> 38 #include "heap.h" 39 #include "memory_block.h" 40 41 class FrameTrackerProducer; 42 43 //! \brief Used by the heap manager to allow the client to access the heap memory. 44 class MemoryBlockManager 45 { 46 friend class HeapManager; 47 48 public: 49 //! \brief Used by the client to acquire space in heap memory. 50 class AcquireParams 51 { 52 public: 53 //! \brief initializes AcquireParams with a tracker ID AcquireParams(uint32_t trackerId,std::vector<uint32_t> & blockSizes)54 AcquireParams( 55 uint32_t trackerId, 56 std::vector<uint32_t> &blockSizes) : m_blockSizes(blockSizes) 57 { 58 m_trackerId = trackerId; 59 } ~AcquireParams()60 virtual ~AcquireParams() {} 61 62 //! \brief Block sizes to allocate 63 std::vector<uint32_t> &m_blockSizes; 64 //! \brief Requested block alignment 65 uint32_t m_alignment = 0; 66 //! \brief Index to the frame tracker 67 uint32_t m_trackerIndex = 0; 68 //! \brief Must be valid, used for determining whether or not a the block is still in use. \see m_trackerData. 69 uint32_t m_trackerId = MemoryBlockInternal::m_invalidTrackerId; 70 //! \brief Zero memory blocks after allocation 71 bool m_zeroAssignedBlock = false; 72 //! \brief Block allocations are flaged as static are expected to be controlled by the client. \see HeapManager::Behavior::clientControlled. 73 bool m_staticBlock = false; 74 }; 75 MemoryBlockManager()76 MemoryBlockManager() { HEAP_FUNCTION_ENTER; } 77 virtual ~MemoryBlockManager(); 78 79 protected: 80 //! 81 //! \brief Acquires space within the heap(s) 82 //! \param [in] params 83 //! Parameters describing the requested space 84 //! \param [out] blocks 85 //! A vector containing the memory blocks allocated 86 //! \param [out] spaceNeeded 87 //! Amount of space that the heap(s) are short of to complete space acquisition 88 //! \return MOS_STATUS 89 //! MOS_STATUS_SUCCESS if success, else fail reason 90 //! 91 virtual MOS_STATUS AcquireSpace( 92 AcquireParams ¶ms, 93 std::vector<MemoryBlock> &blocks, 94 uint32_t &spaceNeeded); 95 96 //! 97 //! \brief Indicates that the client is done editing the blocks 98 //! \param [in] blocks 99 //! Blocks to be submitted 100 //! \return MOS_STATUS 101 //! MOS_STATUS_SUCCESS if success, else fail reason 102 //! 103 virtual MOS_STATUS SubmitBlocks(std::vector<MemoryBlock> &blocks); 104 105 //! 106 //! \brief Either directly adds a block to the free list, or prepares it to be added 107 //! \param [in] block 108 //! Block to be removed 109 //! \return MOS_STATUS 110 //! MOS_STATUS_SUCCESS if success, else fail reason 111 //! 112 virtual MOS_STATUS ClearSpace(MemoryBlock &block); 113 114 //! \brief Reclaims free memory based on whether or not blocks are no longer in use \see m_trackerData 115 //! \param [out] blocksUpdated 116 //! If true blocks have been updated, if false, no blocks were updated 117 //! \return MOS_STATUS 118 //! MOS_STATUS_SUCCESS if success, else fail reason 119 //! 120 virtual MOS_STATUS RefreshBlockStates(bool &blocksUpdated); 121 122 //! 123 //! \brief Stores heap and initializes memory blocks for future use. 124 //! \param [in] heapId 125 //! ID for the heap to be created 126 //! \param [in] size 127 //! Size of the heap to be created. 128 //! \return MOS_STATUS 129 //! MOS_STATUS_SUCCESS if success, else fail reason 130 //! 131 virtual MOS_STATUS RegisterHeap(uint32_t heapId, uint32_t size, bool hwWriteOnly = false); 132 133 //! 134 //! \brief Removes the specified heap from the block manager, this occurs when the 135 //! heap is in the process of being deleted. Ensures heap is not in use. 136 //! \param [in] heapId 137 //! ID for heap to be removed. 138 //! 139 virtual MOS_STATUS UnregisterHeap(uint32_t heapId); 140 141 //! 142 //! \brief Completes heap deletion for all heaps with unused space in the deleted heaps list. 143 //! \return MOS_STATUS 144 //! MOS_STATUS_SUCCESS if success, else fail reason 145 //! 146 MOS_STATUS CompleteHeapDeletion(); 147 148 //! 149 //! \brief Registers the tracker data to be used for determining whether a 150 //! memory block is available. 151 //! \param [in] trackerData 152 //! Must be valid. See description in \see MemoryBlockManager::m_trackerData. 153 //! \return MOS_STATUS 154 //! MOS_STATUS_SUCCESS if success, else fail reason 155 //! 156 virtual MOS_STATUS RegisterTrackerResource(uint32_t *trackerData); 157 158 //! 159 //! \brief Registers the tracker producer to be used for determining whether a 160 //! memory block is available. This function has a higher priority than 161 //! RegisterTrackerResource, so if it is called, the trackerResource will 162 //! be useless. 163 //! \param [in] trackerProducer 164 //! Must be valid; pointer to trackerProducer. 165 //! \return MOS_STATUS 166 //! MOS_STATUS_SUCCESS if success, else fail reason 167 //! 168 virtual MOS_STATUS RegisterTrackerProducer(FrameTrackerProducer *trackerProducer); 169 170 //! 171 //! \brief Gets the size of the all heaps 172 //! \return The size of all heaps managed \see m_size 173 //! GetSize()174 uint32_t GetSize() { return m_totalSizeOfHeaps; } 175 176 //! 177 //! \brief Determines whether a valid tracker data has been registered 178 //! \return True if the pointer is valid, false otherwise 179 //! IsTrackerDataValid()180 bool IsTrackerDataValid() 181 { 182 return (!m_useProducer && m_trackerData != nullptr) 183 || (m_useProducer && m_trackerProducer != nullptr); 184 } 185 186 //! 187 //! \brief All heaps allocated are locked and kept locked for their lifetimes 188 //! \details May only be set before any heaps are allocated. 189 //! \return MOS_STATUS 190 //! MOS_STATUS_SUCCESS if success, else fail reason 191 //! LockHeapsOnAllocate()192 MOS_STATUS LockHeapsOnAllocate() 193 { 194 HEAP_FUNCTION_ENTER; 195 if (m_totalSizeOfHeaps != 0) 196 { 197 HEAP_ASSERTMESSAGE("Locking heaps on allocate may only be set before heaps are allocated"); 198 return MOS_STATUS_UNKNOWN; 199 } 200 m_lockHeapsOnAllocate = true; 201 return MOS_STATUS_SUCCESS; 202 } 203 204 private: 205 //! \brief Describes the information managed by this class for each heap registered 206 struct HeapWithAdjacencyBlockList 207 { HeapWithAdjacencyBlockListHeapWithAdjacencyBlockList208 HeapWithAdjacencyBlockList() 209 { 210 HEAP_FUNCTION_ENTER; 211 } 212 ~HeapWithAdjacencyBlockListHeapWithAdjacencyBlockList213 virtual ~HeapWithAdjacencyBlockList() 214 { 215 HEAP_FUNCTION_ENTER; 216 MOS_Delete(m_heap); 217 auto curr = m_adjacencyListBegin; 218 MemoryBlockInternal *next = nullptr; 219 220 while (curr != nullptr) 221 { 222 next = curr->GetNext(); 223 MOS_Delete(curr); 224 curr = next; 225 } 226 } 227 228 //! \brief Heap which all other members of this struct define. 229 Heap *m_heap = nullptr; 230 //! \brief The list of blocks in the heap arranged by offset in the heap. The head is a dummy block. 231 MemoryBlockInternal *m_adjacencyListBegin = nullptr; 232 //! \brief The size of the heap 233 uint32_t m_size = 0; 234 }; 235 236 //! 237 //! \brief Stores the provided OS interface in the heap 238 //! \param [in] osInterface 239 //! Must be valid 240 //! \return MOS_STATUS 241 //! MOS_STATUS_SUCCESS if success, else fail reason 242 //! 243 virtual MOS_STATUS RegisterOsInterface(PMOS_INTERFACE osInterface); 244 245 //! 246 //! \brief Determines whether or not space is available, if not enough space returns 247 //! the amount short in \a spaceNeeded 248 //! \param [in] sortedSizes 249 //! Requested block sizes sorted in decending order. 250 //! \param [in] params 251 //! Parameters describing the requested space 252 //! \param [out] spaceNeeded 253 //! Amount of space that the heap(s) are short of to complete space acquisition 254 //! \return MOS_STATUS 255 //! MOS_STATUS_SUCCESS if success, else fail reason 256 //! 257 MOS_STATUS IsSpaceAvailable( 258 AcquireParams ¶ms, 259 uint32_t &spaceNeeded); 260 261 //! 262 //! \brief Sets up memory blocks for the requested space 263 //! \param [in] sortedSizes 264 //! Requested block sizes sorted in decending order with original index saved from params. 265 //! \param [in] params 266 //! Parameters describing the requested space 267 //! \param [out] blocks 268 //! A vector containing the memory blocks allocated 269 //! \return MOS_STATUS 270 //! MOS_STATUS_SUCCESS if success, else fail reason 271 //! 272 MOS_STATUS AllocateSpace( 273 AcquireParams ¶ms, 274 std::vector<MemoryBlock> &blocks); 275 276 //! 277 //! \brief Sets up memory blocks for the requested space 278 //! \param [in] alignedSize 279 //! Aligned size of the memory requested 280 //! \param [in] trackerId 281 //! Tracker ID to be used for the allocated block 282 //! \param [in] staticBlock 283 //! Indicates that the newly created block is expected to be static 284 //! \param [out] freeBlock 285 //! Free block that will be used for the allocation of the new block 286 //! \return MOS_STATUS 287 //! MOS_STATUS_SUCCESS if success, else fail reason 288 //! 289 MOS_STATUS AllocateBlock( 290 uint32_t alignedSize, 291 uint32_t trackerId, 292 bool staticBlock, 293 MemoryBlockInternal *freeBlock); 294 295 //! 296 //! \brief Sets up memory blocks for the requested space 297 //! \param [in] alignedSize 298 //! Aligned size of the memory requested 299 //! \param [in] trackerIndex 300 //! Tracker index to be used for the allocated block 301 //! \param [in] trackerId 302 //! Tracker ID to be used for the allocated block 303 //! \param [in] staticBlock 304 //! Indicates that the newly created block is expected to be static 305 //! \param [out] freeBlock 306 //! Free block that will be used for the allocation of the new block 307 //! \return MOS_STATUS 308 //! MOS_STATUS_SUCCESS if success, else fail reason 309 //! 310 MOS_STATUS AllocateBlock( 311 uint32_t alignedSize, 312 uint32_t trackerIndex, 313 uint32_t trackerId, 314 bool staticBlock, 315 MemoryBlockInternal *freeBlock); 316 317 //! 318 //! \brief Sets up memory blocks for the requested space 319 //! \param [in] block 320 //! Block to be added to the sorted pool of type \a state 321 //! \param [in] state 322 //! Type of pool to be added to 323 //! \return MOS_STATUS 324 //! MOS_STATUS_SUCCESS if success, else fail reason 325 //! 326 MOS_STATUS AddBlockToSortedList( 327 MemoryBlockInternal *block, 328 MemoryBlockInternal::State state); 329 330 //! 331 //! \brief Sets up memory blocks for the requested space 332 //! \param [in] block 333 //! Block to be added to the sorted pool of type \a state 334 //! \param [in] state 335 //! Type of pool to be added to, may not be of type MemoryBlockInternal::State::pool since a separate function is dedicated to that case. \see GetBlockFromPool 336 //! \return MOS_STATUS 337 //! MOS_STATUS_SUCCESS if success, else fail reason 338 //! 339 MOS_STATUS RemoveBlockFromSortedList( 340 MemoryBlockInternal *block, 341 MemoryBlockInternal::State state); 342 343 //! 344 //! \brief Gets a pool type block from the sorted block pool, if pool is empty allocates a new one 345 //! \see m_sortedBlockList[MemoryBlockInternal::State::pool] 346 //! \return MemoryBlockInternal* 347 //! Valid pointer if success, nullptr if fail 348 //! 349 MemoryBlockInternal* GetBlockFromPool(); 350 351 //! 352 //! \brief Removes all blocks with heaps matching \a heapId from the sorted block pool for \a state. \see m_sortedBlockList 353 //! \param [in] heapId 354 //! Heap whose blocks should be removed 355 //! \return MOS_STATUS 356 //! MOS_STATUS_SUCCESS if success, else fail reason 357 //! 358 MOS_STATUS RemoveHeapFromSortedBlockList( 359 uint32_t heapId); 360 361 //! 362 //! \brief Merges two contiguous blocks into one. 363 //! \param [in,out] blockCombined 364 //! Block into which \a blockRelease will be merged in to, this block is the output of the merge 365 //! \param [in] blockRelease 366 //! Block to be merged into \a blockCombined, this block will be added back to the pool after the merge 367 //! \return MOS_STATUS 368 //! MOS_STATUS_SUCCESS if success, else fail reason 369 //! 370 MOS_STATUS MergeBlocks( 371 MemoryBlockInternal *blockCombined, 372 MemoryBlockInternal *blockRelease); 373 374 //! 375 //! \brief Temporary function while MOS utilities function is added for smart pointers 376 //! \return std::shared_ptr<T> 377 //! Valid pointer if success, nullptr if fail 378 //! 379 template <class T, class... Args> MakeShared(Args &&...args)380 std::shared_ptr<T> MakeShared(Args&&... args) 381 { 382 std::shared_ptr<T> block = nullptr; 383 try 384 { 385 block = std::make_shared<T>(args...); 386 } 387 catch (const std::bad_alloc& e) 388 { 389 HEAP_ASSERTMESSAGE("Allocation of memory block failed!"); 390 return nullptr; 391 } 392 return block; 393 } 394 395 396 //! \brief Used to retain information about the requested block sizes after those 397 //! sizes are sorted for the return of blocks.\see AcquireParams::m_blockSizes \see AcquireSpace 398 struct SortedSizePair 399 { 400 //! \brief Constructs SortedSizePair SortedSizePairSortedSizePair401 SortedSizePair() {} SortedSizePairSortedSizePair402 SortedSizePair(uint32_t originalIdx, uint32_t blockSize) 403 : m_originalIdx(originalIdx), m_blockSize(blockSize) {} 404 uint32_t m_originalIdx = 0; //!< Original index of the requested block size \see AcquireParams::m_blockSizes 405 uint32_t m_blockSize = 0; //!< Aligned block size 406 }; 407 408 //! \brief Alignment for blocks in heap, currently fixed at a cacheline 409 static const uint16_t m_blockAlignment = 64; 410 //! \brief Alignment for heap, currently fixed at a page 411 static const uint16_t m_heapAlignment = MOS_PAGE_SIZE; 412 //! \brief Number of submissions before a refresh, currently fixed 413 static const uint16_t m_numSubmissionsForRefresh = 128; 414 415 //! \brief Total size of all managed heaps. 416 uint32_t m_totalSizeOfHeaps = 0; 417 //! \brief The list of block pools per heap 418 std::list<std::shared_ptr<HeapWithAdjacencyBlockList>> m_heaps; 419 //! \brief List of block pools per heap for heaps in deletion process 420 std::list<std::shared_ptr<HeapWithAdjacencyBlockList>> m_deletedHeaps; 421 //! \brief Pools of memory blocks sorted by their states based on the state indicated 422 //! by the latest TrackerId. The free pool is sorted in ascending order. 423 MemoryBlockInternal *m_sortedBlockList[MemoryBlockInternal::State::stateCount] = {nullptr}; 424 //! \brief Number of entries in each sorted block list. 425 uint32_t m_sortedBlockListNumEntries[MemoryBlockInternal::State::stateCount] = {0}; 426 //! \brief Sizes of each block pool. 427 //! \brief MemoryBlockInternal::State::pool type blocks have no size, and thus that pool also is expected to be size 0. 428 uint32_t m_sortedBlockListSizes[MemoryBlockInternal::State::stateCount] = {0}; 429 //! \brief Used to compare to a memory block's tracker ID. If the value is greater 430 //! than the tracker ID, then the block is no longer in use and may be reclaimed 431 //! as free space, or if the block is static transitioned to allocated state so 432 //! it may be re-used. \see MemoryBlockInternal::m_trackerId 433 //! \details The client is expected to manage this tracker; it should be valid for the 434 //! life of the heap manager. The tracker may be updated at whatever granularity is 435 //! appropriate--per workload, per frame, etc. It is expected that when the 436 //! tracker data indicates that all blocks with tracker IDs less than or equal 437 //! to the udpated value may be re-used. 438 uint32_t *m_trackerData = nullptr; 439 PMOS_INTERFACE m_osInterface = nullptr; //!< OS interface used for managing graphics resources 440 bool m_lockHeapsOnAllocate = false; //!< All heaps allocated with the keep locked flag. 441 442 //! \brief Persistent storage for the sorted sizes used during AcquireSpace() 443 std::list<SortedSizePair> m_sortedSizes; 444 //! \brief TrackerProducer 445 FrameTrackerProducer *m_trackerProducer = nullptr; 446 //! \bried Whether trackerProducer is set 447 bool m_useProducer = false; 448 }; 449 #endif // __MEMORY_BLOCK_MANAGER_H__ 450