pmem是android为DSP vpu gpu等设备提供的一种内存分配机制,我们都知道vpu gpu这一类设备需要大块的连续物理内存以便进行硬件解码,硬件显示加速。PMEM就像一个小型的buddy内存管理系统,独立于linux kernel内存管理模块管理,不会受到内存管理中的外碎片的影响,同时还可以灵活的提供额外功能。
当然在系统运行一段时间后,PMEM也同样面临着外碎片问题,因此PMEM内存区的使用者尽量分配大块的内存,而不是零星的小内存。
应用层使用方法
1. 分配的内存只在一个进程中使用
pmem_fd = open("/dev/pmem_gpu", O_RDWR, 0);
pmem_base = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, pmem_fd, 0);
2. 不同进程间共享。这利用了PMEM 驱动的Connect功能
进程1:
pmem_fd0 = open("/dev/pmem_gpu", O_RDWR, 0);
pmem_base = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, pmem_fd0, 0);
进程2:
pmem_fd1 = open("/dev/pmem_gpu", O_RDWR, 0);
ret = ioctl(pmem_fd1, PMEM_CONNECT, pmem_fd0);
ret = ioctl(pmem_fd1, PMEM_MAP, ®ion1);
一个进程打开PMEM设备,通过mmap操作映射内存到进程空间,该进程称为PMEM的master进程。其他进程可以再次打开该设备,然后通过PMEM_CONNECT操作,pmem_fd1就和pmem_fd0获得了相同的Pmem空间,这样该进程就称为PMEM的client进程。
PMEM设备接口
内核为每一个PMEM创建一个misc 设备节点,应用层通过这个设备节点的file_operations操作PMEM设备。
内存分配:
PMEM内存是供应用空间程序使用的,kernel和驱动并不会使用PMEM。应用程序首先打开相应PMEM设备节点,使用mmap系统调用或者PMEM_MAP PMEM_ALLOCATE ioctl申请pmem内存
内存释放:
应用程序可以显示的调用PMEM_UNMAP来释放分配的pmem内存,文件release操作会释放这个PMEM设备所有分配的内存。因此只要close了文件,那么就保证所有分配的内存都被回收,防止由于用户疏忽或者程序异常造成的内存泄漏。
获取物理内存地址
sometimes,应用空间需要获取物理地址
ioctl PMEM_GET_PHYS 获取pmem内存物理地址,我们知道pmem驱动维护着多个pmem设备,并且每个pmem设备还可能进行多次分配。那么这里是如何确定请求哪个pmem设备,哪一次分配的物理地址呢?
通过设备节点的从设备号,就可以确定这次请求的pmem设备;此外在file结构的private_data是一个pmem_data结构,pmem_data->index指向了最后一次分配的索引位置。因此PMEM_GET_PHYS获取的是这个pmem设备最后一次分配内存的起始物理地址。
PMEM_GET_SIZE, PMEM_GET_TOTAL_SIZE
PMEM_GET_SIZE用来获取给定PMEM设备最后一次分配的size;而PMEM_GET_TOTAL_SIZE则获取给定PMEM的整个空间size
PMEM_CACHE_FLUSH
刷新给定内存区的cache,dmac_flush_range包括writeback和invalidate操作,使得写cache写回,读cache无效