ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

page_alloc account_freepages

page_alloc account_freepages 空闲页计数与统计更新的辅助函数。它在页被释放回伙伴系统或从伙伴系统取出时调用负责更新 zone 的空闲页计数、迁移类型统计、内存事件等。一、函数签名static inline void account_freepages(struct zone *zone, int nr_pages, int migratetype)参数参数类型含义zonestruct zone *目标 zonenr_pagesint页数变化量可正可负migratetypeint迁移类型用于更新对应统计返回值void。static inline文件内私有 强制/建议内联。在伙伴系统的分配/释放热路径上频繁调用必须零开销。二、nr_pages的符号约定关键nr_pages可正可负。场景nr_pages含义释放页正数空闲页增加分配页负数空闲页减少释放account_freepages(zone, 1 order, migratetype)→ zone 空闲页 2^order。分配account_freepages(zone, -(1 order), migratetype)→ zone 空闲页 -2^order。为什么统一用带符号的int一个函数同时处理增加和减少避免写两个函数。调用方只需传正/负值逻辑简单。内部按符号更新各项统计。三、典型实现static inline void account_freepages(struct zone *zone, int nr_pages, int migratetype) { /* * 1. 更新 zone 的空闲页计数 * zone-free_area 各阶空闲页总数 */ __mod_zone_page_state(zone, NR_FREE_PAGES, nr_pages); /* * 2. 更新 zone 的按迁移类型空闲页统计 * 某些内核版本用 NR_FREE_CMA_PAGES 等独立计数 */ if (is_migrate_cma(migratetype)) __mod_zone_page_state(zone, NR_FREE_CMA_PAGES, nr_pages); /* * 3. 更新全局 VM 事件计数 * 如 PGALLOC页分配、PGFREE页释放 */ __count_zid_vm_events(PGALLOC, zone_idx(zone), nr_pages); /* 或根据符号区分 PGALLOC / PGFREE */ }逐步说明1. 更新 zone 空闲页计数__mod_zone_page_state(zone, NR_FREE_PAGES, nr_pages);NR_FREE_PAGESzone 的空闲页总数per-CPU 缓存 伙伴系统。__mod_zone_page_state()以per-CPU 差分方式更新避免频繁加锁。这是最核心的更新zone-vm_stat[NR_FREE_PAGES] nr_pages。2. 更新迁移类型相关统计if (is_migrate_cma(migratetype)) __mod_zone_page_state(zone, NR_FREE_CMA_PAGES, nr_pages);CMA 页有独立计数NR_FREE_CMA_PAGES用于判断 CMA 区域是否充足。其他迁移类型可能共用NR_FREE_PAGES不单独统计。某些版本还会更新NR_FREE_PAGES之外的 per-migratetype 计数如/proc/pagetypeinfo的数据来源。3. 更新 VM 事件计数__count_zid_vm_events(PGALLOC, zone_idx(zone), nr_pages);PGALLOC页分配事件。__count_zid_vm_events()按 zone 统计事件。释放时可能记PGFREE分配时记PGALLOC——具体实现可能用符号判断。这些计数用于/proc/vmstat展示。4. 与水位、回收的联动更新NR_FREE_PAGES后水位判断zone_watermark_ok()才能正确工作。如果空闲页低于水位可能触发 kswapd 唤醒。所以account_freepages()是内存压力感知的基础。四、与__mod_zone_freepage_state()的关系在伙伴系统代码里常会看到另一个函数static inline void __mod_zone_freepage_state(struct zone *zone, int nr_pages, int migratetype) { __mod_zone_page_state(zone, NR_FREE_PAGES, nr_pages); if (is_migrate_cma(migratetype)) __mod_zone_page_state(zone, NR_FREE_CMA_PAGES, nr_pages); }__mod_zone_freepage_state()是更早/更常见的名字功能与account_freepages()类似。不同内核版本可能用__mod_zone_freepage_state()或重命名为account_freepages()并扩展功能加 VM 事件统计。语义一致更新 zone 空闲页计数含 CMA 特殊处理。使用示例__free_one_page()static inline void __free_one_page(struct page *page, unsigned long pfn, struct zone *zone, unsigned int order, int migratetype, fpi_t fpi_flags) { ... if (compaction_capture(...)) return; /* 被捕获不计入常规空闲 */ set_buddy_order(page, order); list_add(page-lru, zone-free_area[order].free_list[migratetype]); /* 更新统计 */ account_freepages(zone, 1 order, migratetype); }使用示例分配路径static inline void expand(struct zone *zone, struct page *page, int low, int high, int migratetype) { ... /* 分裂大块剩余部分放回 */ set_buddy_order(page[size], high); list_add(page[size].lru, zone-free_area[high].free_list[migratetype]); account_freepages(zone, 1 high, migratetype); }五、为什么要用 per-CPU 差分__mod_zone_page_state(zone, NR_FREE_PAGES, nr_pages);zone 的统计是全局的但更新非常频繁每次分配/释放。如果每次都加锁改全局计数器竞争严重、性能差。内核用per-CPU 差分每个 CPU 维护自己的差分值更新时只改本地差分无锁读全局值时把所有 CPU 差分汇总。这就是__mod_zone_page_state比zone_page_state_add直接改快的原因。代价读到的值可能有轻微延迟/不一致但对统计/水位判断足够。六、与前面内容的呼应前面出现过的这里的关联__free_one_page()释放路径调用account_freepages()expand()/__rmqueue_smallest()分配/分裂路径调用set_buddy_order()标记 Buddy 状态后调用统计compaction_capture()捕获的页不计入统计提前 returnMIGRATE_CMA/is_migrate_cma()特殊处理 CMA 计数zone_watermark_ok()依赖NR_FREE_PAGES本函数更新它NR_FREE_PAGES/NR_FREE_CMA_PAGES本函数更新的计数项per-CPU 差分__mod_zone_page_state的实现方式调用链__free_one_page() / expand() / __rmqueue_smallest() └── account_freepages(zone, ±nr_pages, migratetype) ├── __mod_zone_page_state(zone, NR_FREE_PAGES, nr_pages) // 核心 ├── if (is_migrate_cma) __mod_zone_page_state(..., NR_FREE_CMA_PAGES, ...) └── __count_zid_vm_events(PGALLOC/PGFREE, zone_idx(zone), ...)七、小结表项说明函数名account_freepages作用更新 zone 空闲页计数、迁移类型统计、VM 事件参数zone目标 zone参数nr_pages页数变化量正释放/增加负分配/减少参数migratetype迁移类型用于 CMA 等特殊统计返回值void可见性static inline热路径核心操作__mod_zone_page_state(NR_FREE_PAGES) CMA 特殊 VM 事件别名/前身__mod_zone_freepage_state()实现方式per-CPU 差分避免全局锁竞争调用点__free_one_page()、expand()、__rmqueue_smallest()等一句话总结account_freepages()是伙伴系统分配/释放热路径上的统计更新函数根据带符号的nr_pages正释放、负分配更新 zone 的NR_FREE_PAGES及 CMA 的NR_FREE_CMA_PAGES和 VM 事件计数采用 per-CPU 差分避免锁竞争它是水位判断、内存压力感知和/proc统计的基础与set_buddy_order()在释放路径上紧邻调用。
返回列表