linux3.10 内存管理(三)per_cpu_page缓存

1 per_cpu缓存数据结构

在每一个内存域结构中都有一个指针,该指针指向本内存域每cpu缓存管理结构

struct zone {

......

        struct per_cpu_pageset __percpu *pageset;

......

}

struct per_cpu_pageset {

        struct per_cpu_pages pcp;

......

};
struct per_cpu_pages {

        int count; 

        int high; 

        int batch; 

        struct list_head lists[MIGRATE_PCPTYPES];

};

如果只分配一个页帧,可以直接从per_cpu缓存中分配,而不用经过伙伴系统,可以提高分配效率。Count记录了per_cpu缓存中页帧的总数,high记录了per_cpu缓存中页帧的上限,如果超过这个值就将释放 batch个页帧到伙伴系统中去,如果per_cpu中没有可分配的页帧就从伙伴系统中分配batch个页帧到缓存中来。Per_cpu缓存中的页帧的page就挂接在struct list_head lists中。为防止产生过多内存碎片,内核将页帧分类:可移动页,不可移动页,可回收页等等。内核还定义了一个枚举类型来表示这些可能的类型。

include/linux/mmzone.h

enum {

        MIGRATE_UNMOVABLE,不可移动页帧

        MIGRATE_RECLAIMABLE,可回收页帧

        MIGRATE_MOVABLE,可移动页帧

每CPU缓存链表上能管理的页帧类型的个数

        MIGRATE_PCPTYPES,       /* the number of types on the pcp lists */

前三种的列表中都没用可满足分配的内存块时,就可以从MIGRATE_RESERVE分配

        MIGRATE_RESERVE = MIGRATE_PCPTYPES,

#ifdef CONFIG_CMA

        MIGRATE_CMA,

#endif

用于跨越NUMA节点移动物理内存页,

        MIGRATE_ISOLATE,        /* can't allocate from here */

        MIGRATE_TYPES 表示迁移类型的数目

};

2 per_cpu缓存初始化

在内核启动之初per_cpu机制还没有初始化,用于动态分配per_cpu变量的空间还没有分配,所以定义了一个静态的per_cpu变量boot_pageset,用以暂时管理内存域的per_cpu缓存。

mm/page_alloc.c

static DEFINE_PER_CPU(struct per_cpu_pageset, boot_pageset);

初始化内存域的zone->pageset字段:

start_kernel

     ------->setup_arch

          ---------->paging_init

              ----------->bootmem_init

                    ----------->arm_bootmem_free

                          ------------>free_area_init_node

                                ------------->free_area_init_core

                                      -------------->zone_pcp_init

static __meminit void zone_pcp_init(struct zone *zone)
{
	/*
	 * per cpu subsystem is not up at this point. The following code
	 * relies on the ability of the linker to provide the
	 * offset of a (static) per cpu variable into the per cpu area.
	 */
	zone->pageset = &boot_pageset;

	if (zone->present_pages)
		printk(KERN_DEBUG "  %s zone: %lu pages, LIFO batch:%u\n",
			zone->name, zone->present_pages,
					 zone_batchsize(zone));
}

初始化每个cpu的per_cpu管理结构per_cpu_pages,因为后面将有页帧分配。此时的管理结构仍然是静态分配的那个per_cpu变量,boot_pageset。

start_kernel

      ------->build_all_zonelists

           --------->__build_all_zonelists

static __init_refok int __build_all_zonelists(void *data)

{

......

        for_each_possible_cpu(cpu) {

                setup_pageset(&per_cpu(boot_pageset, cpu), 0);

......

}

start_kernel

       ---------->setup_per_cpu_pageset

前面所用per_cpu管理结构都是临时静态分配的。现在per_cpu机制已经启动,所以重新动态分配一个per_cpu管理结构并初始化。

void __init setup_per_cpu_pageset(void)

{

        struct zone *zone;

遍历每一个内存域,如果某内存域有实际内存,就初始化该内存域的per_cpu管理结构。

        for_each_populated_zone(zone)

                setup_zone_pageset(zone);

}
static void setup_zone_pageset(struct zone *zone)

{

        int cpu;

动态分配per_cpu管理结构

        zone->pageset = alloc_percpu(struct per_cpu_pageset);

        for_each_possible_cpu(cpu) {

                struct per_cpu_pageset *pcp = per_cpu_ptr(zone->pageset, cpu);

初始化per_cpu管理结构的相关字段,函数zone_batchsize根据内存域中页帧多少计算batch的大小

                setup_pageset(pcp, zone_batchsize(zone));

变量percpu_pagelist_fraction可以再/proc/sys/vm/percpu_pagelist_fraction中设置。

                if (percpu_pagelist_fraction)

                        setup_pagelist_highmark(pcp,

                                (zone->present_pages /

                                        percpu_pagelist_fraction));

        }

}

Batch值大约为内存域中内存的0.25‰。

static void setup_pageset(struct per_cpu_pageset *p, unsigned long batch)

{

        struct per_cpu_pages *pcp;

        int migratetype;

        memset(p, 0, sizeof(*p));

        pcp = &p->pcp;

        pcp->count = 0;

        pcp->high = 6 * batch; per_cpu缓存中页帧数不能超过6 *batch。

        pcp->batch = max(1UL, 1 * batch);

清空链表,每一种类型的页帧都有对应类型的链表

        for (migratetype = 0; migratetype < MIGRATE_PCPTYPES; migratetype++)

                INIT_LIST_HEAD(&pcp->lists[migratetype]);

}

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值