ARTS-25(, ION memory, python __init__.py,看房的感想)

Algorithm

代办

Review

ION 是当前 Android 流行的内存分配管理机制,在多媒体部分中使用的最多,例如从 Camera 到 Display,从 Mediaserver 到 Surfaceflinger,都会利用 ION 进行内存分配管理。 ION 的前任是 PMEM,后来由于 PMEM 的一些局限性,Google 推出了 ION 来取代 PMEM,当前 ION 已经融合到 Linux 主线,被广泛使用。

ION 基本概念
ION,最显著的特点是它可以被用户空间的进程之间或者内核空间的模块之间进行内存共享,而且这种共享可以是零拷贝的。在实际使用中,ION 和 VIDEOBUF2、DMA-BUF、V4L2 等结合的很紧密。本文主要介绍 ION,其它子系统感兴趣的话后续会陆续进行介绍。

ION 是在各种 heaps 上分配内存,通过 ion_buffer 来描述所分配的内存。

下图展示了 ION 的基本框架。图中 PID1、PID2、PID3 表示用户空间进程。ION core 表示 ION 核心层,它提供设备创建、注册等服务,同时提供统一的接口给用户使用。ION Driver 利用 ION core 对相应功能进行实现,可以说它是具体平台相关的,例如 SAMSUNG 平台、QUALCOMM 平台和 MTK 平台都会依据自己的特性开发相应的 ION Driver。
在这里插入图片描述
上图虽然描述的是用户空间进程使用 ION 的情形,但实际上,在内核空间同样可以直接使用 ION 来分配、管理内存。例如 M76、M86 平台的相机驱动,都有直接使用 ION 分配和管理内存。

主要数据结构
数据结构是程序设计的基础,代码看的多了,其实可以从数据结构看出其能提供的基本功能和大致用法。 为了抓住纲领,将抓住 ION 的主要数据结构进行介绍。

ion_device
ion_device 是 ION 很重要很基础的数据结构,用 struct ion_device 结构体描述,一般在一个系统中只有一个本实例。例如在 M86 中,就是在 exynos_ion_v2.c 的 exynos_ion_probe() 函数中创建了系统唯一的本实例。

struct ion_device {
	struct miscdevice dev;
	struct rb_root buffers;
	struct mutex buffer_lock;
	struct rw_semaphore lock;
	struct plist_head heaps;
	long (*custom_ioctl)(struct ion_client *client, unsigned int cmd,
			     unsigned long arg);
	struct rb_root clients;
	struct dentry *debug_root;
	struct dentry *heaps_debug_root;
	struct dentry *clients_debug_root;
	struct semaphore vm_sem;
	atomic_t page_idx;
	struct vm_struct *reserved_vm_area;
	pte_t **pte;
	...
};

struct ion_device 其实是 ION 的核心结构,不过由于对于使用 ION 的用户而言是屏蔽的,即如果是单纯使用 ION,不需要直接和本结构打交道。但是想完全的理解 ION,需要对其有所了解。 struct ion_device 是由 ion_device_create() [ion.c] 分配、初始化。

dev 成员,是 struct miscdevice 类型,所以可想而知 ION 是作为 MISC 设备注册进系统的。从这点还可以看出来,用户空间使用 ION 时必定需要使用 open ,ioctl 系统调用。事实也正是如此。
heaps 成员,在 M86 使用过的 KERNEL LINUX 3.10 中是 struct plist_head 类型,但是在此之前并不是此类型,例如在 M65 使用过的 KERNEL LINUX 3.4 中是 struct rb_root 类型。可见随着 KERNEL 和 ION 的演进,struct ion_device 的实现会有所改变。本字段管理的是属于本 struct ion_device 的所有 struct ion_heap 实例。
clients 成员,是 struct rb_root 类型,struct rb_root 是红黑树,属于二叉树的一种。本字段管理的是 struct ion_client 实例。

ion_heap
struct ion_heap 表示 ION 中的重要概念 heap。系统会通过链表或者红黑树,这取决与你所使用的 KERNEL 版本,来管理所有的 heap,这些 heap 可用 struct ion_device::heaps 字段来寻找。

struct ion_heap {
	struct plist_node node;
	struct ion_device *dev;
	enum ion_heap_type type;
	struct ion_heap_ops *ops;
	unsigned long flags;
	unsigned int id;
	const char *name;
	struct shrinker shrinker;
	struct list_head free_list;
	size_t free_list_size;
	spinlock_t free_lock;
	wait_queue_head_t waitqueue;
	struct task_struct *task;

	int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *);
};c

node 成员,是 struct plist_node 结构,用于将本 heap 实例加入到 struct ion_device 所管理的链表中,详情可以参见 ion_device_add_heap() [ion.c] 函数。
dev 成员,是 struct ion_device 结构体指针类型,用于指示本 heap 挂在哪一个 struct ion_device 实例下了。
type 成员,是 enum ion_heap_type 类型,用于表示本 heap 属于哪种类型。用户在使用 ION 分配内存时需要指定 heap 的种类。关于本字段,后续会结合使用方法进行更详细的介绍。
ops 成员,是 struct ion_heap_ops 类型,它很重要!本字段提供的回调函数是用于从本 heap 中分配内存时所时用的。请参见 ion_buffer_create() [ion.c],它会调用 struct ion_heap_ops::allocate() 等回调函数。

ion_handle
struct ion_handle 其实就是表示 buffer,用户空间常用它来表示 buffer。本结构通过 ion_handle_create() [ion.c] 分配、初始化。

struct ion_handle {
	struct kref ref;
	struct ion_client *client;
	struct ion_buffer *buffer;
	struct rb_node node;
	unsigned int kmap_cnt;
	int id;
};

ref 成员,是 struct kref 结构类型,它在内核中被广泛的用来表示引用计数。ion_handle 的创建和销毁都与其有关,下文会有介绍。
client 成员,是 struct ion_client 指针类型,指向其所述的 ion_client 实例。
buffer 成员,是 struct ion_buffer 指针类型,指向真正的 buffer 所在,它可以说是 stuct ion_handle 的核心成员了。

ion_buffer
struct ion_buffer 很重要,通过 ION 分配的内存就是通过它表示的。它和上面提到的 ion_handle 的区别主要在于一个是用户空间使用的,一个是内核空间使用的。即虽然常用的接口函数中使用的是 struct ion_handle,但实际上真正表示内存的其实是 struct ion_buffer。

struct ion_buffer {
	struct kref ref;
	...
	struct ion_device *dev;
	struct ion_heap *heap;
	unsigned long flags;
	unsigned long private_flags;
	size_t size;
	union {
		void *priv_virt;
		ion_phys_addr_t priv_phys;
	};
	struct mutex lock;
	int kmap_cnt;
	void *vaddr;
	int dmap_cnt;
	struct sg_table *sg_table;
	struct page **pages;
	struct list_head vmas;
	struct list_head iovas;
	...
};

ref 成员,是 struct kref 结构实例,维护了本 ion_buffer 的引用计数。当引用计数为 0 时会释放该 buffer,即 struct ion_heap_ops::free 会被调用。分配用 ION_IOC_ALLOC 型 ioctl 系统调用,相应的释放用 ION_IOC_FREE 型 ioctl 系统调用。
size 成员,当然是本 buffer 所表示的空间的大小,用字节表示。
priv_virt 成员,是所分配内存的虚拟地址啦,它常与 struct sg_table,或者封装它的结构,有关。它不是我们在内核中读写时所需的内核虚拟地址啦,内核虚拟地址使用 vaddr 成员来表示的。一般而言,物理内存不连续的,使用本字段;否则使用下面的 priv_phys 字段,如 struct ion_heap_ops contig_heap_ops。
priv_phys 成员,表示所分配的内存的物理地址。它适用于分配的物理内存是连续的 ion heap。这种连续的物理内存:在将其映射到用户空间时,即获取用户空间虚拟地址,可以使用 remap_pfn_range() [memory.c] 这个方便的接口;在将其映射到内核空间时,即获取内核虚拟地址,可以使用 vmap() [vmalloc.c] 这个方便的接口。例子详见 struct ion_heap_ops contig_heap_ops [exynos_ion.c]。priv_virt 成员和 priv_phys 成员组成了一个联合体,其实都表示地址,只不过不同的场景下具体用的不一样而已。
kmap_cnt 成员,记录本 buffer 被映射到内核空间的次数。
vaddr 成员,是本 buffer 对应的内核虚拟地址。当 kmap_cnt 不为 0 时有效。可以通过 ion_map_kernel() [ion.c] 来获取本 buffer 对应的内核虚拟地址。ion_map_kernel() [ion.c] 实际上调用的是相应 struct ion_heap_ops::map_kernel 回调函数获取相应的虚拟地址的。
dmap_cnt 成员,记录本 buffer 被 mapped for DMA 的次数。
sg_table 成员,是 struct sg_table 结构体类型的指针。本字段与 DMA 操作有关,而且仅仅在 dmap_cnt 成员变量不为 0 时是有效的。可以通过 ion_buffer_create() [ion.c] 来初始化本成员变量,该函数实际上是调用相应 ion_heap 所属的 struct ion_heap_ops::map_dma 回调函数获取本字段的值的。
dirty 成员,表示 bitmask。即以位图表示本 buffer 的哪一个 page 是 dirty 的,即不能直接用于 DMA。dirty 表示 DMA 的不一致性,即 CPU 缓存中的内容与内存中的实际内容不一样。

在这里插入图片描述

ION可以释放内存嘛?

答案是否定的。它主要的是提供给applications间共享内存。

ION和PMem可以共存嘛?

可以,但是不能共享buffers.

userspace是如何使用ION?

1:open ION device-------open("/dev/ion", O_RDONLY),返回一个FD(相当于ION client)

2: 客户端要填充如下数据结构,除了handle,也就是你要申请的data:

struct ion_allocation_data {

        size_t len;

        size_t align;

        unsigned int flags;

        struct ion_handle *handle;

   }

3: user space clients 用ioctl跟ION通信

int ioctl(int client_fd, ION_IOC_ALLOC, struct ion_allocation_data *allocation_data)

返回的FD的buffer。

4:FD可以通过Binder机制进行进程间的share

如何查看ION的使用量

for example:


>adb shell

 #mount -t debugfs NONE /d

 #cd /d/ion/

 #ls

 922

 vmalloc

 ...

 # cat vmalloc

 cat vmalloc

 client pid size

 total bytes currently allocated: 0

 # cat 922

 cat 922

 heap_name: size_in_bytes : handle refcount : buffer

 client refcount: 1

参考:http://kernel.meizu.com/memory%20management%20-%20ion.html

https://www.jianshu.com/p/9e19b475771a

https://time.geekbang.org/column/article/107422

Tips

Python init.py 作用详解

init.py该文件的作用就是相当于把自身整个文件夹当作一个包来管理,每当有外部import的时候,就会自动执行里面的函数。

封装成包是很简单的。在文件系统上组织你的代码,并确保每个目录都定义了一个__init__.py文件。 例如:

graphics/
    __init__.py
    primitive/
        __init__.py
        line.py
        fill.py
        text.py
    formats/
        __init__.py
        png.py
        jpg.py

一旦你做到了这一点,你应该能够执行各种import语句,如下:

import graphics.primitive.line
from graphics.primitive import line
import graphics.formats.jpg as jpg

讨论

定义模块的层次结构就像在文件系统上建立目录结构一样容易。 文件__init__.py的目的是要包含不同运行级别的包的可选的初始化代码。 举个例子,如果你执行了语句import graphics, 文件graphics/init.py将被导入,建立graphics命名空间的内容。像import graphics.format.jpg这样导入,文件graphics/init.py和文件graphics/formats/init.py将在文件graphics/formats/jpg.py导入之前导入。

绝大部分时候让__init__.py空着就好。但是有些情况下可能包含代码。 举个例子,init.py能够用来自动加载子模块:

graphics/formats/__init__.py
from . import jpg
from . import png

像这样一个文件,用户可以仅仅通过import grahpics.formats来代替import graphics.formats.jpg以及import graphics.formats.png。

https://www.jianshu.com/p/73f7fbf75183
https://python3-cookbook.readthedocs.io/zh_CN/latest/c10/p01_make_hierarchical_package_of_modules.html
https://stackoverflow.com/questions/448271/what-is-init-py-for
https://www.cnblogs.com/Lands-ljk/p/5880483.html

Share

这周是人生中第一次看房,感受颇多,事先需要从众多的信息中找到你需要的,比如你想要的是学区房,其实需要先查一查上海学区的定义,其实7.8年之后学区的概念就不那么确定了,有可能会发生变化。这个在小城市中思维确实是不一样的,是买中环内的老破小,还是外环范围甚至之外的新房,这个都是需要考虑的问题,精装修的房子确实比较漂亮。而且政府也会限价,对于刚需的人群来说,还是会一扫而空。

最关键的其实还是:需要举一家之力来买房,甚至两家之力。之后的事情,只有自己好好努力了,房贷压力不小,要有心理准备。加油!
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值