回顧2011年底[2],LWN審查了 android kernel patch[3],以指望將這些patch合併到kernel主線中。可是PMEM(android實現的 一個內存分配器)使這個願望破滅了。爲何PMEM不被linux 社區接受的緣由在[3]中有講到。從那開始,PMEM很明確會被徹底拋棄,取而代之的是ION內存管理器。ION是google在Android4.0 ICS爲了解決內存碎片管理而引入的通用內存管理器,它會更加融合kernel。目前QCOM MSM, NVDIA Tegra, TI OMAP, MRVL PXA都用ION替換PMEM。linux
http://android.googlesource.com/kernel/common.gitandroid
ION codes reside in drivers/gpu/iongit
Specific usage examples on omap4:app
http://android.googlesource.com/kernel/omap.git框架
ION 定義了四種不一樣的heap,實現不一樣的內存分配策略。ide
ION_HEAP_TYPE_SYSTEM : 經過vmalloc分配內存函數
ION_HEAP_TYPE_SYSTEM_CONTIG: 經過kmalloc分配內存google
ION_HEAP_TYPE_CARVEOUT: 在保留內存塊中(reserve memory)分配內存spa
ION_HEAP_TYPE_CUSTOM: 由客戶本身定義.net
下圖是兩個client共享內存的示意圖。圖中有2個heap(每種heap都有本身的內存分配策略),每一個heap中分配了若干個buffer。client的handle管理到對應的buffer。兩個client是經過文件描述符fd來實現內存共享的。
定義了6種 ioctl 接口,能夠與用戶應用程序交互。
ION_IOC_ALLOC: 分配內存
ION_IOC_FREE: 釋放內存
ION_IOC_MAP: 獲取文件描述符進行mmap (? 在code中未使用這個定義)
ION_IOC_SHARE: 建立文件描述符來實現共享內存
ION_IOC_IMPORT: 獲取文件描述符
ION_IOC_CUSTOM: 調用用戶自定義的ioctl
ION_IOC_SHARE 及ION_IOC_IMPORT是基於DMABUF實現的,因此當共享進程獲取文件描述符後,能夠直接調用mmap來操做共享內存。mmap實現由DMABUF子系統調用ION子系統中mmap回調函數完成。
內核驅動也能夠註冊爲一個ION的客戶端(client),能夠選擇使用哪一種類型的heap來申請內存。
ion_client_create: 分配一個客戶端。
ion_client_destroy: 釋放一個客戶端及綁定在它上面的全部ion handle.
ion handle: 這裏每一個ion handle映射到一個buffer中,每一個buffer關聯一個heap。也就是說一個客戶端能夠操做多塊buffer。
Buffer 申請及釋放函數:
ion_alloc: 申請ion內存,返回ion handle
ion_free: 釋放ion handle
ION 經過handle來管理buffer,驅動須要能夠訪問到buffer的地址。ION經過下面的函數來達到這個目的
ion_phys: 返回buffer的物理地址(address)及大小(size)
ion_map_kernel: 給指定的buffer建立內核內存映射
ion_unmap_kernel: 銷燬指定buffer的內核內存映射
ion_map_dma: 爲指定buffer建立dma 映射,返回sglist(scatter/gather list)
ion_unmap_dma: 銷燬指定buffer的dma映射
ION是經過handle而非buffer地址來實現驅動間共享內存,用戶空間共享內存也是利用一樣原理。
ion_share: given a handle, obtain a buffer to pass to other clients
ion_import: given an buffer in another client, import it
ion_import_fd: given an fd obtained via ION_IOC_SHARE ioctl, import it
Heap 接口定義 [drivers/gpu/ion/ion_priv.h]
這些接口不是暴露給驅動或者用戶應用程序的。
/** * struct ion_heap_ops - ops to operate on a given heap * @allocate: allocate memory * @free: free memory * @phys get physical address of a buffer (only define on physically contiguous heaps) * @map_dma map the memory for dma to a scatterlist * @unmap_dma unmap the memory for dma * @map_kernel map memory to the kernel * @unmap_kernel unmap memory to the kernel * @map_user map memory to userspace */ struct ion_heap_ops { int (*allocate) (struct ion_heap *heap, struct ion_buffer *buffer, unsigned long len,unsigned long align, unsigned long flags); void (*free) (struct ion_buffer *buffer); int (*phys) (struct ion_heap *heap, struct ion_buffer *buffer, ion_phys_addr_t *addr, size_t *len); struct scatterlist *(*map_dma) (struct ion_heap *heap, struct ion_buffer *buffer); void (*unmap_dma) (struct ion_heap *heap, struct ion_buffer *buffer); void * (*map_kernel) (struct ion_heap *heap, struct ion_buffer *buffer); void (*unmap_kernel) (struct ion_heap *heap, struct ion_buffer *buffer); int (*map_user) (struct ion_heap *mapper, struct ion_buffer *buffer, struct vm_area_struct *vma); };
ION 在/sys/kernel/debug/ion/ 提供一個debugfs 接口。
每一個heap都有本身的debugfs目錄,client內存使用情況顯示在/sys/kernel/debug/ion/<<heap name>>
$cat /sys/kernel/debug/ion/ion-heap-1 client pid size test_ion 2890 16384
每一個由pid標識的client也有一個debugfs目錄/sys/kernel/debug/ion/<<pid>>
$cat /sys/kernel/debug/ion/2890 heap_name: size_in_bytes ion-heap-1: 40960 11
參考文獻
1. https://wiki.linaro.org/BenjaminGaignard/ion
2. http://lwn.net/Articles/480055/
3. http://lwn.net/Articles/472984/