判断某个阶数(order)的页是否允许走 PCP(Per-CPU Pages)缓存路径。它是 PCP 分配/释放入口的第一道"门槛"检查,用static inline强制内联。
一、函数签名
static inline bool pcp_allowed_order(unsigned int order)
参数
| 参数 | 类型 | 含义 |
|---|---|---|
order | unsigned int | 分配阶数(0 ~MAX_ORDER-1) |
返回值
bool:true表示该阶数允许走 PCP 路径;false表示不允许,应直接走伙伴系统。
static inline
文件内私有 + 强制内联。
在
rmqueue()、free_unref_page()等极热路径的入口调用,必须零开销。
二、背景:为什么 PCP 只允许低阶页?
PCP 缓存的是低阶页(order ≤
PAGE_ALLOC_COSTLY_ORDER,通常为 3)。更高阶的页(order > 3)直接走伙伴系统,不进 PCP。
原因
1. 高阶页数量少、不"热"
系统运行中,绝大多数分配是order 0(单页),少量是 order 1/2/3。
order ≥ 4 的分配("costly order")很少,缓存它们收益不大。
2. 缓存高阶页会浪费内存
PCP 是每个 CPU、每个 zone一份。
如果缓存高阶页,一个 CPU 可能囤积几十上百页的大块,乘以 CPU 数 × zone 数,浪费巨大。
低阶页缓存代价小(单页/几页),收益高。
3. 高阶页释放/合并复杂
高阶页释放时涉及伙伴合并,走伙伴系统更自然。
放进 PCP 再取出会打乱合并时机。
PAGE_ALLOC_COSTLY_ORDER
内核常量,通常为3。
含义:
order > PAGE_ALLOC_COSTLY_ORDER的分配被视为"代价高(costly)",分配器会更谨慎、更努力避免失败。PCP 允许的最大阶数就是
PAGE_ALLOC_COSTLY_ORDER。
三、典型实现
static inline bool pcp_allowed_order(unsigned int order) { if (order <= PAGE_ALLOC_COSTLY_ORDER) return true; #ifdef CONFIG_PCP_BATCH_SCALE_MAX /* 某些配置下允许更大阶数走 PCP? */ #endif return false; }或更简洁地:
static inline bool pcp_allowed_order(unsigned int order) { return order <= PAGE_ALLOC_COSTLY_ORDER; }可能的变体
不同内核版本/配置下,实现可能略有差异:
1. 基础版本
return order <= PAGE_ALLOC_COSTLY_ORDER;
最直接:order ≤ 3 允许,否则不允许。
2. 带配置的版本
某些内核可能引入配置项,允许调整 PCP 支持的最大阶数。
但主流实现就是
order <= PAGE_ALLOC_COSTLY_ORDER。
3. 与MIGRATE_PCPTYPES配合
除了阶数,PCP 还限制迁移类型(只缓存
MIGRATE_PCPTYPES种)。pcp_allowed_order()只管阶数,迁移类型的限制在order_to_pindex()里处理。两者共同决定"某次分配/释放能否走 PCP"。
四、调用场景
1. 分配路径:rmqueue()
static inline struct page *rmqueue(struct zone *zone, unsigned int order, ...) { if (likely(pcp_allowed_order(order))) { page = rmqueue_pcplist(zone, order, ...); // 走 PCP if (page) return page; } /* 否则走伙伴系统 */ return __rmqueue(zone, order, ...); }先判断阶数是否允许走 PCP;
允许则尝试从 PCP 取页