blob: bf7ae44120d9098d32f6f7beaf1fdd1352eb984d [file] [log] [blame]
/*
* Copyright (c) 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 heap_manager.cpp
//! \brief Implements functionalities pertaining to the heap manager.
//!
#include "heap_manager.h"
HeapManager::~HeapManager()
{
HEAP_FUNCTION_ENTER;
m_currHeapId = 0;
m_currHeapSize = 0;
m_extendHeapSize = 0;
m_osInterface = nullptr;
}
MOS_STATUS HeapManager::AcquireSpace(
MemoryBlockManager::AcquireParams &params,
std::vector<MemoryBlock> &blocks,
uint32_t &spaceNeeded)
{
HEAP_FUNCTION_ENTER;
// first time space is being acquired, allocate the first heap
if (m_heapIds.empty())
{
HEAP_CHK_STATUS(AllocateHeap(m_currHeapSize));
}
if (m_behavior != Behavior::clientControlled)
{
if (params.m_staticBlock)
{
HEAP_ASSERTMESSAGE("Static blocks are only allowed when the client controls behavior");
return MOS_STATUS_INVALID_PARAMETER;
}
if (!m_blockManager.IsTrackerDataValid())
{
HEAP_ASSERTMESSAGE("A tracker must be registered before acquiring space if client does not control behavior");
return MOS_STATUS_INVALID_PARAMETER;
}
}
spaceNeeded = 0;
MOS_STATUS acquireSpaceResult = m_blockManager.AcquireSpace(params, blocks, spaceNeeded);
if (acquireSpaceResult == MOS_STATUS_CLIENT_AR_NO_SPACE)
{
bool blocksUpdated = false;
// no need to refresh the block states for every space acquisition
// attempt for first AcquireSpace failure
HEAP_CHK_STATUS(m_blockManager.RefreshBlockStates(blocksUpdated));
if (blocksUpdated)
{
if ((m_blockManager.AcquireSpace(params, blocks, spaceNeeded)) ==
MOS_STATUS_CLIENT_AR_NO_SPACE)
{
// if space may not be acquired after refreshing block states, execute behavior
HEAP_CHK_STATUS(BehaveWhenNoSpace());
HEAP_CHK_STATUS(m_blockManager.AcquireSpace(params, blocks, spaceNeeded));
}
}
else
{
// if no blocks updated after refresh, execute behavior
HEAP_CHK_STATUS(BehaveWhenNoSpace());
HEAP_CHK_STATUS(m_blockManager.AcquireSpace(params, blocks, spaceNeeded));
}
}
else
{
HEAP_CHK_STATUS(acquireSpaceResult);
}
return MOS_STATUS_SUCCESS;
}
MOS_STATUS HeapManager::ClearSpace(MemoryBlock &block)
{
HEAP_FUNCTION_ENTER;
if (m_behavior != clientControlled)
{
HEAP_ASSERTMESSAGE("Only client controlled behavior allows for clients to clear space");
return MOS_STATUS_INVALID_PARAMETER;
}
HEAP_CHK_STATUS(m_blockManager.ClearSpace(block))
return MOS_STATUS_SUCCESS;
}
MOS_STATUS HeapManager::RegisterTrackerResource(uint32_t *trackerData)
{
HEAP_FUNCTION_ENTER;
return m_blockManager.RegisterTrackerResource(trackerData);
}
MOS_STATUS HeapManager::RegisterTrackerProducer(FrameTrackerProducer *trackerProducer)
{
HEAP_FUNCTION_ENTER;
return m_blockManager.RegisterTrackerProducer(trackerProducer);
}
MOS_STATUS HeapManager::SetInitialHeapSize(uint32_t size)
{
HEAP_FUNCTION_ENTER;
if (size == 0)
{
HEAP_ASSERTMESSAGE("0 is an invalid size for heap extension");
return MOS_STATUS_INVALID_PARAMETER;
}
m_currHeapSize = MOS_ALIGN_CEIL(size, m_heapAlignment);
return MOS_STATUS_SUCCESS;
}
MOS_STATUS HeapManager::SetExtendHeapSize(uint32_t size)
{
HEAP_FUNCTION_ENTER;
if (size == 0)
{
HEAP_ASSERTMESSAGE("0 is an invalid size for heap extension");
return MOS_STATUS_INVALID_PARAMETER;
}
if (m_behavior == Behavior::wait)
{
HEAP_ASSERTMESSAGE("The heap may not be extended in the case of wait behavior");
return MOS_STATUS_INVALID_PARAMETER;
}
m_extendHeapSize = MOS_ALIGN_CEIL(size, m_heapAlignment);
return MOS_STATUS_SUCCESS;
}
MOS_STATUS HeapManager::RegisterOsInterface(PMOS_INTERFACE osInterface)
{
HEAP_FUNCTION_ENTER;
HEAP_CHK_NULL(osInterface);
m_osInterface = osInterface;
HEAP_CHK_STATUS(m_blockManager.RegisterOsInterface(m_osInterface));
return MOS_STATUS_SUCCESS;
}
uint32_t HeapManager::GetTotalSize()
{
HEAP_FUNCTION_ENTER;
uint32_t totalSize = m_blockManager.GetSize();
// Since allocation is delayed to when space is acquired, it is possible
// for manager to be in a valid state if a size of 0 is returned.
if (totalSize == 0 && m_currHeapId == Heap::m_invalidId)
{
totalSize = m_currHeapSize;
}
return totalSize;
}
MOS_STATUS HeapManager::AllocateHeap(uint32_t size)
{
HEAP_FUNCTION_ENTER;
HEAP_CHK_NULL(m_osInterface);
if (size == 0)
{
HEAP_ASSERTMESSAGE("0 is an invalid size for heap allocation");
return MOS_STATUS_INVALID_PARAMETER;
}
++m_currHeapId;
m_heapIds.push_back(m_currHeapId);
HEAP_CHK_STATUS(m_blockManager.RegisterHeap(m_currHeapId, size, m_hwWriteOnlyHeap));
return MOS_STATUS_SUCCESS;
}
void HeapManager::FreeHeap()
{
// Free oldest heap
auto heapId = m_heapIds.front();
m_heapIds.pop_front();
m_blockManager.UnregisterHeap(heapId);
}
MOS_STATUS HeapManager::Wait()
{
HEAP_FUNCTION_ENTER_VERBOSE;
bool blocksUpdated = false;
for (auto waitMs = m_waitTimeout; waitMs > 0; waitMs -= m_waitIncrement)
{
MOS_Sleep(m_waitIncrement);
HEAP_CHK_STATUS(m_blockManager.RefreshBlockStates(blocksUpdated));
if (blocksUpdated)
{
break;
}
}
return (blocksUpdated) ? MOS_STATUS_SUCCESS : MOS_STATUS_CLIENT_AR_NO_SPACE;
}
MOS_STATUS HeapManager::BehaveWhenNoSpace()
{
HEAP_FUNCTION_ENTER_VERBOSE;
switch (m_behavior)
{
case wait:
HEAP_CHK_STATUS(Wait());
break;
case extend:
m_currHeapSize += m_extendHeapSize;
HEAP_CHK_STATUS(AllocateHeap(m_currHeapSize));
break;
case destructiveExtend:
FreeHeap();
m_currHeapSize += m_extendHeapSize;
HEAP_CHK_STATUS(AllocateHeap(m_currHeapSize));
break;
case waitAndExtend:
if (Wait() == MOS_STATUS_CLIENT_AR_NO_SPACE)
{
m_currHeapSize += m_extendHeapSize;
HEAP_CHK_STATUS(AllocateHeap(m_currHeapSize));
}
break;
case clientControlled:
// heap manager gives control back to the client
return MOS_STATUS_CLIENT_AR_NO_SPACE;
default:
HEAP_ASSERTMESSAGE("The requested behavior is not yet implemented");
return MOS_STATUS_UNIMPLEMENTED;
}
return MOS_STATUS_SUCCESS;
}