1 /* 2 * Copyright (c) 2015-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 mhw_block_manager.h 24 //! \brief This modules implements state heap block manager used in MHW 25 //! 26 #ifndef __MHW_BLOCK_MANAGER_H__ 27 #define __MHW_BLOCK_MANAGER_H__ 28 29 #include "mos_os.h" 30 #include "mhw_state_heap.h" 31 #include "mhw_memory_pool.h" 32 33 #define BLOCK_MANAGER_CHK_STATUS(_stmt) \ 34 MOS_CHK_STATUS_RETURN(MOS_COMPONENT_HW, MOS_HW_SUBCOMP_ALL, _stmt) 35 36 #define BLOCK_MANAGER_CHK_STATUS_MESSAGE(_stmt, _message, ...) \ 37 MOS_CHK_STATUS_MESSAGE_RETURN(MOS_COMPONENT_HW, MOS_HW_SUBCOMP_ALL, _stmt, _message, ##__VA_ARGS__) 38 39 #define BLOCK_MANAGER_CHK_NULL(_ptr) \ 40 MOS_CHK_NULL_RETURN(MOS_COMPONENT_HW, MOS_HW_SUBCOMP_ALL, _ptr) 41 42 #define MHW_BLOCK_MANAGER_INVALID_TAG ((uint32_t)-1) 43 44 // Maximum allocation array size 45 #define MHW_BLOCK_MANAGER_MAX_BLOCK_ARRAY 64 46 47 typedef struct _MHW_BLOCK_MANAGER_PARAMS 48 { 49 uint32_t dwPoolInitialCount; //!< Initial number of memory blocks in pool 50 uint32_t dwPoolMaxCount; //!< Maximum number of memory blocks in pool 51 uint32_t dwPoolIncrement; //!< Memory block pool increment 52 uint32_t dwHeapInitialSize; //!< Initial heap size 53 uint32_t dwHeapIncrement; //!< Heap size increment 54 uint32_t dwHeapMaxSize; //!< Maximum overall heap size 55 uint32_t dwHeapMaxCount; //!< Maximum number of heaps 56 uint32_t dwHeapGranularity; //!< Block granularity 57 uint32_t dwHeapBlockMinSize; //!< Minimum block fragment size (never create a block smaller than this) 58 } MHW_BLOCK_MANAGER_PARAMS, *PMHW_BLOCK_MANAGER_PARAMS; 59 60 #define MHW_BLOCK_POSITION_TAIL (NULL) 61 #define MHW_BLOCK_POSITION_HEAD ((PMHW_STATE_HEAP_MEMORY_BLOCK) -1) 62 63 typedef struct _MHW_BLOCK_LIST 64 { 65 PMHW_BLOCK_MANAGER pBlockManager; //!< Block Manager the list belongs to 66 PMHW_STATE_HEAP_MEMORY_BLOCK pHead; //!< Head of the list 67 PMHW_STATE_HEAP_MEMORY_BLOCK pTail; //!< Tail of the list 68 MHW_BLOCK_STATE BlockState; //!< Described the type of block the list contains 69 int32_t iCount; //!< Number of elements on the list 70 uint32_t dwSize; //!< Total memory in the list 71 char szListName[16]; //!< List name for debugging purposes 72 } MHW_BLOCK_LIST, *PMHW_BLOCK_LIST; 73 74 struct MHW_BLOCK_MANAGER 75 { 76 private: 77 MHW_BLOCK_MANAGER_PARAMS m_Params; //!< Block Manager configuration 78 MHW_MEMORY_POOL m_MemoryPool; //!< Memory pool of PMHW_STATE_HEAP_MEMORY_BLOCK objects 79 MHW_BLOCK_LIST m_BlockList[MHW_BLOCK_STATE_COUNT]; //!< Block lists associated with each block state 80 PMHW_STATE_HEAP m_pStateHeap; //!< Points to state heap 81 82 public: 83 84 //! 85 //! \brief Initializes the MHW_BLOCK_MANAGER 86 //! \details Constructor of MHW_BLOCK_MANAGER which initializes all parameters and members 87 //! \param [in] pParams 88 //! Pointer to block manager params. If it is null, default param will be used. 89 //! 90 MHW_BLOCK_MANAGER(PMHW_BLOCK_MANAGER_PARAMS pParams); 91 92 //! 93 //! \brief Destructor of MHW_BLOCK_MANAGER 94 ~MHW_BLOCK_MANAGER(); 95 96 //! 97 //! \brief Adds newly created state heap to block manager 98 //! \details Adds a new state heap to memory block manager. A new memory free memory block is added to 99 //! the free list representing the new available heap. 100 //! \param [in] pStateHeap 101 //! Pointer to the newly created state heap 102 //! \return MOS_STATUS 103 //! Returns the status of the operation 104 //! 105 MOS_STATUS RegisterStateHeap(PMHW_STATE_HEAP pStateHeap); 106 107 //! 108 //! \brief Unregisters state heap from block manager prior to deallocation 109 //! \details Removes state heap from block manager. Memory blocks must be all deleted. 110 //! \param [in] pStateHeap 111 //! Pointer to the newly created state heap 112 //! \return MOS_STATUS 113 //! Returns the status of the operation 114 //! 115 MOS_STATUS UnregisterStateHeap(PMHW_STATE_HEAP pStateHeap); 116 117 //! 118 //! \brief Update block states based on last executed tag 119 //! \details Update block states based on last executed tag 120 //! submitted unlocked blocks are released; 121 //! move to allocated 122 //! \param [in] dwSyncTag 123 //! sync tag 124 //! \return MOS_STATUS 125 //! Returns the status of the operation 126 //! 127 MOS_STATUS Refresh(); 128 129 //! 130 //! \brief Allocate memory block with scratch space 131 //! \details Allocate memory block with scratch space 132 //! \param [in] dwSize 133 //! Size of memory block to allocate 134 //! \param [in] dwAlignment 135 //! Alignment 136 //! \param [in] dwScratchSpace 137 //! Scratch space size 138 //! \return PMHW_STATE_HEAP_MEMORY_BLOCK 139 //! Pointer to the allocated memory block 140 //! 141 PMHW_STATE_HEAP_MEMORY_BLOCK AllocateWithScratchSpace( 142 uint32_t dwSize, 143 uint32_t dwAlignment, 144 uint32_t dwScratchSpace); 145 146 //! 147 //! \brief Allocate free block of memory 148 //! \details Allocate free memory block of memory for use by the client 149 //! \param [in] dwSize 150 //! Size of memory to be allocated 151 //! \param [in] dwAlignment 152 //! Memory alignment 153 //! \param [in] pHeapAffinity 154 //! Pointer to heap affinity 155 //! \return PMHW_STATE_HEAP_MEMORY_BLOCK 156 //! Pointer to allocated memory block 157 //! 158 PMHW_STATE_HEAP_MEMORY_BLOCK AllocateBlock( 159 uint32_t dwSize, 160 uint32_t dwAlignment, 161 PMHW_STATE_HEAP pHeapAffinity); 162 163 //! 164 //! \brief Free memory block 165 //! \details Free memory block according to the sync tag 166 //! \param [in] pBlock 167 //! Pointer to memory block to be freed 168 //! \param [in] dwSyncTag 169 //! Sync tag 170 //! \return MOS_STATUS 171 //! Returns the status of the operation 172 //! 173 MOS_STATUS FreeBlock( 174 PMHW_STATE_HEAP_MEMORY_BLOCK pBlock); 175 176 //! 177 //! \brief Calculate the memory of space required 178 //! \details Calculate the memory of space required 179 //! \param [in] pdwSizes 180 //! Pointer to memory block to be freed 181 //! \param [in] iCount 182 //! Sync tag 183 //! \param [in] dwAlignment 184 //! alignment 185 //! \param [in] bHeapAffinity 186 //! heap affinity 187 //! \param [in] pHeapAffinity 188 //! pointer to state heap affinity 189 //! \return uint32_t Size of space needed by client 190 //! 191 uint32_t CalculateSpaceNeeded( 192 const uint32_t *pdwSizes, 193 int32_t iCount, 194 uint32_t dwAlignment, 195 bool bHeapAffinity, 196 PMHW_STATE_HEAP pHeapAffinity); 197 198 //! 199 //! \brief Submit memory block 200 //! \details Submit memory block according to the sync tag 201 //! \param [in] pBlock 202 //! Pointer to memory block to be submitted 203 //! \param [in] dwSyncTag 204 //! Sync tag 205 //! \return MOS_STATUS 206 //! Returns the status of the operation 207 //! 208 MOS_STATUS SubmitBlock( 209 PMHW_STATE_HEAP_MEMORY_BLOCK pBlock, 210 const FrameTrackerTokenFlat *trackerToken); 211 212 //! 213 //! \brief Set state heap to block manager 214 //! \details Set state heap to block manager 215 //! \param [in] pStateHeap 216 //! Pointer to state heap 217 //! 218 void SetStateHeap(PMHW_STATE_HEAP pStateHeap); 219 220 // Multiple Block Allocation algorithm description (multiple kernel load): 221 // 222 // Multiple blocks must be efficiently allocated in multiple heaps or in a single heap. 223 // 224 // Each load may introduce block fragmentation. The more kernels are loaded, the greater 225 // are the chances to fragment the heap, reducing the chances of finding contiguous for a 226 // larger kernel. Therefore, the efficient way to use the heap is to load larger kernels 227 // first ensuring they have enough contiguous space, and then load the smaller kernels, 228 // which are more likely to fit in remaining blocks. 229 // 230 // So the algorithm is the following: 231 // 232 // 1) The total size of all blocks is calculated to check if there's even a fighting chance 233 // to load them all - if the amount available is insufficient, other measures will be taken. 234 // 235 // 2) In order to allocate blocks according to size, we first sort the array of sizes 236 // using an index array (never touching the source array!) - this is done by a merge sort 237 // implementation, which is O(n*log(n)) - may try using other algorithm such as QuickSort - 238 // although quicksort is not always the best (may be O(n^2) in same cases) 239 // 240 // 3) Select a specific heap (or nullptr if bHeapAffinity is false). Check if there is enough space 241 // to load all blocks - ignoring the fragmentation for now. Only by traversing the list of 242 // blocks we will be able to determine if the heap can be used or not. Trying to load larger 243 // kernels FIRST helps identifying heap fragmentation issues faster than leaving it for last. 244 // 245 // 4) Load the array of kernels one at a time according to size (larger first). Select a specific 246 // heap or nullptr (if any heap, don't care). 247 // 248 // 5) If all succeeded, then we are ready to return the list of blocks to the client. 249 // 250 // 6) If it fails, release the already allocated blocks. the algorithm does check for space in the 251 // current heap before even starting the loop. The failure will not happen for lack of space, 252 // but because of fragmentation of free space. In case of bHeapAffinity = false, we also check 253 // the aggregate free space. 254 // 255 // 7) If the heap affinity is selected and the intended heap is also provided, we're done - if we 256 // were not able to load the blocks, the overall operation has failed. If affinity is selected but 257 // the heap was not provided, we try the next heap until no more heaps are available. This particular 258 // situation is intended for loading all blocks in the same heap without specifying which one. 259 // 260 261 //! 262 //! \brief Allocate multiple blocks 263 //! \details Allocate multiple blocks 264 //! \param [in] pdwSizes 265 //! Pointer to sizes 266 //! \param [in] iCount 267 //! Count of blocks to be allocated 268 //! \param [in] dwAlignment 269 //! Alignment 270 //! \param [in] bHeapAffinity 271 //! true if all blocks must be allocated in the same heap 272 //! \param [in] pHeapAffinity 273 //! Pointer to heap affinity 274 //! \return PMHW_STATE_HEAP_MEMORY_BLOCK 275 //! Pointer to allocated memory block 276 //! 277 PMHW_STATE_HEAP_MEMORY_BLOCK AllocateMultiple( 278 uint32_t *pdwSizes, 279 int32_t iCount, 280 uint32_t dwAlignment, 281 bool bHeapAffinity, 282 PMHW_STATE_HEAP pHeapAffinity); 283 284 private: 285 286 //! 287 //! \brief Gets memory block from pool 288 //! \details Gets memory block from pool, extending the pool if necessary 289 //! \return PMHW_STATE_HEAP_MEMORY_BLOCK 290 //! Returns a pointer to the memory block, nullptr if failed to allocate or 291 //! all blocks are in use and the pool reached its maximum size. 292 //! 293 PMHW_STATE_HEAP_MEMORY_BLOCK GetBlockFromPool(); 294 295 //! 296 //! \brief Extends pool of MHW_STATE_HEAP_MEMORY_BLOCK objects 297 //! \details Allocates an array of MHW_STATE_HEAP_MEMORY_BLOCK objects and appends to the pool of objects for reuse. 298 //! The allocation of memory block structures is limited to the maximum number defined when creating 299 //! the Memory Block Manager object. The increase in number of memory blocks may be due to increased 300 //! block fragmentation, system load or other factors (increase in queue depth, increas in memory 301 //! blocks maintained by the client - such as number of kernels loaded). 302 //! \param [in] dwCount 303 //! Number of additional blocks to add to the pool 304 //! \return N/A 305 //! 306 void ExtendPool(uint32_t dwCount); 307 308 //! 309 //! \brief Attach block into appropriate memory block list 310 //! \details Sets block state and inserts it into the memory block list associated with the new state. 311 //! The block may be inserted at the "Head" or "Tail" of the list, or after another block from the same list. 312 //! \param [in]BlockState 313 //! New block state, defines which list the block is to be inserted. 314 //! NOTE: The block must not belong to any other list before calling this function (pPrev/pNext = nullptr). 315 //! \param [in] pBlock 316 //! Pointer to memory block 317 //! \param [in] pBlockPos 318 //! Pointer to memory block after which the block is to be inserted (inserted AFTER pBlockPos) 319 //! If set to MHW_BLOCK_POSITION_HEAD, inserts block at the head of the list. 320 //! If set to MHW_BLOCK_POSITION_TAIL, inserts block at the tail of the list. 321 //! \return MOS_STATUS 322 //! Returns error code 323 //! 324 MOS_STATUS AttachBlock( 325 MHW_BLOCK_STATE BlockState, 326 PMHW_STATE_HEAP_MEMORY_BLOCK pBlock, 327 PMHW_STATE_HEAP_MEMORY_BLOCK pBlockPos); 328 329 //! 330 //! \brief INTERNAL function to insert a block into a block list. 331 //! \details Insert a block into a block list at a given position (head, tail, insert after block) 332 //! Ensures that the list and the block position are both valid. 333 //! Does not check if the block is still attached to another list. 334 //! IMPORTANT: Block must be detached, at the risk of corrupting other block lists. 335 //! This function does not track state heap usage 336 //! \param [in] pList 337 //! Pointer to memory block list structure 338 //! \param [in] BlockState 339 //! New block state, defines the state of the new block, 340 //! must match the state associated with the list and reference block 341 //! \param [in] pBlock 342 //! Pointer to memory block to be inserted 343 //! \param [in] pBlockPos 344 //! Pointer to memory block after which the block is to be inserted (inserted AFTER pBlockPos) 345 //! If set to MHW_BLOCK_POSITION_HEAD, inserts block at the head of the list. 346 //! If set to MHW_BLOCK_POSITION_TAIL, inserts block at the tail of the list. 347 //! \return MOS_STATUS 348 //! Returns error code 349 //! 350 MOS_STATUS AttachBlockInternal( 351 PMHW_BLOCK_LIST pList, 352 MHW_BLOCK_STATE BlockState, 353 PMHW_STATE_HEAP_MEMORY_BLOCK pBlock, 354 PMHW_STATE_HEAP_MEMORY_BLOCK pBlockPos); 355 356 //! 357 //! \brief Removes a block from a memory block list 358 //! \details Removes a block from a memory block list from a given 359 //! \param [in] BlockState 360 //! Block state defines from which list the block is to be removed. 361 //! \param [in] pBlockPos 362 //! Defines the object in list to be detached. 363 //! If set to MHW_BLOCK_POSITION_HEAD, detaches the first block in the list. 364 //! If set to MHW_BLOCK_POSITION_TAIL, detaches the last block in the list. 365 //! \return PMHW_STATE_HEAP_MEMORY_BLOCK 366 //! Returns a pointer to the block detached, nullptr if the list is empty or invalid. 367 //! 368 PMHW_STATE_HEAP_MEMORY_BLOCK DetachBlock( 369 MHW_BLOCK_STATE BlockState, 370 PMHW_STATE_HEAP_MEMORY_BLOCK pBlockPos); 371 372 //! 373 //! \brief INTERNAL function to remove a block from a block list. 374 //! \details Removes a block from a list provided. The caller may specify the block 375 //! to remove, or request the head or tail of the list. 376 //! Ensures that the list and the block position are both valid. 377 //! Does not check if the block is still attached to another list. 378 //! IMPORTANT: Block must be detached, at the risk of corrupting other block lists. 379 //! This function does not track state heap usage 380 //! \param [in] pList 381 //! Pointer to memory block list structure 382 //! \param [in] pBlock 383 //! Pointer to memory block to be inserted 384 //! \return PMHW_STATE_HEAP_MEMORY_BLOCK 385 //! Returns block, nullptr if failure or no block available 386 //! 387 PMHW_STATE_HEAP_MEMORY_BLOCK DetachBlockInternal( 388 PMHW_BLOCK_LIST pList, 389 PMHW_STATE_HEAP_MEMORY_BLOCK pBlock); 390 391 //! 392 //! \brief Interface to move block from one list to another 393 //! \details Moves a block from a list into another 394 //! Ensures that the list and the block position are both valid. 395 //! Does not check if the block is still attached to another list. 396 //! IMPORTANT: Block must be detached, at the risk of corrupting other block lists. 397 //! This function does not track state heap usage 398 //! \param [in] pSrcList 399 //! Pointer to source list 400 //! \param [in] pDstList 401 //! Pointer to destination list 402 //! \param [in] pBlock 403 //! Pointer to memory block to be moved 404 //! \param [in] pBlockPos 405 //! Pointer to memory block after which the block is to be inserted (inserted AFTER pBlockPos) 406 //! If set to MHW_BLOCK_POSITION_HEAD, inserts block at the head of the list. 407 //! If set to MHW_BLOCK_POSITION_TAIL, inserts block at the tail of the list. 408 //! \return MOS_STATUS 409 //! Returns error code 410 //! 411 MOS_STATUS MoveBlock( 412 PMHW_BLOCK_LIST pSrcList, // Source list 413 PMHW_BLOCK_LIST pDstList, // Destination list 414 PMHW_STATE_HEAP_MEMORY_BLOCK pBlock, // Block to be moved (or HEAD/TAIL of source list) 415 PMHW_STATE_HEAP_MEMORY_BLOCK pBlockPos); // Position to insert (or HEAD/TAIL of target list) 416 417 //! 418 //! \brief Returns memory block object to pool 419 //! \details Returns memory block object to pool 420 //! \param [in] pBlock 421 //! Pointer to memory block to be returned back to pool 422 //! \return N/A 423 //! 424 void ReturnBlockToPool(PMHW_STATE_HEAP_MEMORY_BLOCK pBlock); 425 426 //! 427 //! \brief Consolidate free memory 428 //! \details Consolidate free memory blocks adjacent to a given free block (within the same state heap). 429 //! \param [in] pBlock 430 //! Pointer to free memory block 431 //! \return N/A 432 //! 433 void ConsolidateBlock(PMHW_STATE_HEAP_MEMORY_BLOCK pBlock); 434 435 //! 436 //! \brief INTERNAL: Move block from free to allocated list 437 //! \details Move block from free to allocated list, setting up pointer/offset to data 438 //! \param [in] pBlock 439 //! Pointer to free memory block 440 //! \param uint32_t dwAlignment 441 //! [in] Data alignment, assured to be power of 2 by caller 442 //! \return MOS_STATUS 443 //! Returns the status of the operation 444 //! 445 MOS_STATUS AllocateBlockInternal( 446 PMHW_STATE_HEAP_MEMORY_BLOCK pBlock, 447 uint32_t dwAlignment); 448 449 //! 450 //! \brief Split block internal 451 //! \details Split block internal 452 //! \param [in] pBlock 453 //! Pointer to block to be splitted 454 //! \param [in] dwSplitSize 455 //! Size of the block to be splitted 456 //! \param [in] dwAlignment 457 //! Data alignment, assured to be power of 2 by caller 458 //! \param [in] bBackward 459 //! if true, use higher part of the block 460 //! \return MOS_STATUS 461 //! Returns the status of the operation 462 //! 463 MOS_STATUS SplitBlockInternal( 464 PMHW_STATE_HEAP_MEMORY_BLOCK pBlock, 465 uint32_t dwSplitSize, 466 uint32_t dwAlignment, 467 bool bBackward); 468 469 //! 470 //! \brief Merge blocks 471 //! \details Merge blocks 472 //! \param [in] pBlockL 473 //! Pointer to block in lower memory 474 //! \param [in] pBlockH 475 //! Pointer to block in higher memory 476 //! \param [in] dwAlignment 477 //! Data alignment, assured to be power of 2 by caller 478 //! \param [in] bBackward 479 //! if True, pBlcokL is merged into pBlockH 480 //! if False, pBlockH is merged into pBlockL 481 //! \return MOS_STATUS 482 //! Returns the status of the operation 483 //! 484 MOS_STATUS MergeBlocksInternal( 485 PMHW_STATE_HEAP_MEMORY_BLOCK pBlockL, 486 PMHW_STATE_HEAP_MEMORY_BLOCK pBlockH, 487 uint32_t dwAlignment, 488 bool bBackward); 489 490 //! 491 //! \brief ResizeBlock 492 //! \details ResizeBlock 493 //! \param [in] pBlock 494 //! Pointer to block to be resized 495 //! \param [in] dwNewSize 496 //! new size of block 497 //! \param [in] dwAlignment 498 //! Data alignment, assured to be power of 2 by caller 499 //! \param [in] bBackward 500 //! if True, allow block to grow forward/backwards (moving its start offset) 501 //! if False, Always grow/shrink forward; 502 //! \return MOS_STATUS 503 //! Returns the status of the operation 504 //! 505 MOS_STATUS ResizeBlock( 506 PMHW_STATE_HEAP_MEMORY_BLOCK pBlock, 507 uint32_t dwNewSize, 508 uint32_t dwAlignment, 509 bool bBackward); 510 }; 511 512 #endif // __MHW_BLOCK_MANAGER_H__ 513