SPRD ION 代码阅读理解---笔记

本文介绍了ION,Google Android 4.0后引入的内存管理技术,主要涉及ION的概念、应用场景、使用方式及相关概念。文章通过分析SPRD ION驱动的代码,详细讲解了ION内存的申请和释放过程,包括内存对齐、伙伴系统以及scatterlist的使用,旨在帮助读者深入理解ION的工作原理。
摘要由CSDN通过智能技术生成

缘由:
在应用层两次调用 open_adf 接口后,整个系统就 crash了,经过log分析发现,在 kernel 第二次ION申请内存的时候,出了问题。那什么是ION?怎么玩的?于是准备一探究竟。

什么是 ION?
ION 是google android系统在4.0后引入的一种内存管理技术。详细链接如下:
The Android ION memory allocator

用在哪些地方?
应用层和kernel层都可以使用。应用层比如 camera、display、audio等系统。同时,ION 可以在两个进程间进行内存共享。

如何用?
对于kernel层,直接调用 ION 框架中相关的函数接口就可以;对于应用层,通过访问平台提供的 ION 驱动设备节点 “/dev/ion” 来进行操作。

相关概念
ion_client:申请内存的对象,一般一个进程代表一个 client。以应用层为例,打开一次 “/dev/ion” 节点,就产生一个 client。
ion_heap:内存缓冲池,存放通过伙伴系统申请的各种页面。heap 在系统开机阶段由平台ION驱动调用ION框架中相关接口函数创建。为了分类管理申请的页面,heap 也是多个种类。
ion_buffer:申请的内存页面,存放在 heap 的 pool 中。
ion_handle:存放申请到的 buffer 的句柄

简要理解

首先,在设备树中,SPRD 的 ION 配置部分,先指定了平台上的 heap相关信息,包括 type、id、name;如下:

ion {
   
	compatible = "sprd,ion";
	#address-cells = <1>;
	#size-cells = <0>;

	heap@0 {
   
		reg = <0>;
		label = "system";
		type = <0>;
	};

	heap@3 {
   
		reg = <3>;
		label = "carveout_fb";
		type = <2>;
		memory-region = <&fb_reserved>;
	};
};

其次,在代码中,SPRD ION 驱动,一是调用ION的 ion_device_create 接口函数,创建设备驱动节点“/dev/ion”,并注册相关的 ion 操作 ioctl 文件接口:

idev = ion_device_create(&sprd_ion_ioctl);

接着,调用 ION 的 ion_heap_create 接口函数,按照 ION 设备树里面的配置,创建各种 heap。注意,此时的 heap 中是空的,并没有内存页面存在。heap 中页面,是后续慢慢的存放进去的。(根据heap的type不同,这里的过程稍微不一致,以下以 ION_HEAP_TYPE_SYSTEM 为例)。

通过 ION 申请内存的接口是 ion_alloc 。该函数会去指定的 ion_heap中查,如果 ion_heap的 pool 中有空闲且符合要求的页面,则直接取用该页面;如果没有,则需要通过伙伴(buddy)系统的alloc_pages 去获取新的页面,至于如何通过伙伴系统去获取内存,此处略过不表。ion_alloc 申请的内存空间,最后会将句柄放置到 ion_handle 中,返回给 ion_client

而在 client 不再使用当前页面时,就需要释放。释放分两种情况,一是需要立即归还给系统的页面,二是可以暂时不归还给系统的页面。如果是需要立即规划给系统的页面,则需要调用 ion_page_pool_free_immediate 函数,最后走到 __free_pages 流程上;如果是可以暂时不归还给系统的页面,则调用了 ion_page_pool_free 函数,最后将这些页面存入指定的 heap 中,并对存入的页面进行统计、归纳整理,如果下一次再有 ion alloc 的需求发出,则alloc会先查询 heap 中的页面是否符合要求,如果有符合要求的页面,就直接使用了,不再通过伙伴系统去申请新的页面。

这里需要做一个对比,就是从伙伴系统申请页面,以及站在伙伴系统的基础上,直接从 ion heap 中获取页面,它们的速度肯定是不一样的,则效率也是不一样的。毕竟,产生一次缺页中断或者重新做一次物理内存块到虚拟页面的映射,这都是需要时间的。而 ion heap 中的页面,就像一个数组一样,申请一次,每次用的时候,最多采用 memset 清零就好。

代码考察

以下考察下 ION_HEAP_TYPE_SYSTEM 类型的 alloc 和 free 的过程。
针对 ION_HEAP_TYPE_SYSTEM 类型的 type, ion_alloc 最终会调用 ion_system_heap_allocate 接口。

struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
			     size_t align, unsigned int heap_id_mask,
			     unsigned int flags)
{
   
    buffer = ion_buffer_create(heap, dev, len, align, flags);
}
static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
				     struct ion_device *dev,
				     unsigned long len,
				     unsigned long align,
				     unsigned long flags)
{
   
	ret = heap->ops->allocate(heap, buffer, len, align, flags);
}

上面的 allocate 注册地方如下:

static struct ion_heap_ops system_heap_ops = {
   
	.allocate = ion_system_heap_allocate,
};

则可以继续考察 ion_system_heap_allocate 的实现(代码片段):

static int ion_system_heap_allocate(struct ion_heap *heap,
				     struct ion_buffer *buffer,
				     unsigned long size, unsigned long align,
				     unsigned long flags)
{
   
//....
	unsigned long size_remaining = PAGE_ALIGN(size);
//.....
	INIT_LIST_HEAD(&pages);
	INIT_LIST_HEAD(&pages_from_pool);
	while (size_remaining > 0) {
   
		info = alloc_largest_available(sys_heap, buffer, size_remaining,
					       max_order);
		if (!info)
			goto free_pages;

		sz = (1 << info->order) * PAGE_SIZE;
		if (info->from_pool) {
   
			pool_sz += sz;
			list_add_tail(&info->list, &pages_from_pool);
		} else {
   
			int index;
			for (index = 0; index < num_orders; index++) {
   
				if (info->order == orders[index]) {
   
					buddy_orders[index]++;
					break;
				}
			}
			buddy_sz += sz;
			list_add_tail(&info->list, &pages);
		}
		size_remaining -= sz;
		max_order = info->order;
		i++;
	}
//....
	table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
	if (!table)
		goto free_pages;

	if (sg_alloc_table(table, i, GFP_KERNEL
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值