内存管理五
此部分内容多且杂,其实完全可以合并到前四篇文章中。但考虑前四篇总结已经完成,章节插入不方便,所以还是多写一篇。
本文分成两部分来论述
1、 DMA与Cache一致性问题。
2、 常用的命令接口和文件接口简要说明。
DMA与Cache一致性问题
关于这一部分,宋老师的文章已经讲解的非常细致,我在写也无非是画蛇添足,所以此处只做简单总结。附上文章连接,http://mp.weixin.qq.com/s/5K7rlPXo2yIcoIXXgqqLfQ
而实际上,如果你不是在IC公司,大部分时候你只需要在驱动程序中轻松敲下dma_alloc_coherent来获取一片能确保DMA和cache一致性的内存就可以了,具体实现细节对你来说可能并不重要。请看下图:
A.DMA的内存分配区域
不论是应用程序还是驱动程序,在获取内存时都需要获得一片连续地址的内存,但是由
于DMA设备访问内存不经过MMU,所以也无法把不连续的物理地址映射为连续的虚拟地址,解决这个问题有两种方式:
a. 在CMA区域申请DMA内存,因为CMA本身是一片连续的物理内存,CMA通常被分配在高端内存,这个时候这片内存会被映射到vmalloc映射区,如果CMA在低端内存,则不需要重新映射,因为低端内存在开机时已经与low Memory映射区建立了一一映射关系。
b. 如果设备存在IOMMU,那么做DMA内存分配时则不需要关心具体的内存分配区域,IOMMU会让设备看到一片连续的地址范围,它的功能类似MMU,只不过MMU是把物理地址转换为连续的虚拟地址供CPU使用,而IOMMU是把物理地址转换为连续的总线地址供设备使用。
B. 确保DMA和cache一致性的手段
确保DMA和cache一致性的手段有以下三种:
a. 页表设置uncache
要保证DMA和cache一致性最简单办法,在申请到内存后,修改对应的页表,将页表的cache属性改为uncache,这样,当CPU在访问该片内存时就不会从cache取数据。
b. 硬件确保一致性
有的设备提供了确保一致性的硬件机制,这时我们申请内存后则不需要修改页表的cache属性,一致性由硬件来保证。
c. 代码手动同步
如果对应的内存区域已经申请好了,设备直接使用,那么驱动就无法更改对应页表的cache属性,这时解决一致性的手段时在每次访问这篇内存前手动同步cache内容到内存,同时禁止CPU对这片内存的访问,直到设备访问完成。实际上下面提到的DMA streaming mapping就是通过这种方式实现的。
C. API接口
当我们的驱动自己获取内存,可以使用一致性DMA缓冲区API接口,就是
dam_alloc_coherent();如果对应的内存已经被成功分配,我们在使用前需要调用DMA流映射API接口,确保cache的内容被成功flush到内存,对应的函数有dma_map_sg()和dma_map_single(),他们两个的区别是,sg映射的内存是分散/聚集的,分散在不同的位置,single映射的内存是连续的一片内存,通常是CMA。
常用的命令接口和文件接口简要说明
A. 文件Dirty数据写回配置接口
/proc/sys/vm/dirty_expire_centisecs:设置Dirty数据的写回时间期限,超过这个时间,在flusher线程下次唤醒后,写回这部分数据,单位是百分之一秒,厘秒。
/proc/sys/vm/dirty_writeback_centisecs:flusher线程周期性唤醒的时间,单位是厘秒,设置为0,表示禁止定期写回。Flusher线程唤醒后会把超过期限的脏页和进程超过dirty_background_ratio值的脏页写回。
/proc/sys/vm/dirty_background_ratio:进程持有的脏页的个数阀值,单位是页,超过这个值,flusher线程在下次唤醒后会对脏页进行写回。
/proc/sys/vm/dirty_ ratio:进程持有的脏页的个数阀值,单位是页,超过这个值,进程delay,无法在进行任何的写操作,并且进程自行完成脏页的回写。
B. Memory Cgroup的使用
控制group的最大使用内存示例如下:
$:cd /sys/fs/cgroup/memory
$:mkdir A //创建一个分组
$:cd A/
$echo $((200*1024*1024)) >memory.limit_in_bytes //设置该组最大可使用内存200M
$:cgexec –g memory:A ./a.out //将a.out添加到组A并执行
C. 内存回收接口说明
在内存管理四章节中提到内存回收有三个水位,min,low和hight,当内存的水位达到low,说明内存紧张,这时kswapd开始工作,在后台慢慢回收内存,直到水位达到high,当系统内存异常紧张时,达到min水位,程序被堵住,Direct reclaim被触发。具体相关接口如下:
/proc/zoneinfo //该文件可以查看到各个zone的情况,包括各个zone的三个水位设置
/proc/sys/vm/min_free_kbytes //可用于查看和设置min水位的值
其中low水位和high水位没有对应的设置接口,是通过计算得来的。
Low = min*5/4
High = min*6/4
各个zone的水位标准是按总的水位标准等比例划分的,比如normal zone是800M,内存一共1G,min_free_kbytes被设置为30720,即30M,那么,normal zone的min水位就等于,800/1024 * 30720,就是24000
D. Swappiness接口
Swappiness越大,越倾向于回收匿名页;swappiness越小,越倾向于回收file-backed的页面。当然,它们的回收方法都是一样的LRU算法。Swappiness的接口有两个,一个是cgroup里的swappiness,一个是/proc/sys/vm下的swappiness,他们的区别是作用域不同,cgroup里的swappiness只控制组内程序的回收倾向,而/proc/sys/vm/swappiness控制当前整个系统,除了在cgroup被重新定义的程序。
E. Getdelays工具
要使用该工具需要打开内核选项CONFIG_TASK_DELAY_ACCT和CONFIG_TASKSTATS。该工具的源文件在LinuxKernelSource/Documentation/accounting下。使用getdelays可以查看当前系统或者某个进程调度的延时,IO的delay情况,swap和内存回收的delay情况,帮助用户查看程序的耗时情况。
F. Vmstat命令
该命令可周期性的查看swap in/out和block in/out的情况。
更多系统参数接口请查看我另一篇博客:linux系统为用户提供的文件接口