内存管理-11-buddy伙伴子系统-2-Per-CPU页帧缓存

基于msm-5.4

一、概述

1. 实现背景

buddy子系统管理的物理页面,绝大多数都是放在 zone::free_area[] 中的链表中,少部分放在 zone::lowmem_reserve[] 中。还有少量页面放在
zone::__percpu pageset 这个每CPU变量中,每种迁移类型也都对应一个链表,但是没有order,都是单页大小的内存块。

由于前两个部分对所有CPU来说是全局的,链表的维护需要拿锁,这个同步带来开销。现在多核CPU是有多级缓存的,只有L1是私有的,L2/L3都是公有的,不同的CPU去访问同一个变量的时候,又涉及到缓存的同步刷新问题,这也会带来一定的开销。

使用本地缓存的页面不需要去申请锁,单个物理页面的申请释放是最频繁的,如果将单个物理页面的申请与释放做成一个每CPU的缓存,这样就不需要去拿全局锁了。Per-CPU页帧缓存的目的就是提升申请物理内存的性能,减少锁和cache缓存同步带来的开销。


2. 实现原理

struct zone 中有一个每CPU的 pageset 成员。

struct zone {
    struct per_cpu_pageset __percpu *pageset;
}

struct per_cpu_pageset {
    struct per_cpu_pages pcp;
    s8 stat_threshold;
    s8 vm_stat_diff[NR_VM_ZONE_STAT_ITEMS];
};

struct per_cpu_pages {
    int count;        //lists链表中页面的个数
    int high;        //高水位,需要清空
    int batch;        //伙伴块添加/删除的大小
    struct list_head lists[MIGRATE_PCPTYPES]; //每个迁移类型一个链表,链表上的页面都是单个物理页
};

在释放单个物理页的时候,不会释放给伙伴系统,而是直接释放到自己的本地 per_cpu_pages::lists 链表上。等到下次再申请单个物理页面时,首先去本地链表上去拿,若拿不到再到全局伙伴系统中去拿。

这个本地链表上缓存的单个物理页面的个数不是无限增加的,当超过 _watermark[] 水位值,伙伴系统中页面数较少的时候,会再将每CPU的页缓存释放到伙伴系统的全局链表上。

 

posted on 2024-07-02 14:43  Hello-World3  阅读(39)  评论(0编辑  收藏  举报

导航