blob: 55ad959da5331c5a1293ce32a048852f6729c4ba [file] [log] [blame]
/*
* Copyright (c) 2015-2017, Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
//!
//! \file mhw_block_manager.h
//! \brief This modules implements state heap block manager used in MHW
//!
#ifndef __MHW_BLOCK_MANAGER_H__
#define __MHW_BLOCK_MANAGER_H__
#include "mos_os.h"
#include "mhw_state_heap.h"
#include "mhw_memory_pool.h"
#define BLOCK_MANAGER_CHK_STATUS(_stmt) \
MOS_CHK_STATUS_RETURN(MOS_COMPONENT_HW, MOS_HW_SUBCOMP_ALL, _stmt)
#define BLOCK_MANAGER_CHK_STATUS_MESSAGE(_stmt, _message, ...) \
MOS_CHK_STATUS_MESSAGE_RETURN(MOS_COMPONENT_HW, MOS_HW_SUBCOMP_ALL, _stmt, _message, ##__VA_ARGS__)
#define BLOCK_MANAGER_CHK_NULL(_ptr) \
MOS_CHK_NULL_RETURN(MOS_COMPONENT_HW, MOS_HW_SUBCOMP_ALL, _ptr)
#define MHW_BLOCK_MANAGER_INVALID_TAG ((uint32_t)-1)
// Maximum allocation array size
#define MHW_BLOCK_MANAGER_MAX_BLOCK_ARRAY 64
typedef struct _MHW_BLOCK_MANAGER_PARAMS
{
uint32_t dwPoolInitialCount; //!< Initial number of memory blocks in pool
uint32_t dwPoolMaxCount; //!< Maximum number of memory blocks in pool
uint32_t dwPoolIncrement; //!< Memory block pool increment
uint32_t dwHeapInitialSize; //!< Initial heap size
uint32_t dwHeapIncrement; //!< Heap size increment
uint32_t dwHeapMaxSize; //!< Maximum overall heap size
uint32_t dwHeapMaxCount; //!< Maximum number of heaps
uint32_t dwHeapGranularity; //!< Block granularity
uint32_t dwHeapBlockMinSize; //!< Minimum block fragment size (never create a block smaller than this)
} MHW_BLOCK_MANAGER_PARAMS, *PMHW_BLOCK_MANAGER_PARAMS;
#define MHW_BLOCK_POSITION_TAIL (NULL)
#define MHW_BLOCK_POSITION_HEAD ((PMHW_STATE_HEAP_MEMORY_BLOCK) -1)
typedef struct _MHW_BLOCK_LIST
{
PMHW_BLOCK_MANAGER pBlockManager; //!< Block Manager the list belongs to
PMHW_STATE_HEAP_MEMORY_BLOCK pHead; //!< Head of the list
PMHW_STATE_HEAP_MEMORY_BLOCK pTail; //!< Tail of the list
MHW_BLOCK_STATE BlockState; //!< Described the type of block the list contains
int32_t iCount; //!< Number of elements on the list
uint32_t dwSize; //!< Total memory in the list
char szListName[16]; //!< List name for debugging purposes
} MHW_BLOCK_LIST, *PMHW_BLOCK_LIST;
struct MHW_BLOCK_MANAGER
{
private:
MHW_BLOCK_MANAGER_PARAMS m_Params; //!< Block Manager configuration
MHW_MEMORY_POOL m_MemoryPool; //!< Memory pool of PMHW_STATE_HEAP_MEMORY_BLOCK objects
MHW_BLOCK_LIST m_BlockList[MHW_BLOCK_STATE_COUNT]; //!< Block lists associated with each block state
PMHW_STATE_HEAP m_pStateHeap; //!< Points to state heap
public:
//!
//! \brief Initializes the MHW_BLOCK_MANAGER
//! \details Constructor of MHW_BLOCK_MANAGER which initializes all parameters and members
//! \param [in] pParams
//! Pointer to block manager params. If it is null, default param will be used.
//!
MHW_BLOCK_MANAGER(PMHW_BLOCK_MANAGER_PARAMS pParams);
//!
//! \brief Destructor of MHW_BLOCK_MANAGER
~MHW_BLOCK_MANAGER();
//!
//! \brief Adds newly created state heap to block manager
//! \details Adds a new state heap to memory block manager. A new memory free memory block is added to
//! the free list representing the new available heap.
//! \param [in] pStateHeap
//! Pointer to the newly created state heap
//! \return MOS_STATUS
//! Returns the status of the operation
//!
MOS_STATUS RegisterStateHeap(PMHW_STATE_HEAP pStateHeap);
//!
//! \brief Unregisters state heap from block manager prior to deallocation
//! \details Removes state heap from block manager. Memory blocks must be all deleted.
//! \param [in] pStateHeap
//! Pointer to the newly created state heap
//! \return MOS_STATUS
//! Returns the status of the operation
//!
MOS_STATUS UnregisterStateHeap(PMHW_STATE_HEAP pStateHeap);
//!
//! \brief Update block states based on last executed tag
//! \details Update block states based on last executed tag
//! submitted unlocked blocks are released;
//! move to allocated
//! \param [in] dwSyncTag
//! sync tag
//! \return MOS_STATUS
//! Returns the status of the operation
//!
MOS_STATUS Refresh();
//!
//! \brief Allocate memory block with scratch space
//! \details Allocate memory block with scratch space
//! \param [in] dwSize
//! Size of memory block to allocate
//! \param [in] dwAlignment
//! Alignment
//! \param [in] dwScratchSpace
//! Scratch space size
//! \return PMHW_STATE_HEAP_MEMORY_BLOCK
//! Pointer to the allocated memory block
//!
PMHW_STATE_HEAP_MEMORY_BLOCK AllocateWithScratchSpace(
uint32_t dwSize,
uint32_t dwAlignment,
uint32_t dwScratchSpace);
//!
//! \brief Allocate free block of memory
//! \details Allocate free memory block of memory for use by the client
//! \param [in] dwSize
//! Size of memory to be allocated
//! \param [in] dwAlignment
//! Memory alignment
//! \param [in] pHeapAffinity
//! Pointer to heap affinity
//! \return PMHW_STATE_HEAP_MEMORY_BLOCK
//! Pointer to allocated memory block
//!
PMHW_STATE_HEAP_MEMORY_BLOCK AllocateBlock(
uint32_t dwSize,
uint32_t dwAlignment,
PMHW_STATE_HEAP pHeapAffinity);
//!
//! \brief Free memory block
//! \details Free memory block according to the sync tag
//! \param [in] pBlock
//! Pointer to memory block to be freed
//! \param [in] dwSyncTag
//! Sync tag
//! \return MOS_STATUS
//! Returns the status of the operation
//!
MOS_STATUS FreeBlock(
PMHW_STATE_HEAP_MEMORY_BLOCK pBlock);
//!
//! \brief Calculate the memory of space required
//! \details Calculate the memory of space required
//! \param [in] pdwSizes
//! Pointer to memory block to be freed
//! \param [in] iCount
//! Sync tag
//! \param [in] dwAlignment
//! alignment
//! \param [in] bHeapAffinity
//! heap affinity
//! \param [in] pHeapAffinity
//! pointer to state heap affinity
//! \return uint32_t Size of space needed by client
//!
uint32_t CalculateSpaceNeeded(
const uint32_t *pdwSizes,
int32_t iCount,
uint32_t dwAlignment,
bool bHeapAffinity,
PMHW_STATE_HEAP pHeapAffinity);
//!
//! \brief Submit memory block
//! \details Submit memory block according to the sync tag
//! \param [in] pBlock
//! Pointer to memory block to be submitted
//! \param [in] dwSyncTag
//! Sync tag
//! \return MOS_STATUS
//! Returns the status of the operation
//!
MOS_STATUS SubmitBlock(
PMHW_STATE_HEAP_MEMORY_BLOCK pBlock,
const FrameTrackerTokenFlat *trackerToken);
//!
//! \brief Set state heap to block manager
//! \details Set state heap to block manager
//! \param [in] pStateHeap
//! Pointer to state heap
//!
void SetStateHeap(PMHW_STATE_HEAP pStateHeap);
// Multiple Block Allocation algorithm description (multiple kernel load):
//
// Multiple blocks must be efficiently allocated in multiple heaps or in a single heap.
//
// Each load may introduce block fragmentation. The more kernels are loaded, the greater
// are the chances to fragment the heap, reducing the chances of finding contiguous for a
// larger kernel. Therefore, the efficient way to use the heap is to load larger kernels
// first ensuring they have enough contiguous space, and then load the smaller kernels,
// which are more likely to fit in remaining blocks.
//
// So the algorithm is the following:
//
// 1) The total size of all blocks is calculated to check if there's even a fighting chance
// to load them all - if the amount available is insufficient, other measures will be taken.
//
// 2) In order to allocate blocks according to size, we first sort the array of sizes
// using an index array (never touching the source array!) - this is done by a merge sort
// implementation, which is O(n*log(n)) - may try using other algorithm such as QuickSort -
// although quicksort is not always the best (may be O(n^2) in same cases)
//
// 3) Select a specific heap (or nullptr if bHeapAffinity is false). Check if there is enough space
// to load all blocks - ignoring the fragmentation for now. Only by traversing the list of
// blocks we will be able to determine if the heap can be used or not. Trying to load larger
// kernels FIRST helps identifying heap fragmentation issues faster than leaving it for last.
//
// 4) Load the array of kernels one at a time according to size (larger first). Select a specific
// heap or nullptr (if any heap, don't care).
//
// 5) If all succeeded, then we are ready to return the list of blocks to the client.
//
// 6) If it fails, release the already allocated blocks. the algorithm does check for space in the
// current heap before even starting the loop. The failure will not happen for lack of space,
// but because of fragmentation of free space. In case of bHeapAffinity = false, we also check
// the aggregate free space.
//
// 7) If the heap affinity is selected and the intended heap is also provided, we're done - if we
// were not able to load the blocks, the overall operation has failed. If affinity is selected but
// the heap was not provided, we try the next heap until no more heaps are available. This particular
// situation is intended for loading all blocks in the same heap without specifying which one.
//
//!
//! \brief Allocate multiple blocks
//! \details Allocate multiple blocks
//! \param [in] pdwSizes
//! Pointer to sizes
//! \param [in] iCount
//! Count of blocks to be allocated
//! \param [in] dwAlignment
//! Alignment
//! \param [in] bHeapAffinity
//! true if all blocks must be allocated in the same heap
//! \param [in] pHeapAffinity
//! Pointer to heap affinity
//! \return PMHW_STATE_HEAP_MEMORY_BLOCK
//! Pointer to allocated memory block
//!
PMHW_STATE_HEAP_MEMORY_BLOCK AllocateMultiple(
uint32_t *pdwSizes,
int32_t iCount,
uint32_t dwAlignment,
bool bHeapAffinity,
PMHW_STATE_HEAP pHeapAffinity);
private:
//!
//! \brief Gets memory block from pool
//! \details Gets memory block from pool, extending the pool if necessary
//! \return PMHW_STATE_HEAP_MEMORY_BLOCK
//! Returns a pointer to the memory block, nullptr if failed to allocate or
//! all blocks are in use and the pool reached its maximum size.
//!
PMHW_STATE_HEAP_MEMORY_BLOCK GetBlockFromPool();
//!
//! \brief Extends pool of MHW_STATE_HEAP_MEMORY_BLOCK objects
//! \details Allocates an array of MHW_STATE_HEAP_MEMORY_BLOCK objects and appends to the pool of objects for reuse.
//! The allocation of memory block structures is limited to the maximum number defined when creating
//! the Memory Block Manager object. The increase in number of memory blocks may be due to increased
//! block fragmentation, system load or other factors (increase in queue depth, increas in memory
//! blocks maintained by the client - such as number of kernels loaded).
//! \param [in] dwCount
//! Number of additional blocks to add to the pool
//! \return N/A
//!
void ExtendPool(uint32_t dwCount);
//!
//! \brief Attach block into appropriate memory block list
//! \details Sets block state and inserts it into the memory block list associated with the new state.
//! The block may be inserted at the "Head" or "Tail" of the list, or after another block from the same list.
//! \param [in]BlockState
//! New block state, defines which list the block is to be inserted.
//! NOTE: The block must not belong to any other list before calling this function (pPrev/pNext = nullptr).
//! \param [in] pBlock
//! Pointer to memory block
//! \param [in] pBlockPos
//! Pointer to memory block after which the block is to be inserted (inserted AFTER pBlockPos)
//! If set to MHW_BLOCK_POSITION_HEAD, inserts block at the head of the list.
//! If set to MHW_BLOCK_POSITION_TAIL, inserts block at the tail of the list.
//! \return MOS_STATUS
//! Returns error code
//!
MOS_STATUS AttachBlock(
MHW_BLOCK_STATE BlockState,
PMHW_STATE_HEAP_MEMORY_BLOCK pBlock,
PMHW_STATE_HEAP_MEMORY_BLOCK pBlockPos);
//!
//! \brief INTERNAL function to insert a block into a block list.
//! \details Insert a block into a block list at a given position (head, tail, insert after block)
//! Ensures that the list and the block position are both valid.
//! Does not check if the block is still attached to another list.
//! IMPORTANT: Block must be detached, at the risk of corrupting other block lists.
//! This function does not track state heap usage
//! \param [in] pList
//! Pointer to memory block list structure
//! \param [in] BlockState
//! New block state, defines the state of the new block,
//! must match the state associated with the list and reference block
//! \param [in] pBlock
//! Pointer to memory block to be inserted
//! \param [in] pBlockPos
//! Pointer to memory block after which the block is to be inserted (inserted AFTER pBlockPos)
//! If set to MHW_BLOCK_POSITION_HEAD, inserts block at the head of the list.
//! If set to MHW_BLOCK_POSITION_TAIL, inserts block at the tail of the list.
//! \return MOS_STATUS
//! Returns error code
//!
MOS_STATUS AttachBlockInternal(
PMHW_BLOCK_LIST pList,
MHW_BLOCK_STATE BlockState,
PMHW_STATE_HEAP_MEMORY_BLOCK pBlock,
PMHW_STATE_HEAP_MEMORY_BLOCK pBlockPos);
//!
//! \brief Removes a block from a memory block list
//! \details Removes a block from a memory block list from a given
//! \param [in] BlockState
//! Block state defines from which list the block is to be removed.
//! \param [in] pBlockPos
//! Defines the object in list to be detached.
//! If set to MHW_BLOCK_POSITION_HEAD, detaches the first block in the list.
//! If set to MHW_BLOCK_POSITION_TAIL, detaches the last block in the list.
//! \return PMHW_STATE_HEAP_MEMORY_BLOCK
//! Returns a pointer to the block detached, nullptr if the list is empty or invalid.
//!
PMHW_STATE_HEAP_MEMORY_BLOCK DetachBlock(
MHW_BLOCK_STATE BlockState,
PMHW_STATE_HEAP_MEMORY_BLOCK pBlockPos);
//!
//! \brief INTERNAL function to remove a block from a block list.
//! \details Removes a block from a list provided. The caller may specify the block
//! to remove, or request the head or tail of the list.
//! Ensures that the list and the block position are both valid.
//! Does not check if the block is still attached to another list.
//! IMPORTANT: Block must be detached, at the risk of corrupting other block lists.
//! This function does not track state heap usage
//! \param [in] pList
//! Pointer to memory block list structure
//! \param [in] pBlock
//! Pointer to memory block to be inserted
//! \return PMHW_STATE_HEAP_MEMORY_BLOCK
//! Returns block, nullptr if failure or no block available
//!
PMHW_STATE_HEAP_MEMORY_BLOCK DetachBlockInternal(
PMHW_BLOCK_LIST pList,
PMHW_STATE_HEAP_MEMORY_BLOCK pBlock);
//!
//! \brief Interface to move block from one list to another
//! \details Moves a block from a list into another
//! Ensures that the list and the block position are both valid.
//! Does not check if the block is still attached to another list.
//! IMPORTANT: Block must be detached, at the risk of corrupting other block lists.
//! This function does not track state heap usage
//! \param [in] pSrcList
//! Pointer to source list
//! \param [in] pDstList
//! Pointer to destination list
//! \param [in] pBlock
//! Pointer to memory block to be moved
//! \param [in] pBlockPos
//! Pointer to memory block after which the block is to be inserted (inserted AFTER pBlockPos)
//! If set to MHW_BLOCK_POSITION_HEAD, inserts block at the head of the list.
//! If set to MHW_BLOCK_POSITION_TAIL, inserts block at the tail of the list.
//! \return MOS_STATUS
//! Returns error code
//!
MOS_STATUS MoveBlock(
PMHW_BLOCK_LIST pSrcList, // Source list
PMHW_BLOCK_LIST pDstList, // Destination list
PMHW_STATE_HEAP_MEMORY_BLOCK pBlock, // Block to be moved (or HEAD/TAIL of source list)
PMHW_STATE_HEAP_MEMORY_BLOCK pBlockPos); // Position to insert (or HEAD/TAIL of target list)
//!
//! \brief Returns memory block object to pool
//! \details Returns memory block object to pool
//! \param [in] pBlock
//! Pointer to memory block to be returned back to pool
//! \return N/A
//!
void ReturnBlockToPool(PMHW_STATE_HEAP_MEMORY_BLOCK pBlock);
//!
//! \brief Consolidate free memory
//! \details Consolidate free memory blocks adjacent to a given free block (within the same state heap).
//! \param [in] pBlock
//! Pointer to free memory block
//! \return N/A
//!
void ConsolidateBlock(PMHW_STATE_HEAP_MEMORY_BLOCK pBlock);
//!
//! \brief INTERNAL: Move block from free to allocated list
//! \details Move block from free to allocated list, setting up pointer/offset to data
//! \param [in] pBlock
//! Pointer to free memory block
//! \param uint32_t dwAlignment
//! [in] Data alignment, assured to be power of 2 by caller
//! \return MOS_STATUS
//! Returns the status of the operation
//!
MOS_STATUS AllocateBlockInternal(
PMHW_STATE_HEAP_MEMORY_BLOCK pBlock,
uint32_t dwAlignment);
//!
//! \brief Split block internal
//! \details Split block internal
//! \param [in] pBlock
//! Pointer to block to be splitted
//! \param [in] dwSplitSize
//! Size of the block to be splitted
//! \param [in] dwAlignment
//! Data alignment, assured to be power of 2 by caller
//! \param [in] bBackward
//! if true, use higher part of the block
//! \return MOS_STATUS
//! Returns the status of the operation
//!
MOS_STATUS SplitBlockInternal(
PMHW_STATE_HEAP_MEMORY_BLOCK pBlock,
uint32_t dwSplitSize,
uint32_t dwAlignment,
bool bBackward);
//!
//! \brief Merge blocks
//! \details Merge blocks
//! \param [in] pBlockL
//! Pointer to block in lower memory
//! \param [in] pBlockH
//! Pointer to block in higher memory
//! \param [in] dwAlignment
//! Data alignment, assured to be power of 2 by caller
//! \param [in] bBackward
//! if True, pBlcokL is merged into pBlockH
//! if False, pBlockH is merged into pBlockL
//! \return MOS_STATUS
//! Returns the status of the operation
//!
MOS_STATUS MergeBlocksInternal(
PMHW_STATE_HEAP_MEMORY_BLOCK pBlockL,
PMHW_STATE_HEAP_MEMORY_BLOCK pBlockH,
uint32_t dwAlignment,
bool bBackward);
//!
//! \brief ResizeBlock
//! \details ResizeBlock
//! \param [in] pBlock
//! Pointer to block to be resized
//! \param [in] dwNewSize
//! new size of block
//! \param [in] dwAlignment
//! Data alignment, assured to be power of 2 by caller
//! \param [in] bBackward
//! if True, allow block to grow forward/backwards (moving its start offset)
//! if False, Always grow/shrink forward;
//! \return MOS_STATUS
//! Returns the status of the operation
//!
MOS_STATUS ResizeBlock(
PMHW_STATE_HEAP_MEMORY_BLOCK pBlock,
uint32_t dwNewSize,
uint32_t dwAlignment,
bool bBackward);
};
#endif // __MHW_BLOCK_MANAGER_H__