Per-CPU pages

定义

PCPper_cpu_pagesBuddy system机制中,优先分配最近被释放的页,因为这些页位于cache中的概率比较大。

因此buddy system为每个cpu维护了一个per_cpu_pages数据结构,用于保存最近被释放的页框。

pcp只包含了order <= PAGE_ALLOC_COSTLY_ORDER的页框,在当前内核版本中该值被定义为3。

数据结构

定义在include/linux/mmzone.h

1. per_cpu_pages

  • count:当前链表里page的个数。
  • high:高水位。当pcp中page num高于high watermark时就会回收page到buddy。
  • batch:每次回收/分配buddy system页表的数量为batch* 2 ^order个page。
  • lists: pcp下包含的page的链表,和buddy一样每个migratetype有一个。
    • page链表的数量 = migratetype的数量 x pcp支持的order数量

NR_PCP_LISTS =  MIGRATE_PCPTYPES * (PAGE_ALLOC_COSTLY_ORDER + 1)

若pcp包含的页框数量太多,有些页框可能早已不在cache中,从而失去了其本身的目的。这些缓存在pcp中的页框,若释放到free_area中则可能可以与其它页框合并成order更高的内存块,从而减少系统的内存碎片。

high参数目的

  • high:当pcp中的内存高于high时,其会将一部分内存释放回buddy中,如果pcp中的内存不足,也会从free_area中分配部分内存。动态调整范围在 [high_min, high_max] 之间
  • 那么每次释放或分配内存的数量是多少呢?它是由batch参数指定的,其表示单次分配或释放的页框数为batch* 2 ^order个。
  • high_min ≤ high ≤ high_max
  • high_min:通常是batch*4, 保证PCP至少有high_minpage
  • high_max:通常是batch * 12 限制PCP缓存的最大页数。

2. per_cpu_pageset

每个zone下包含有一个per_cpu_pagesett数据结构记录pcp相关信息。

 

per_cpu_pageset的数据结构如下

内核启动时候start_kernel()调用setup_per_cpu_pageset()初始化per_cpu_pageset:

2.1 setup_per_cpu_pageset

(1)为每个zone调用setup_zone_pageset分配并初始化per_cpu_pageset。

2.2 setup_zone_pageset

(1)给每个cpu分配一块struct per_cpu_pages空间。

  PS: alloca_percpu: 为每个 CPU 分配一个独立的内存块。每个 CPU 访问自己的内存副本,无需同步。

(2)初始化每个cpu的struct per_cpu_pages的每个变量, 这里是给每个变量都赋0。

PS: 通过per_cpu_ptr(zone->per_cpu_pageset, cpu_x); 得到一个指针,指向cpu_x的那个struct per_cpu_pages空间。以此来访问这个结构体。

(3)真正的PCP初始化。如果配置了percpu_pagelist_fraction, 将根据实际内存大小计算high和batch的值并赋值。

函数实现

内存分配

调用过程

rmqueue_pcplist

(1)当pcp list为空时调用rmqueue_bulk从buddy申请batch个页面。

(2)从pcp list里找到page分配并从list里删除。

释放内存

free_frozen_page_commit

(1)把page添加到pcp list中,增加pcp的page计数pcp->count。

(2)计算watermark,如果pcp中的page技术高于watermark就释放batch* 2 ^order个page到buddy。

function main() { mem_total_str=`cat /proc/meminfo |grep MemTotal` mem_total=${mem_total_str:16:8} fn_enable=`getprop persist.sys.oplus.nandswap` kernel_version=`uname -r` fg_protect_enable=`getprop persist.sys.oplus.fg.protect.condition` if [ -z "$fg_protect_enable" ]; then fg_protect_enable=0 fi # if kernel_version is 5.1*, use zstdn for better performance if [[ "$kernel_version" == "5.1"* ]]; then zram1_comp_algorithm="zstdn" fi # We will double per-cpu pages in our uxmem ko. Our ko is loaded after # pcp pages set. So here we write something to percpu_pagelist_fraction # then we write it back immediatelly to trigger a pcp pages update. # It is not needed for kernels above 5.15 as their pcp pages is quite large. if [[ "$kernel_version" == "5.10"* ]]; then percpu_pagelist_fraction=`cat /proc/sys/vm/percpu_pagelist_fraction` echo 10000 > /proc/sys/vm/percpu_pagelist_fraction echo $percpu_pagelist_fraction > /proc/sys/vm/percpu_pagelist_fraction fi if [ -e "/sys/kernel/mm/chp/enabled" ]; then chp_supported=1 fi if [ -z $mem_total ]; then echo -e "read meminfo failed\n" exit -1 fi if [ $chp_supported -eq 1 ]; then local val=0 if [ "$my_engineering_type" != "release" ]; then val=1 fi echo $val > /sys/kernel/mm/chp/bug_on fi if [ -L "/dev/block/mapper/hybridswap_crypto" ]; then hybridswap_partition="/dev/block/mapper/hybridswap_crypto" fi if [ -L $hybridswap_partition -a "$fn_enable" == "true" ]; then nandswapV2_supported=1 fi load_mm_config configure_platform_parameters set_mm_config configure_nandswap_parameters ret=$? if [ $ret -eq 22 ]; then nandswap_sz_mb=0 nandswapV2_supported=0 configure_zram_parameters setprop $prop_nandswap_curr 0 zram_init exit fi configure_zram_parameters zram_init if [ "$fn_enable" == "true" -a "$nandswap_sz_mb" != "0" ]; then nandswap_init else write_nandswap_err $ERR_SET_ZRAM setprop $prop_nandswap_curr 0 fi setprop persist.sys.oplus.hybridswap_app_memcg false setprop persist.sys.oplus.hybridswap_app_uid_memcg false if [ $hybridswap_init -eq 1 ]; then if [[ "$kernel_version" == "5.1"* ]]; then if [ $chp_supported -eq 0 ] && [ $mem_total -gt 4194304 ] && [ ! -f /my_product/etc/extension/sys_mt_config_list.xml ]; then setprop persist.sys.oplus.hybridswap_app_uid_memcg true fi fi support_memory_nirvana_feature support_nirvana=$? if [ "$support_nirvana" -eq 1 ] && [ $mem_total -gt 6291456 ]; then setprop persist.sys.oplus.hybridswap_app_uid_memcg true fi setprop persist.sys.oplus.hybridswap_app_memcg true fi if [ $fg_protect_enable -eq 1 ]; then setprop persist.sys.oplus.hybridswap_app_uid_memcg true setprop persist.sys.oplus.hybridswap_app_memcg true fi } 代码注释
08-24
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值