基于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的页缓存释放到伙伴系统的全局链表上。
标签:11,缓存,buddy,zone,struct,链表,CPU,页面 From: https://www.cnblogs.com/hellokitty2/p/18279836