Davinci的异构多核间通信基础组件SysLink
3.5、HeapMP
HeapMP主要包括HeapBufMP和HeapMemMP,用于共享内存区的堆内存配置和管理。
HeapMP具备以下几个特征:
支持多宿主,即无论是运行HLOS的主处理器还是运行SYS/BIOS的从处理器都可以配置和管理堆内存;
可以将共享内存区配置成缓冲池(buffer pools);
可以从共享内存区分配和释放缓冲区;
3.5.1、HeapBufMP
HeapBufMP为用户提供了固定大小的缓冲池管理接口;
HeapBufMP组件为用户提供的API接口如下:
HeapBufMP创建/删除:HeapBufMP_create();HeapBufMP_delete();
HeapBufMP打开/关闭:HeapBufMP_open();HeapBufMP_close();
HeapBufMP参数初始化:HeapBufMP_Params_init();
HeapBufMP分配/释放内存:HeapBufMP_alloc();HeapBufMP_free();
HeapBufMP获取所有状态:HeapBufMP_getExtendedStats();HeapBufMP_getStats();
3.5.2、HeapMultiBufMP
在SysLink包中并没有找到相关API,但SysLink UserGuide中有提到.
HepMultiBufMP为用户提供了可配置大小的缓冲池管理接口。
3.5.3、HeapMemMP
HeapMemMp为用户提供了基于堆的可变大小的内存管理机制。
HeapMemMp组件为用户提供的接口如下:
HeapMemMP参数初始化:HeapMemMP_Params_init();
HeapMemMP创建/删除:HeapMemMP_create()/HeapMemMP_delete();
HeapMemMP打开/关闭:HeapMemMP_open()/HeapMemMP_close();
HeapMemMP分配/释放内存:HeapMemMP_alloc()/HeapMemMP_free();
HeapMemMP获取内存状态:HeapMemMP_getExtendedStats()/HeamMemMP_getStats();
HeapMemMP恢复内存初始状态:HeapMemMP_restore();
3.6、FrameQ
FrameQ是专门为传递视频帧而设计出来的组件。FrameQ的基本数据结构是可用于queue/dequeue数据的数据队列,封装了视频帧缓存指针、帧数据类型、帧宽、帧高、时间戳等信息。
对于FrameQ模块具有以下特征:
支持多个读者,但写者唯一;
可以分配和释放Frames;
可以对指向同一块内存区多次分配和初始化成新的帧buffer;
FrameQ允许有多个队列,在多通道的运用中,视频帧会根据通道号被分配到相应的帧队列中;
FrameQ中用于buffer管理的模块称为FrameQBufMgr,该模块用于提供buffer管理接口和通知机制。
FrameQ提供以下API接口:
FrameQ组件初始化/销毁:FrameQ_setup()/FrameQ_destroy();
创建/删除FrameQ实例:FrameQ_create()/FrameQ_delete();
打开/关闭FrameQ实例:FrameQ_open()/FrameQ_close();FrameQ_openByAddr();
为FrameQ实例分配/释放内存:FrameQ_alloc()/FrameQ_free();FrameQ_allocv/FrameQ_freev();
插入/释放FrameQ中帧:FrameQ_put()/FrameQ_get();FrameQ_putv()/FrameQ_getv();
复制给定的帧:FrameQ_dup();
注册/注销FrameQ通知:FrameQ_registerNotifier()/FrameQ_unregisterNotifier();
强制发送通知:FrameQ_sendNotify()
获取FrameQ中有效帧数/已被释放的帧数:FrameQ_getNumFrames()/FrameQ_getNumFreeFrames(); - FrameQ_getvNumFrames()/FrameQ_getvNumFreeFrames()
- FrameQ控制:FrameQ_control()
复制代码
获取FrameQ的头指针:FrameQ_getExtendedHeaderPtr();
获取帧buffer/帧大小/帧数:FrameQ_getFrameBuffer()/FrameQ_getFrameBufSize()/FrameQ_getNumFrameBuffers();
获取空数据帧大小/位置:FrameQ_getFrameBufValidSize()/FrameQ_getFrameBufDataStartOffset();
设置空数据帧大小/位置:FrameQ_setFrameBufValidSize()/FrameQ_setFrameBufDataStartOffset();
获取FrameQ默认设置:FrameQ_getConfig();
3.7、RingIO
RingIO是基于数据流的环形缓冲buffer,而且针对于音视频数据的特性做了优化。
RingIO支持一下特性:
仅支持一个读者和一个写者;
读写相对独立,可以在不同的进程或者处理器中同时进行读写操作;
RingIO为用户提供了以下接口:
1.RingIO参数初始化:RingIO_Params_init();
2.创建/删除RingIO对象:RingIO_create()/RingIO_delete();
3.打开/关闭RingIO对象:RingIO_open()/RingIO_close();RingIO_openByAddr();
4.获取共享内存请求:RingIO_sharedMemReq();
5.注册/注销RingIO通知:RingIO_registerNotifier()/RingIO_unregisterNotifier();
6.强制发送RingIO通知:RingIO_sendNotify();
7.获取RingIO通知类型:RingIO_setNotifyType();
8.设置/获取水印标志/通知类型:RIngIO_setWaterMark()/RIngIO_getWaterMark()
9.获取/释放RingIO数据:RingIO_acquire()/RingIO_release();
10.设置/获取RingIO属性:RingIO_setvAttribute()/RingIO_getvAttribute();
11.设置/获取RingIO固定大小的属性:RingIO_setAttribute()/RingIO_getAttribute();
12.刷新RingIO的buffer:RingIO_flush();
13.获取有效/空buffer大小:RingIO_getValidSize()/RingIO_getEmptySize();
14.获取有效/空属性大小:RingIO_getValidAttrSize()/RingIO_getEmptyAttrSize();
15.获取用户需求buffer的大小/位置:RingIO_getAcquiredSize()/RingIO_getAcquiredOffset();
4、公共组件(基础组件)
Utility Modules包括SharedRegion(IPC中属于类库ti.sdo.ipc.SharedRegion)、List、Trace、MultiProc、NameServer等,这些模块是上层组件实现的基础。在IPC包中,该组件对应于类库ti.sdo.utils.
4.1、SharedRegion(非常重要,SysLink模块最基础的模块)
4.1.1、SharedRegion总览
SharedRegion顾名思义,是共享内存区的意思。SharedRegion模块负责管理共享内存区。在一个有共享内存的多核架构中,普遍会遇到共享内存映射虚拟地址转换问题,如下图所示:
SharedRegion有两种配置方式,即静态配置方法(对于SYS/BIOS侧可以通过cfg脚本配置,而对于HLOS则当从处理器被加载的时候会通过读取SYS/BIOS共享内存区配置信息来获取,请参考内核driver/dsp/syslink/notify_shmdriver/notify_shm_drv.c中实现)和动态配置方法(通过SharedRegion模块提供的API SharedRegion_setEntry()来设置,但值得注意的是这个API只是把入口信息放入该处理器对应的共享内存查找表中,而其他处理器也需要在自己的系统中使用该API来加入该入口)。实际配置中需要指明共享内存区在各个处理器中映射的虚拟地址及堆栈设置等,如上图所示,对于proc0来说,SR0映射出的虚拟地址为0x80000000,而对于Proc[1..3]映射出的地址则是0x90000000;SR0中有部分预留区域且被配置成HeapMemMP(见3.5.3节);此外由上图还可以知道,SharedRegion 1是Proc1--Proc6构成的子系统的内部共享内存,且配置成使用HeapMemMP来管理。
SharedRegion模块由于其状态都存在处理器本地的内存中,因此其本身并不会占用共享内存区空间。所有的SharedRegion模块API都是用Gate用于进程互斥操作。
SharedRegion模块会为系统中每个处理器创建一个共享内存查找表。在这个查找表中包含了所有处理器与共享内存区的关系及相关设置。如果某块共享内存区对于某处理器是不能访问,那么在表中会设置为空。
在runtime时,共享内存查找表与共享内存区指针一起被用于快速的地址转换操作;
在共享内存查找表中最大入口数(即SharedRegion的个数)使用ShareRegion.numEntries静态配置。在系统runtime中可以使用静态配置或者动态配置增减入口数,但必须在更改后更新所有处理器的表。共享内存入口数越多耗费在地址转换上的时间越长,因此考虑到效率,尽可能设计少的入口数。
SharedRegion 0的意义比较特殊,在所有使用IPC组建的环境中都必须配置并且所有的处理器都有权限访问该共享区域,虽然应用程序也可以使用这部分内存,但不建议用户在不了解该区域详细的内存分布时使用,否则容易造成系统挂死。由DM8168的配置DVRRDK_xx.xx.xx.xx\dvr_rdk\mcfw\src_bios6\cfg\ti816x\SYSLINK_common.cfg可以看出该区域用于MsgQ。
4.1.2、SharedRegion配置方式举例
一般来说配置一个SharedRegion需要设置以下几个:
base - The base address共享内存区的基地址,这个所谓的基地址实际上是映射后的虚拟地址,并非物理地址;
len - The length共享内存区的大小,对于同一片共享内存,其所有者的查找表中该项值应该是相同的;
name - The name of the region该共享内存区的名字;
isValid - Whether the region is valid对于该处理器而言,是否具有权限去访问该共享内存区;
ownerProcId - The id of the processor which owns the region管理该内存区的处理器ID,该处理器具有创建HeapMemMP的权限,而其他处理器只有使用的权限;
cacheEnable - Whether the region is cacheable是否为该共享内存区创建cache;
cacheLineSize - The cache line size cache的大小;
createHeap - Whether a heap is created for the region.是否使用Heap(堆)管理该内存区域;
静态配置方法e.g.:DVRRDK_xx.xx.xx.xx\dvr_rdk\mcfw\src_bios6\cfg\ti816x\SYSLINK_common.cfg
- /* Set Shared Region variables by picking up the information from Platform
- * memory map
- */
- var sr0MemSection = Program.cpu.memoryMap['SR0']; //此处值都是有config_xxx.bld文件读取的,下同
- var sr1MemSection = Program.cpu.memoryMap['SR1'];
- var sr2MemSection = Program.cpu.memoryMap['SR2_FRAME_BUFFER_MEM'];
- var sr3MemSection = Program.cpu.memoryMap['SR3_FRAME_BUFFER_EXTRA'];
- /*
- * Need to define the shared region. The IPC modules use this
- * to make portable pointers. All processors need to add this
- * call with their base address of the shared memory region.
- * If the processor cannot access the memory, do not add it.
- This section is the SR0 section of syslink and is
- used for MsgQ's that are present on different processors.
- A8 - NON-CACHED
- M3 - NON-CACHED
- DSP - NON-CACHED
- */
- SharedRegion.setEntryMeta( 0,
- {
- base: sr0MemSection.base,
- len: sr0MemSection.len,
- name: sr0MemSection.name,
- isValid: true,
- ownerProcId: srOwnerProcId,
- cacheEnable: false,
- cacheLineSize: 128,
- createHeap: true
- }
- );
复制代码
注:在IPC中所给的例子除了设置以上需要设置SharedRegion.cacheLineSize、SharedRegion.numEnties、SharedRegion.translate等,如果不知道入口地址,可以讲isValid设置成false,在runtime时通过计算来得到,然后是中SharedRegion_getEntry()来设置。
e.g.
- var SharedRegion = xdc.useModule('ti.sdo.ipc.SharedRegion');
- SharedRegion.cacheLineSize = 32;//cache行缓冲字节数,暂时还没明白这个设置于上面例子中cacheLineSize: 128有何区别,如何不指定则使用默认值;
- SharedRegion.numEntries = 4;//总的共享内存区个数(入口数);
- SharedRegion.translate = true;//是否需要做地址转换,如果设置为false,因为不需要做地址转换,则对总体性能有所提升;
复制代码
动态配置方法e.g.:DVRRDK_xx.xx.xx.xx\dvr_rdk\mcfw\src_bios6\utils\src\utils_mem.c
- SharedRegion_Entry srEntry;
- Int srStatus = SharedRegion_S_SUCCESS;
- UInt32 srId;
- SharedRegion_entryInit(&srEntry);
- SharedRegion_getEntry(srId, &srEntry);
- Vps_printf (" %d: MEM: Shared Region %d: Base = 0x%08x, Length = 0x%08x (%d MB) \n",\
- Utils_getCurTimeInMsec(), srId,srEntry.base,srEntry.len, srEntry.len/(1024*1024));
- if ((FALSE == srEntry.isValid)&&(0 != srEntry.len))
- {
- srEntry.isValid = TRUE;
- do {
- srStatus = SharedRegion_setEntry(srId, &srEntry);
- if (srStatus != SharedRegion_S_SUCCESS) {
- Vps_printf(" %d: MEM: ERROR: SharedRegion_setEntry (%d, 0x%08x) FAILED !!! "
- " (status=%d) \n", Utils_getCurTimeInMsec(), srId, &srEntry, srStatus);
- Task_sleep(1000);
- }
- } while (srStatus != SharedRegion_S_SUCCESS);
- }
- if (srEntry.len)
- {
- gUtils_heapMemHandle = SharedRegion_getHeap(srId);
- UTILS_assert(gUtils_heapMemHandle != NULL);
- gUtils_memClearBuf = FALSE;
- }
复制代码
注:通常来说动态创建入口的方式不常用,一般只是用来更改原有配置。另外,如果想完全重新配置一个共享内存,可以在每个处理器上调用SharedRegion_clear()来清除该共享内存的入口信息。
|