针对低端机KSM的优化

article/2025/9/17 4:18:32

简介: 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;
}







http://chatgpt.dhexx.cn/article/BCwYTUgG.shtml

相关文章

Linux KSM共享内存

简介&#xff1a;作为一个系统管理程序&#xff08;hypervisor&#xff09;&#xff0c;Linux 有几个创新&#xff0c;2.6.32 内核中一个有趣的变化是 KSM(Kernel Samepage Merging) 允许这个系统管理程序通过合并内存页面来增加并发虚拟机的数量。本文探索 KSM 背后的理念&am…

Linux KSM

转载&#xff1a;http://www.cnblogs.com/zhangzhang/archive/2012/05/23/2514336.html 简介&#xff1a;作为一个系统管理程序&#xff08;hypervisor&#xff09;&#xff0c;Linux 有几个创新&#xff0c;2.6.32 内核中一个有趣的变化是 KSM(Kernel Samepage Merging) 允许…

KSM应用实践

KSM应用实践 原创 lyonger 网易游戏运维平台 2019-08-17 lyonger 18年加入网易&#xff0c;先后负责过多个游戏产品的运维工作&#xff0c;多年运维生涯。负责小游戏CI/CD、事件处理平台开发、游戏Nomad运维模式探索、gitlab平台维护等工作。主要关注Linux性能优化、DevOps、云…

linux ksm,内存页面共享-KSM

导读 本文适合有基本Linux内存管理概念的新手阅读&#xff0c;且本文旨在从工作流程和设计思想上介绍KSM&#xff0c;在涉及到源代码的地方&#xff0c;进行了部分删减&#xff0c;如果想详细了解KSM&#xff0c;推荐阅读源代码及源代码中的注释。 作者也是初次接触Linux内核源…

Linux内存管理 之 KSM功能介绍

目录 前言1. 概述1.1 使用 madvise 控制 KSM1.1 KSM 守护进程 sysfs 接口 2.KSM技术应用场景3. KSM技术实践3.1 查看KSM运行情况3.2 KSM设置3.3 对vm的设置 前言 KSM(Kernel Samepage Merging) 共享内存的概念在现代操作系统中很常用了&#xff0c;比如&#xff0c;一个程序启…

HTTP 401 错误 - 未授权: (Unauthorized)

http://blog.csdn.net/patronsaint/article/details/5639962 介绍 您的Web服务器认为&#xff0c;客户端&#xff08;例如您的浏览器或我们的 CheckUpDown 机器人&#xff09;发送的 HTTP 数据流是正确的&#xff0c;但进入网址 (URL) 资源 &#xff0c; 需要用户身份验证 &a…

403错误(已解决)

问题描述&#xff1a; 取得到图片的地址&#xff0c;但是显示图片无法加载 浏览器开发者模式报错403 问题解决&#xff1a; 图片的url部署在阿里云的oss存储仓库上&#xff0c;登陆阿里云发现是欠费导致的oss文件存储功能失效 补充&#xff1a; 403 Forbidden错误的原因和解…

Error:Request failed with status code 401

Error:Request failed with status code 401 错误示例&#xff1a; // 获取个人信息 export const getUserInfoAPI () > {return request({url: /v1_0/user/profile,method: GET,Headers: {Authorization: Bearer ${getToken()}}}) }正确做法 // 获取个人信息 export co…

服务器发送了 HTTP 状态代码 401: Unauthorized

根据wsdl连接生成客户端代码&#xff0c;调用接口报错&#xff1a;服务器发送了 HTTP 状态代码 401: Unauthorized。查询此错误的原因是没有访问权限&#xff0c;想到客户再提供接口wsdl访问连接的时候提供了用户名和密码。 解决办法&#xff1a; 增加此类 在接口运行前增加此…

前端401错误 解决方法:响应拦截器

目录 1.该问题出现的原因 2.处理401问题的解决方案原理 3.使用响应拦截器解决问题 1.该问题出现的原因 在前后端分离项目中&#xff0c;最常见的是前端点击登录后&#xff0c;后端返回token字符串&#xff0c;这个token可以看作是一个“令牌”&#xff0c;就比如你去酒店办理…

解密网站401错误:了解发生原因和修复方法

​  每个网站都会有不同的错误码&#xff0c;其中&#xff0c;401错误被认为是相对常见的错误码。那么&#xff0c;什么是网站401错误呢?在摸清了这一点之后&#xff0c;我们也需要学习一下如何解决它。 什么是 401 状态码? 401 状态代码是 Web 服务器发送给浏览器的 HTTP …

401 错误原因和解决方案

401.1 您未被授权查看该页 HTTP 错误 401.1 - 未经授权&#xff1a;访问由于 凭据无效被拒绝。 出现问题的原因&#xff1a; 计算机用户名ftpname帐号的密码和IIS中记录的不一致。 出现这个问题的原因就是手工到IIS中修改了用户的登录密码&#xff0c;从而导致计算机用户名…

401错误 解决方法:响应拦截器

关于401错误 401错误场景 1. 用户未登录,代码报401,应该回到登录页 2. 登录用户的token过期 : 怎样理解token过期? . 就是登录成功了以后,后端会返回一个token值,这个值在后续请求时带上&#xff08;就像是开门钥匙), 但是&#xff0c;这个值一般会有有效期&#xff08;具…

点到超平面的距离公式

超平面&#xff1a; 第一步&#xff1a;求出超平面的法向量 超平面上任意两点, 则向量一定垂直于该超平面的法向量。这两点满足&#xff1a; 两式相减&#xff1a; 就是向量&#xff0c;由此可以看出超平面的法向量就是向量 第二步&#xff1a;求出点到超平面的距离r 假设…

模式识别中的最优分类超平面与线性支持向量机

模式识别中的最优分类超平面与线性支持向量机 本章的内容需要你理解一下的基础知识。 模式识别部分&#xff1a;线性分类器基本概念、感知器 数学基础部分&#xff1a;拉格朗日乘子法、拉格朗日对偶问题 当然&#xff0c;以上的基础知识不需要你现在就看&#xff0c;可以在阅…

平面、超平面的法线,平行超平面的距离

1. 法线 一个平面或超平面由一个方程&#xff08;不是一组方程&#xff09;定义&#xff1a; { x ∣ a T x b } \{x\mid a^Txb\} {x∣aTxb} 其中 a a a 是一个非零的列向量&#xff0c;而 b b b 是一个实数。那么它的法线&#xff08;垂线&#xff09;向量是 a a a。 例如…

如何理解超平面?

超平面的公式 首先明确几个定义&#xff1a;(1) 超平面是指n维线性空间中维度为n-1的子空间。它可以把线性空间分割成不相交的两部分。比如二维空间中&#xff0c;一条直线是一维的&#xff0c;它把平面分成了两块&#xff1b;三维空间中&#xff0c;一个平面是二维的&#xf…

支持向量所在超平面方程_如何用python绘制超平面支持向量机?

一个完整的例子 import numpy as np import matplotlib.pyplot as plt def __intersect(rect, line): l = [] xmin,xmax,ymin,ymax = rect a,b,c = line assert a!=0 or b!=0 if a == 0: y = -c/b if y<=ymax and y>=ymin: l.append((xmin, y)) l.append((xmax, y)) retu…

SVM(四):超平面详细解释

目录 背景定义超平面方程推导平面直线方程空间平面方程超平面 点到超平面的距离推导点到平面直线的距离点到空间平面的距离超平面 判断超平面的正反 背景 关于超平面的介绍&#xff0c;网上的博客资料太多了&#xff0c;然而真正简洁易懂、切中要害的实在是太少了&#xff0c;…

【支持向量机】最大间隔超平面及Matlab代码

线性可分 在特征空间中&#xff0c;有两个训练样本可以通过一条直线区分开&#xff0c;则称为线性可分。而在特征空间大于等于四维时&#xff0c;分开训练样本的平面&#xff0c;称为超平面。 我们定义一条直线方程&#xff1a; ω 1 x 1 ω 2 x 2 b 0 ω_1x_1ω_2x_2b0 …