简介: KSM的基本概念和思想可参考如下的分析
http://blog.csdn.net/summer_liuwei/article/details/6013255
http://blog.csdn.net/haitaoliang/article/details/25003395 代码分析
一, 编译设置,初始化
1. @kernel-3.18/arch/arm/configs/FRT_debug_defconfig & FRT_defconfig
CONFIG_KSM=y
write /sys/kernel/mm/ ksm /pages_to_scan 100
write /sys/kernel/mm/ ksm /sleep_millisecs 20
write /sys/kernel/mm/ ksm /run 1  <0,1,2>
循环kernel thread: ksmd
二,代码分析
1. @Ksm.c (mm)
static int __init ksm_init(void)
{
struct task_struct *ksm_thread;
int err;
err = ksm_slab_init();
if (err)
goto out;
ksm_thread = kthread_run( ksm_scan_thread, NULL, " ksmd");
if (IS_ERR(ksm_thread)) {
pr_err("ksm: creating kthread failed\n");
err = PTR_ERR(ksm_thread);
goto out_free;
}
static int ksm_scan_thread(void *nothing)
{
set_freezable();
/* M: set KSMD's priority to the lowest value */
set_user_nice(current, 19);
/* set_user_nice(current, 5); */
while (! kthread_should_stop()) {
mutex_lock(&ksm_thread_mutex);
wait_while_offlining();
if ( ksmd_should_run()) {
#ifdef KSM_KCTL_INTERFACE
ksm_tuning_pressure();
#endif
ksm_do_scan(ksm_thread_pages_to_scan);
}
mutex_unlock(&ksm_thread_mutex);
try_to_freeze(); //是否当前进程可以被frezze
if ( ksmd_should_run()) {
schedule_timeout_interruptible(
msecs_to_jiffies(ksm_thread_sleep_millisecs));
} else {
wait_event_freezable( ksm_thread_wait,
ksmd_should_run() || kthread_should_stop());
}
}
return 0;
}
/**
* kthread_should_stop - should this kthread return now?
*
* When someone calls kthread_stop() on your kthread, it will be woken
* and this will return true.  You should then return, and your return
* value will be passed through to kthread_stop().
*/
bool kthread_should_stop(void)
{
return test_bit( KTHREAD_SHOULD_STOP, &to_kthread(current)->flags);
}
static int ksmd_should_run(void)
{
return (ksm_run & KSM_RUN_MERGE) && !list_empty(&ksm_mm_head.mm_list); //KSM_RUN_MERGE 1
}
static void ksm_tuning_pressure(void)
{
#if NR_CPUS > 1
if (bat_is_charger_exist() == KAL_TRUE) {
if (ksm_thread_sleep_millisecs == 20 &&
ksm_thread_pages_to_scan == 100)
return;
/*set to default value */
ksm_thread_sleep_millisecs = 20;
ksm_thread_pages_to_scan = 100;
} else {
int num_cpus = num_online_cpus();
int three_quater_cpus = ((3 * num_possible_cpus() * 10)/4 + 5)/10;
int one_half_cpus = num_possible_cpus() >> 1;
if (num_cpus >= three_quater_cpus) {
ksm_thread_sleep_millisecs = 20;
ksm_thread_pages_to_scan = 100;
} else if (num_cpus >= one_half_cpus) {
ksm_thread_sleep_millisecs = 3000;
ksm_thread_pages_to_scan = 200;
} else {
ksm_thread_sleep_millisecs = 10000;
ksm_thread_pages_to_scan = 200;
}
}
#endif
}
/**
* ksm_do_scan  - the ksm scanner main worker function.
* @scan_npages - number of pages we want to scan before we return.
*/
static void ksm_do_scan(unsigned int scan_npages)
{
struct rmap_item * rmap_item;
struct page *uninitialized_var(page);
while (scan_npages-- && likely(!freezing(current))) {
cond_resched();
rmap_item = scan_get_next_rmap_item(&page);
if (!rmap_item)
return;
cmp_and_merge_page(page, rmap_item);
put_page(page);
}
}
struct rmap_item { 该条目保存有物理地址到虚拟地址的反向映射,同时用来组织稳定树的红黑树结构,对于非稳定树保存有校验和
struct rmap_item *rmap_list;
union {
struct anon_vma *anon_vma; /* when stable */
};
struct mm_struct *mm;
unsigned long address; /* + low bits used for flags below */
unsigned int oldchecksum; /* when unstable */
union {
struct rb_node node; /* when node of unstable tree */
struct { /* when listed from stable tree */
struct stable_node *head;
struct hlist_node hlist;
};
};
};

三, 主要流程图
1. ksmd线程扫描
  • ksmd线程优先级设置为最低

    • F S   UID   PID  PPID C PRI  NI BIT    SZ WCHAN  TTY          TIME CMD
    • 1 R     0     26    2       0   0    19   -     0        ?        00:00:43 ksmd
  • ksmd线程可以通过ksm_run控制是否一直扫描和暂停等
  • ksmd的sleep时长和每次扫描的page页数,是通过cpu的负载来调整的,负载越高sleep越短,扫描页数越少
    • 调整规则: (xx_millisecs, xx_scan)
    • 1.如果充电则(20, 100)
    • 2. online/possible_cpu > ¾, (20,100)
    • 3. online/possible_cpu > ½, (3000, 200)
    • 4. 其他(10000, 200)
  • ksmd线程会挂住,如果设置ksm_run=0(停止)或者扫描完所有页,这时就需要唤醒该线程,比如设置ksm_run=1
#define KSM_RUN_STOP 0
#define KSM_RUN_MERGE 1
#define KSM_RUN_UNMERGE 2
#define KSM_RUN_OFFLINE 4
  • ksmd线程目前是亮屏会启动,灭屏会挂起
  • 如果ksmd没有被中止, 则它会一直扫描完每个进程MM中所有的VMA匿名页后,

           

  • 有新的用户进程被创建,则把该进程的mm添加到KSM的扫描队列中;如果有用户进程被杀,则把该进程的mm从KSM扫描队列中删除。
  • 分析KSM的scan_get_next_rmap_item()函数,可以看到KSM尽力为每一个页面分配一个rmap_item结构体,如果该页面不能合并,那么不仅没有减少内存使用,相反还增加了一个rmap_item结构体大小的内存开销。要解决这个问题,需要采样另外一种rmap_item的生成算法,对于合并不成功的rmap_item,能够回收该rmap_item
  • 每次扫描ksm_thread_pages_to_scan个页面后,下次扫描则接着上次的页面继续扫描,每次开始扫描页面的起始地址保存在全局变量ksm_scan.address中
  • KSM用struct rmap_item链表保存相同页合并的信息,比如匿名页虚拟地址和物理地址之间的映射关系。举例:进程A中mm的虚拟地址V1指向物理页地址P1,进程B中mm的虚拟地址V2指向物理页地址P2,KSM通过扫描发现物理页P1和P2完全相同,则建立一个rmap_item反映射关系(虚拟地址--物理页),然后删除其中一个物理页P2, 如果进程A只读访问P1, 进程B只读访问P2, 则KSM直接返回唯一的共同页,如果进程A需要写入P1则产生缺页中断,重新分配物理页P3,同时也给进程B分配物理页P4。KSM就释放以前的相同页
  • KSM管理合并页面,有稳定树和不稳定树两个重要数据结构。稳定树:存储那些已经发现是稳定的且通过 KSM 合并的页面;不稳定树:用于存储还不能理解为稳定的新页面
  • 当扫描完成(通过 ksm.c/ksm_do_scan() 执行)时,稳定树被保存下来,但不稳定树则被删除并在下一次扫描时重新构建。
  • 由于稳定树中的所有页面都是写保护的,因此当一个页面试图被写入时将生成一个页面故障,从而允许 CoW 进程为写入程序取消页面合并(请参见 ksm.c/break_cow())。稳定树中的孤立页面将在稍后被删除(除非该页面的两个或更多用户存在,表明该页面还在被共享)。
  • KSM扫描完,只是表示把链表ksm_scan中的每个进程mm的VMA匿名页处理完。如果新创建的进程少,则很快能处理完一次;如果进程创建和死掉反反复复,则容易造成系统负担
四,如何使用
1. @Ksm.txt (documentation\vm)
The KSM daemon is controlled by sysfs files in /sys/kernel/mm/ksm/, readable by all but writable only by root:
pages_to_scan    - how many present pages to scan before ksmd goes to sleep e.g. "echo 100 > /sys/kernel/mm/ksm/pages_to_scan"
Default: 100 (chosen for demonstration purposes)
sleep_millisecs  - how many milliseconds ksmd should sleep before next scan e.g. "echo 20 > /sys/kernel/mm/ksm/sleep_millisecs"
Default: 20 (chosen for demonstration purposes)
merge_across_nodes - specifies if pages from different numa nodes can be merged. When set to 0, ksm merges only pages which physically
reside in the memory area of same NUMA node. That brings lower latency to access of shared pages. Systems with more
nodes, at significant NUMA distances, are likely to benefit from the lower latency of setting 0. Smaller systems, which
need to minimize memory usage, are likely to benefit from the greater sharing of setting 1 (default). You may wish to
compare how your system performs under each setting, before deciding on which to use. merge_across_nodes setting can be
changed only when there are no ksm shared pages in system: set run 2 to unmerge pages first, then to 1 after changing merge_across_nodes, to remerge according to the new setting.
Default: 1 (merging across nodes as in earlier releases)
run              - set 0 to stop ksmd from running but keep merged pages, set 1 to run ksmd e.g. "echo 1 > /sys/kernel/mm/ksm/run",
set 2 to stop ksmd and unmerge all pages currently merged, but leave mergeable areas registered for next run Default: 0 (must be changed to 1 to activate KSM, except if CONFIG_SYSFS is disabled)
The effectiveness of KSM and MADV_MERGEABLE is shown in /sys/kernel/mm/ksm/:
pages_shared     - how many shared pages are being used
pages_sharing    - how many more sites are sharing them i.e. how much saved
pages_unshared   - how many pages unique but repeatedly checked for merging
pages_volatile   - how many pages changing too fast to be placed in a tree
full_scans       - how many times all mergeable areas have been scanned
A high ratio of pages_sharing to pages_shared indicates good sharing, but a high ratio of pages_unshared to pages_sharing indicates wasted effort. pages_volatile embraces several different kinds of activity, but a high proportion there would also indicate poor use of madvise MADV_MERGEABLE.
2. KSM 配置和监控
     KSM 的管理和监控通过 sysfs(位于根 /sys/kernel/mm/ksm)执行。在这个 sysfs 子目录中,您将发现一些文件,有些用于控制,其他的用于监控。
     第一个文件 run 用于启用和禁用 KSM 的页面合并。默认情况下,KSM 被禁用(0),但 可以通过将一个 1 写入这个文件来启用 KSM 守护进程 (例如,echo 1 > sys/kernel/mm/ksm/run)。 通过写入一个 0,可以从运行状态禁用这个守护进程(但是保留合并页面的当前集合) 。另外, 通过写入一个 2,可以从运行状态(1)停止 KSM 并请求取消合并所有合并页面。
     KSM 运行时,可以通过 3 个参数(sysfs 中的文件)来控制它。 sleep_millisecs 定义执行另一次页面扫描前 ksmd 休眠的毫秒数。 max_kernel_pages 文件定义 ksmd 可以使用的最大页面数(默认值是可用内存的 25%,但可以写入一个 0 来指定为无限)。最后, pages_to_scan 文件定义一次给定扫描中可以扫描的页面数。任何用户都可以查看这些文件,但是用户必须拥有根权限才能修改它们。
     还有 5 个通过 sysfs 导出的可监控文件(均为只读),它们表明 ksmd 的运行情况和效果。full_scans 文件表明已经执行的全区域扫描的次数。剩下的 4 个文件表明 KSM 的页面级统计数据:
full_scans :表明已经执行的全区域扫描的次数
pages_shared: stable稳定树的节点数(共享后的物理页面数)。
pages_sharing:表示被共享的物理页面数。(例如将3个相同的页面合并成1个页面,则pages_shared=1,pages_sharing=2,两者比例体现了页面共享效率)
pages_unshared:ksm的暂未共享页面数,即unstable不稳定树的节点数。
pages_volatile:频繁改变的页面的数量。
pages_to_scan: 每次扫描的页面数
sleep_millisecs:每次扫描需要休息的间隔时间,不能一直run,这样会消耗CPU
     KSM 作者定义: 较高的 pages_sharing/pages_shared 比率表明高效的页面共享 (反之则表明资源浪费)。
3. 关键点
1). 合并的都是VMA中的匿名页
2). 每次处理固定的 页数(pages_to_scan)
3). 根据CPU online个数调整pages_to_scan & sleep_millisecs, online cpu个数越多,sleep_millisecs越短
4). 亮屏就开始合并页的扫描和操作,灭屏就停止
五,调试测试
1. 读取 KSM信息 /sys/kernel/mm/ksm/*
full_scans
pages_shared
pages_sharing
pages_to_scan
pages_unshared
pages_volatile
run
sleep_millisecs
2. 控制CPU online/offline: sys/devices/proc/hps/system/cpu
echo 0  > /proc/hps/enabled      该命令屏蔽系统自己的调核策略
echo 0 > /sys/devices/system/cpu/cpu3/online  该命令关cpu3
固定GPU频率
echo 0 > gpufreq_state
echo 549250 > gpufreq_opp_freq
3. 控制是否充电
cat /proc/mtk_battery_cmd/current_cmd  //就可以disable 充电
echo 1500 0 > /proc/mtk_battery_cmd/current_cmd  //就可以enable充电
4. 打印输出
pr_info("peter_xu ksm:  %s enter pid = %d, uid = %d, state = %ld\n",
current->comm, current->pid, current_uid().val, current->state);
5. LINUX / android / system / core / include / cutils / android_filesystem_config.h
UID对应的名称
6. pmap pid
六,优化手段
1.  ksm_thread_sleep_millisecs 和 ksm_thread_pages_to_scan 重新合理设置;  bat_is_charger_exist
2. 只对系统常驻进程采取KSM, 容易被杀掉的用户进程则不做KSM处理
@Ksm.c (mm)
#ifdef CONFIG_KSM_GO
/* Merge page or not after once scan */
static bool ksm_find_same_page = true;
#endifstatic void stable_tree_append(struct rmap_item *rmap_item,struct stable_node *stable_node)
{rmap_item->head = stable_node;rmap_item->address |= STABLE_FLAG;hlist_add_head(&rmap_item->hlist, &stable_node->hlist);if (rmap_item->hlist.next)ksm_pages_sharing++;elseksm_pages_shared++;
#ifdef CONFIG_KSM_GOksm_find_same_page = true;
#endif
}static void ksm_tuning_pressure(void)
{
#ifdef CONFIG_KSM_GOif (ksm_find_same_page) {ksm_thread_sleep_millisecs = 20;ksm_thread_pages_to_scan = 100;} else {ksm_thread_sleep_millisecs += 50;if (ksm_thread_sleep_millisecs > 1000) {ksm_thread_sleep_millisecs = 1000;}ksm_thread_pages_to_scan += 100;if (ksm_thread_pages_to_scan > 500) {ksm_thread_pages_to_scan = 500;}}ksm_find_same_page = false;
#else
#if NR_CPUS > 1if (bat_is_charger_exist() == KAL_TRUE) {if (ksm_thread_sleep_millisecs == 20 &&ksm_thread_pages_to_scan == 100)return;/*set to default value */ksm_thread_sleep_millisecs = 20;ksm_thread_pages_to_scan = 100;} else {int num_cpus = num_online_cpus();int three_quater_cpus = ((3 * num_possible_cpus() * 10)/4 + 5)/10;int one_half_cpus = num_possible_cpus() >> 1;if (num_cpus >= three_quater_cpus) {ksm_thread_sleep_millisecs = 20;ksm_thread_pages_to_scan = 100;} else if (num_cpus >= one_half_cpus) {ksm_thread_sleep_millisecs = 3000;ksm_thread_pages_to_scan = 200;} else {ksm_thread_sleep_millisecs = 10000;ksm_thread_pages_to_scan = 200;}}
#endif
#endif
}static int ksm_fb_notifier_callback(struct notifier_block *p,unsigned long event, void *data)
{int blank;if (event != FB_EVENT_BLANK)return 0;blank = *(int *)((struct fb_event *)data)->data;if (blank == FB_BLANK_UNBLANK) { /*LCD ON*/
#ifdef CONFIG_KSM_GOksm_run_change(KSM_RUN_STOP);
#elseksm_run_change(KSM_RUN_MERGE);
#endif} else if (blank == FB_BLANK_POWERDOWN) { /*LCD OFF*/
#ifdef CONFIG_KSM_GOksm_find_same_page = true;ksm_run_change(KSM_RUN_MERGE);
#elseksm_run_change(KSM_RUN_STOP);
#endif}return 0;
}






针对低端机KSM的优化相关推荐

  1. unity3d 优化 高中低端机 机型分类

    unity 开发移动端游戏众多, 此文章为优化考虑, 对不同的手机分类为高中低端, 分类标准如下 Android 需要综合架构(这问题自己想).核心数(代码请在blog里找).主频(代码请在blog里 ...

  2. 低端机Arouter初始化耗时分析与优化

    Android 项目中用到了阿里开源路由框架   https://github.com/alibaba/ARouter 但是低端机首次安装启动发现耗时比较长,那么我们分析一下原因,read thd  ...

  3. ANR实战案例3 - 应用在部分低端机ANR优化案例

    系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用 文章目录 系列文章目录 前言 一.Blocked状态 1. ...

  4. 中移动强推五模手机 千元低端机面临成本难题

    作为TD-LTE产业链的老大哥,中国移动的一举一动都备受产业链上下游的关注,因为可能一个细微的调整就事关大家的切身利益. 近日,中移动(44.87, 0.02, 0.04%)对于4G定制终端要求的变化 ...

  5. k3note Android8,联想乐檬K3 Note官方稳定版 最新VIBE刷机包 精简优化 完美加入Root权限...

    联联想乐檬K3 Note官方稳定版 最新VIBE刷机包 精简优化 完美加入Root权限 ROM介绍: 1.基于官方最新发布的VIBEUI_V3.1_1622_5.440.1_ST_K50-T5稳定版固 ...

  6. 【大会】中低端机如何实现复杂多媒体功能?

    软/硬编码.解码,超分,各式各样的特效,如何发挥出高端机型的性能的通时,保障中低端机运行流畅,这需要研发.运营和产品团队紧密配合.本专题将讨论在客户端与web端实现高效研发与高性能多媒体能力实现的经验 ...

  7. hbase针对fullgc所做的优化(Memstore所作的优化 针对BlockCache所作优化)

    先看: 深入研究java gc https://blog.51cto.com/12445535/2372976 老年代 CMS gc回收算法 对hbase的影响 https://blog.51cto. ...

  8. linux多核cpu 优化,Ubuntu是否针对多核CPU进行了优化?

    问题描述 Ubuntu是否使用多核CPU(据说Windows 7会这样做)? 换句话说,它是否进行了多任务优化,以便用户可以从4+核心处理器中受益? 最佳解决思路 是的,Ubuntu针对多核CPU进行 ...

  9. android6.0 1g运存,全新安卓系统只要1G运存就能流畅运行!低端机 老手机有救了!...

    原标题:全新安卓系统只要1G运存就能流畅运行!低端机 老手机有救了! 安卓发展了也近十年了,最大的特点就是开放,这个毋庸置疑,还有一个特点... 那就是吃配置,在11-15年,尤为明显,大家都是在宣传 ...

最新文章

  1. 进程状态控制-进程的阻塞和唤醒
  2. 2019cvpr oral | 实时自适应立体匹配
  3. Centos更换阿里云源
  4. tableau必知必会之VMware 搭建 Tableau Server for Linux 单机环境
  5. .net core 技术栈 网站收集
  6. 执行SQL-DefaultSqlSession.selectOne()
  7. php 播放多个音乐,meting 音乐播放插件多域名跨域解决方法
  8. height百分比失效
  9. php小猫咪图床源码V1.8
  10. python 哥德巴赫猜想的验证
  11. Java线程安全队列Queue实现原理
  12. 创建docker容器的命令
  13. java实现lru缓存_Java中的LRU缓存实现
  14. Frame Stacking 框架堆叠
  15. Python 路径处理(os.path模块)
  16. UE4遇到的各种奇葩问题
  17. GPS基带P码处理总结——FPGA实现的关键点
  18. 表单中多个文本框实时计算金钱总和值
  19. MPEG PS流格式
  20. android 游戏遥感,Android2.2+游戏摇杆 MOPS魅影T800评测

热门文章

  1. HSF + EDAS 搭建微服务项目
  2. hsf端口_hsf配置
  3. java线程池多线程优先级_Java线程优先级
  4. mysql 只读视图_MySQL 视图
  5. “I am a student”反转成“student a am I”
  6. 六一快乐,教你用python画出你的童年回忆
  7. 根据城市名获取首字母
  8. scrapy.Request callback不执行
  9. 【那些年,我们一起追的女孩】第十三章
  10. MCDF实验_lab4(4)