一、Camx内存池架构简介
1.1内存池使用的优点
起首,在项目中假如频仍的使用malloc申请内存空间,堆上分配和开释内存,会导致性能的丧失。由于堆空间申请的存储地点是不连续的,也会使体系中出现的大量的内存碎片,低沉内存的使用率,而内存池的使用就很好的办理了这些性能和内存上的题目。
其次,内存池使用映射到连续物理地点的Ion Buffer(本质是linux的file文件),通过文件形貌符可以实现各个进程间数据的共享,比堆空间的使用范围大多了,能更好的link上下路各个模块间的链路。
1.2Camx内存池架构总览
高通Camx架构中的imageBuffer在pipeline的流转中扮演着告急的作用,而管理imagerBuffer的ImageBufferManager与MemPool Manager共同负担起高通Camx架构中的内存池的调理脚色,下图简单绘制了一下相互的调用关系。
二、Camx ImageBufferManager
代码路径:vendor\qcom\proprietary\camx\src\core\camximagebuffermanager.cpp
vendor\qcom\proprietary\camx\src\core\camximagebuffer.cpp
2.1 ImageBufferManager干系函数分析
2.1.1 ImageBufferManager::Create函数实现如下
- CamxResult ImageBufferManager::Create(
- const CHAR* pBufferManagerName,
- BufferManagerCreateData* pCreateData,
- ImageBufferManager** ppImageBufferManager)
- {
- CamxResult result = CamxResultSuccess;
- ImageBufferManager* pImageBufferManager = NULL;
- if (CamxResultSuccess == result)
- {
- *ppImageBufferManager = NULL;
- pImageBufferManager = CAMX_NEW ImageBufferManager();
- }
-
- if (CamxResultSuccess == result)
- {
- // 从内存池中为ImageBufferManager分配内存
- result = pImageBufferManager->Initialize(pBufferManagerName, pCreateData);
- if (CamxResultSuccess == result)
- {
- CAMX_LOG_INFO(CamxLogGroupMemMgr, "[%s] : allocRequired=%d, immediateAllocBufferCount=%d, maxBufferCount=%d", pBufferManagerName, pCreateData->allocateBufferMemory, pCreateData->immediateAllocBufferCount, pCreateData->maxBufferCount);
- // 初始化ImageBufferManager中的buffers,这里是重点
- result = pImageBufferManager->InitializeBuffers(pCreateData);
- }
- }
- if (CamxResultSuccess == result)
- {
- *ppImageBufferManager = pImageBufferManager;
- }
- return result;
复制代码 2.1.2 ImageBufferManager::InitializeBuffer实现如下
- CamxResult ImageBufferManager::InitializeBuffers(
- BufferManagerCreateData* pCreateData) {
- m_createData = *pCreateData;
- m_currentFormat = pCreateData->bufferProperties.imageFormat;
- m_maxBufferCount = pCreateData->maxBufferCount;
- m_immediateAllocBufferCount = pCreateData->immediateAllocBufferCount;
- // Allocate the minimum number of buffers needed immediately serially
- for (UINT i = 0; i < m_immediateAllocBufferCount; i++)
- {
- // ①new buffer
- ImageBuffer* pBuffer = CAMX_NEW ImageBuffer();
- if (NULL != pBuffer)
- {
- // ②buffer初始化,buffer相关信息放在全局变量m_createData中
- result = pBuffer->Initialize(m_pBufferManagerName, &m_createData, &m_currentFormat, this,m_hMemPoolBufMgrHandle);
- // ③Allocate the buffer
- result = pBuffer->Allocate();
- LDLLNode* pNode = static_cast<LDLLNode*>(CAMX_CALLOC(sizeof(LDLLNode)));
-
- if (NULL != pNode)
- {
- pNode->pData = pBuffer;
- // ④Add the buffer to the free buffer list
- m_freeBufferList.InsertToTail(pNode);
- }
- }
复制代码 2.1.3 ImageBufferManager::GetImageBuffer函数实现如下
①从free-list中找buffer;假如没有
②再去busy-list中找引用计数为0的buffer;照旧没有
③看看能不能自己创建buffer;假如不能创建
④超时等候n次去获取busy-list中引用计数为0的buffer
颠末上述使用,假如能获取到buffer,先添加buffer的引用计数,然后封装成node,放到busy-list链表尾
- ImageBuffer* ImageBufferManager::GetImageBuffer()
- {
- // first:先从free_list的头部取出buffer节点
- LDLLNode* pNode = m_freeBufferList.RemoveFromHead();
- ImageBuffer* pBuffer = NULL;
- // Check the free List for an available buffer
- if (NULL != pNode)
- {
- // 取出buffer节点中的buffer
- pBuffer = static_cast<ImageBuffer*>(pNode->pData);
- CAMX_FREE(pNode); // 释放该节点所占用的内存
- pNode = NULL;
-
-
- }
- // second:如果free_list中没有可用buffer,就去busy_list中去取
- if (NULL == pBuffer)
- {
- // 从头遍历busy_list中的节点
- pNode = m_busyBufferList.Head();
- while (NULL != pNode)
- {
- ImageBuffer* pBusyBuffer = static_cast<ImageBuffer*>(pNode->pData);
- LDLLNode* pNext = LightweightDoublyLinkedList::NextNode(pNode);
- if (0 == pBusyBuffer->GetReferenceCount())
- {
- // 如果该busy-buffer的引用计数为0,说明该buffer可以被使用
- m_busyBufferList.RemoveNode(pNode);
- // 就从busy_list中取出node,这里会先移出,然后后面会再次添加到busy-list的尾部
- if (NULL == pBuffer) {
- // We will keep this buffer
- pBuffer = pBusyBuffer; // 将上述busy-buffer赋值给pBuffer
- CAMX_FREE(pNode); // 释放该节点所占用的内存
- pNode = NULL;
- }
- else
- {
- // 如果从busy-list取节点时刚好发现pBuffer不为空了,而pNode都从busy-list中取出来了,这次不用就下次再用吧,将其放到free-list中
- m_freeBufferList.InsertToTail(pNode);
-
- }
- }
- pNode = pNext;
- }
- }
- // third:如果free-list和busy-list中没有找到引用计数为0的buffer,看看能不能创建buffer
- if (NULL == pBuffer)
- {
-
- UINT numOfFreeBuffers = m_freeBufferList.NumNodes();
- UINT numOfBusyBuffers = m_busyBufferList.NumNodes();
-
- // If no free buffers were found either in the free list or the busy list, we check to see if an additional buffer
- // can be allocated immediately
- if ((numOfFreeBuffers + numOfBusyBuffers) < m_maxBufferCount)
- {
- // 只要没有达到创建buffer的max值,就能额外创建buffer
- CamxResult result = CamxResultSuccess;
- // 下面就是buffer创建三部曲
- pBuffer = CAMX_NEW ImageBuffer();
- if (NULL != pBuffer)
- {
- result = pBuffer->Initialize(m_pBufferManagerName, &m_createData, &m_currentFormat, this, m_hMemPoolBufMgrHandle);
-
- }
- else
- {
- CAMX_LOG_ERROR(CamxLogGroupMemMgr, "[%s] Ran out of memory to allocate", GetBufferManagerName());
- result = CamxResultENoMemory;
- }
-
- if (CamxResultSuccess == result)
- {
- if ((TRUE == m_createData.allocateBufferMemory) &&
- (FALSE == m_createData.bEnableLateBinding))
- {
- // Allocate the buffer
- result = pBuffer->Allocate();
- }
- }
- }
- }
- // four:如果上面三种情况都不满足,那么就只能等待busy-list中的buffer释放了
- if (NULL == pBuffer)
- {
- pNode = NULL;
- while (NULL == pNode)
- {
- // 设置超时等待,接收busy-list中的buffer释放信号
- result = m_pWaitFreeBuffer->TimedWait(m_pLock->GetNativeHandle(), BufferTimeoutMilliseconds);
- pNode = m_freeBufferList.RemoveFromHead();
-
- if (timeoutCount >= MaxTimeoutCount)
- {
- // 这里会进行几次超时等待,如果超过最大等待次数就退出循环,等不下去了,累了!!
- CAMX_LOG_ERROR(CamxLogGroupMemMgr, "[%s] Waited %ux%u times and failed to get buffer, returning a null buffer", GetBufferManagerName(), timeoutCount, BufferTimeoutMilliseconds);
- break;
- }
- else if (CamxResultETimeout == result)
- { // 继续超时等待,死等,还挺执着!!
- // timeout happened, print an error log and continue waiting
- timeoutCount++;
-
- CAMX_LOG_WARN(CamxLogGroupMemMgr, "[%s] Waiting %ux%d ms timedout, there might be a leak or performance issue", GetBufferManagerName(), timeoutCount, BufferTimeoutMilliseconds);
- }
- else if (CamxResultSuccess != result)
- {
- // 函数执行期间遇到错误,退出循环
- timeoutCount++;
- CAMX_LOG_ERROR(CamxLogGroupMemMgr, "[%s] Waiting %dx%d ms failed for unknown reason, result=%s",GetBufferManagerName(), timeoutCount,BufferTimeoutMilliseconds,Utils::CamxResultToString(result));
- break;
- }
- }
-
- // 如果free-list中取到节点了,万事大吉,取其buffer。念念不忘,必有回响!
- if (NULL != pNode)
- {
- pBuffer = static_cast<ImageBuffer*>(pNode->pData);
- CAMX_FREE(pNode);
- pNode = NULL;
- CAMX_LOG_INFO(CamxLogGroupMemMgr, "[%s] Returning a buffer [%p] from the free list after wait ended",GetBufferManagerName(), pBuffer);
- }
-
- }
- // 几经波折,如果能取到buffer,会进一步处理
- if (NULL != pBuffer)
- {
- m_pLock->Unlock();
- pBuffer->AddImageReference(); // 添加buffer的引用计数
- m_pLock->Lock();
- pBuffer->SetBusyState(TRUE); // 我很忙
- pBuffer->ClearReferenceHolderData();
- pNode = static_cast<LDLLNode*>(CAMX_CALLOC(sizeof(LDLLNode)));
-
- if (NULL != pNode)
- {
- pNode->pData = pBuffer;
- m_busyBufferList.InsertToTail(pNode); // 将节点插入到busy-list的尾部
-
- m_peakBufferHolders = Utils::MaxUINT(m_peakBufferHolders, m_busyBufferList.NumNodes());
- }
-
- }
-
- return pBuffer;
- }
复制代码 2.1.4 ImageBufferManager::AddReference函数实现如下
①查察该buffer是否在free-list中,假如在则将其从free-list中移到busy-list中,并添加该buffer的引用计数;假如不在
②查察该buffer是否在busy-list中,假如在则增长该buffer的引用计数。
- UINT ImageBufferManager::AddReference(
- ImageBuffer* pImageBuffer) {
- BOOL doneFlag = FALSE;
- UINT count = 0;
- LDLLNode* pNode;
- // 看看该buffer是不是在free-list中,如果是,则将其从中移除并添加到busy-list中
- pNode = m_freeBufferList.Head();
-
- while (NULL != pNode)
- {
-
- if (pImageBuffer == static_cast<ImageBuffer*>(pNode->pData))
- {
- // Add reference to the image buffer
- count = pImageBuffer->AddImageReference();
- // Move if from free list to busy list
- m_freeBufferList.RemoveNode(pNode);
- pImageBuffer->SetBusyState(TRUE);
- m_busyBufferList.InsertToTail(pNode);
- CAMX_LOG_VERBOSE(CamxLogGroupMemMgr, "[%s] Image buffer %p in free list, reference count after adding = %d",GetBufferManagerName(), pImageBuffer, pImageBuffer->GetReferenceCount());
-
- doneFlag = TRUE;
- break;
- }
- pNode = LightweightDoublyLinkedList::NextNode(pNode);
- }
- // 添加引用的buffer不在freelist中
- if (FALSE == doneFlag)
- {
- pNode = m_busyBufferList.Head();
-
- // Didn't find the image buffer in free list, then search busy list
- while (NULL != pNode)
- {
- // Found the image buffer in busy list
- if (pImageBuffer == static_cast<ImageBuffer*>(pNode->pData))
- {
- // Add reference to the image buffer
- count = pImageBuffer->AddImageReference();
-
- CAMX_LOG_VERBOSE(CamxLogGroupMemMgr, "[%s] Image buffer %p in busy list, reference count after adding = %d",GetBufferManagerName(), pImageBuffer, pImageBuffer->GetReferenceCount());
-
- doneFlag = TRUE;
- break;
- }
- pNode = LightweightDoublyLinkedList::NextNode(pNode);
- }
- }
-
- if (FALSE == doneFlag)
- {
- CAMX_LOG_ERROR(CamxLogGroupMemMgr, "[%s] Add reference to image buffer %p failed.",GetBufferManagerName(), pImageBuffer);
- }
- m_pLock->Unlock();
- return count;
- }
-
- CAMX_INLINE UINT AddImageReference()
- {
- UINT count = CamxAtomicIncU(&m_aReferenceCount); // 引用计数+1
- return count; // 返回添加引用计数后的数值
- }
复制代码 2.1.5 ImageBufferManager::ReleaseReference函数实现如下
①查察该buffer是否在busy-list中;假如在
②查察将该buffer引用计数-1后的引用计数值;假如为0
③将其从busy-list移动到free-list链表中,并发送信号关照那些等候buffer的线程去取buffer(GetImageBuffer中假如取不到buffer,会设置超时等候)
- UINT ImageBufferManager::ReleaseReference(
- ImageBuffer* pImageBuffer)
- {
- BOOL doneFlag = FALSE;
- UINT count = 0;
- LDLLNode* pNode = m_busyBufferList.Head();
-
- while (NULL != pNode)
- {
- // Found the image buffer in busy list,
- if (pImageBuffer == static_cast<ImageBuffer*>(pNode->pData))
- {
- if (0 < pImageBuffer->GetReferenceCount())
- {
- // count为该buffer引用计数-1后的结果
- count = pImageBuffer->ReleaseImageReference();
- if (0 == count)
- {
- // Move the buffer to the free list
- m_busyBufferList.RemoveNode(pNode);
-
- if ((TRUE == m_createData.bEnableLateBinding) &&
- (TRUE == m_createData.allocateBufferMemory) &&
- (TRUE == pImageBuffer->HasBackingBuffer()))
- {
- // If late binding is enabled, release the buffer and just add the holder ImageBuffer object into
- // free list. When this ImageBuffer is acquired, explicit BindBuffer on this ImageBuffer object will be
- // called to allocate or bind the buffer back to this ImageBuffer
- pImageBuffer->Release(FALSE);
- }
-
- pImageBuffer->SetBusyState(FALSE);// 为即将插入到free-list中的buffer设置状态时传参false,为busy-list时传参true
- m_freeBufferList.InsertToTail(pNode);
-
- // 发送信号通知等待此buffer的线程,有buffer用了,不用等了
- m_pWaitFreeBuffer->Signal();
- }
- }
- doneFlag = TRUE;
- break;
- }
-
- pNode = LightweightDoublyLinkedList::NextNode(pNode);
- }
-
- if (FALSE == doneFlag)
- {
- CAMX_LOG_ERROR(CamxLogGroupMemMgr, "[%s] Didn't find the image buffer %p in busy list.",GetBufferManagerName(), pImageBuffer);
- }
- return count;
- }
复制代码 三、Camx MemPoolManager
在对ImageBufferManager接口举行具体阐明后,对MemPoolMgr中怎样获取ImagerBufferManager所需的ImageBuffer举行了下图的关系阐明。
四、Camx ImageBuffer
imageBuffer在pipeline中扮演着非常告急的决议,负责图像数据在node之间的流转。在pipeline中node之间的毗连是靠port来链接的,而port的毗连正是通过共享内存(一组imageBuffer)来实现的
高通Camx架构通过一个 Import 使用,把MemPoolBuffer的bufferInfo,通报给 imagebuffer的bufferInfo。 ImageBuffer 在 pipeline node port口 之间是通过通报这个bufferInfo,把一个node 的outputport 通报给 inputport的。
以下是简单的ImageBuffer在pipeline内里的流转表示图:
五、Ending
本博文告急对一些文章中高通内存池架构/ImageBuffer举行拆分举行框架上的梳理,很多具体的各个模块细节可参考以下博文:
1.ImageBufferManager具体在整个流程中的调用以及ImgeBuffer在pipeline之间的流转:ImageBufferManager先容-CSDN博客
DMABuffer分析_dma buffer-CSDN博客
2.MemPoolMgr与ImageBufferManager之间更具体的link以及更深条理的涉及明白:DMABuffer分析_dma buffer-CSDN博客
3.关于ION buffer本质与mmap映射使用更具体的阐明:
Android ION 干系信息查察方法_kernel查察ion-CSDN博客
ION根本概念先容和原理分析_ion buffer-CSDN博客
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金 |