欢迎光临散文网 会员登陆 & 注册

一文图解|内存页面迁移技术

2023-09-21 15:47 作者:补给站Linux内核  | 我要投稿

1. 概述

页面迁移(page migrate)最早是为 NUMA 系统提供一种将进程页面迁移到指定内存节点的能力用来提升访问性能。后来在内核中广泛被使用,如内存规整、CMA、内存hotplug等。

页面迁移对上层应用业务来说是不可感知的,因为其迁移的是物理页面,而应用只访问的是虚拟内存。内核迁移完成后,更新修改对应页表指向迁移后的页面即可。当然了这里说的不可感知是指业务不太关注,也不需要做对应修改。实际上有些场景发生页面迁移是业务性能是有影响的,下面会详细描述。

2. 典型场景

我们列举2个内核中发生页面迁移的典型场景。

2.1 NUMA Balancing引起的页面迁移

在典型 NUMA 中,存在多个 node, 本地 CPU 访问本地 node 节点对应的 memory 性能会快一些。

Linux 的 NUMA 自动均衡机制会尝试将内存迁移到正在访问它的 CPU 节点所在的 node。如下图所示, CPU24 ~ CPU47 访问不是本地 node 对应的 memory,性能会比较慢,系统会将其迁移到本地 node 对应的 memory 以提升访问性能。

迁移后如下图:

2.2 内存碎片整理

系统使用一段时候后,由于内存碎片的原因,较难满足连续内存需求,如果需要分配连续大块内存,需要进行内存规整以形成大块连续内存,页面迁移是内存碎片整理的基础。

3. 实现分析

3.1 迁移模式

内核中通过接口 migrate_pages 实现页而迁移, 分为3个模式。

3.2 实现流程

内核文档有描述这个API是怎么工作的。不过这个描述着实是不太友好, 不容易在脑海形成画面。

我们通过结合代码实现,把这个转化为流程图:

总结一下,页面迁移过程本质就是分配一个 new_page, 解除原有 page 映射,把旧 page 复制到新 page 并建立新 page 的映射。


【文章福利】小编推荐自己的Linux内核技术交流群:【749907784】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!(含视频教程、电子书、实战项目及代码)  



4. 页面迁移过程用户态访问处理

到这里可能会有疑问:如果在页面迁移过程中,应用发生发访问这个迁移中的页面,会发生什么?

  • 情景1: 旧页面的页表还未解映射, 此时发生缺页可以正常访问原来页面。


  • 情景2: 旧页面解除了映射,但新页面还未建立映射。这时访问会发生等待,需要等新页面建立映射并copy完成页面后才能访问。


  • 情景3: 完成了页面迁移动作,可以正常访问新页面了。


下面我们重点分析一下,当旧页面解除了映射,且新页面未建立映射这个过程中发生了用户态访问,内核的处理流程是怎样的。

首先我们看一下旧页面解除了映射的过程:

解除映射后,再次发生映射就走到 do_swap_page 中了。

总结一下:

页面迁移前,首先会获取旧页面和新页面的页面锁 PG_lock,在解除映射的时候传入了由于页面迁移导致的解映射标记 TTU_MIGRATION,设置了此标记会生成一个带页面迁移标识的 swap_entry 设置到 pte 中。在设置好的那一刻走,应用进程无法很顺利地访问这个页面了,需要通过 do_swap_entry 路径。

假如此时应用进程访问了这个页面,会走进到 do_swap_entry,取出带迁移标识的 swap_entry,识别到这个标识,会等待页面锁释放。页面锁只有在页面迁移完成后才会被释放,也就是会发生等待直到页面迁移完成。

5. 用户态如何避免发生页面迁移

上面我们已经知道,如果有页面迁移过程中发生用户态访问,很可能是需要发生等待其迁移完成, 这个过程需要一定耗时。而有时的场景我们是需要避免此种时延抖动,那有什么办法呢?

方法就是让这个页面短时间内变得不可移动。

可以看到当发生页面复制过程中,如果 page 的引用计数不符合预期(期望为0)时,这时系统认为有人在使用,不适用做迁移。那么,我们只需要增加 page 的引用计数就可以。

可以在不想被迁移的时间段开始前通过 pin_user_pages 这样的接口,结束时 unpin 就可以了。接口最终会调到 try_grab_page 增加引用计数。


原文作者:五花肉



一文图解|内存页面迁移技术的评论 (共 条)

分享到微博请遵守国家法律