Skip to content

Latest commit

 

History

History
54 lines (45 loc) · 2.92 KB

page-migration.md

File metadata and controls

54 lines (45 loc) · 2.92 KB

page migration

页迁移最初是为了解决NUMA中一个节点的CPU上运行的进程访问另一个节点中 的内存而提出的,目前内存紧缩(compaction)创建大页时,也需要用到页 迁移。

应用程序可以使用mbind系统调用的MF_MOVE和MF_MOVE_ALL将该程序的内存都 迁移到指定的内存节点中,或者使用migrate_pages函数将其他程序的内存迁 移到某个内存节点之中,这样做的目的是为了降低内存访问的开销,使得每个 CPU都能访问到离它最近的内存。目前大多数内存迁移都需要人为的去指定, 操作系统不能自动进行,有些时候NUMA系统会根据一些内存访问的统计信息 做出一些迁移。

cgroup中的cpuset子系统是用来管理NUMA系统中的节点,当属于一个cpuset 的进程被迁移到另一个cpuset中时,该进程使用的内存也会自动的被迁移到 另一个cpuset中。

内核中使用migrate_pages的方法

  1. 使用isolate_lru_page函数将待迁移的页从LRU链表上删除;
  2. 准备分配新内存的函数,这个函数负责分配新的内存——即将迁移到的内存;
  3. 调用migrate_pages函数开始内存迁移;

migrate_pages迁移步骤

  1. 锁定即将迁移的页;
  2. 保证该页已经完成了回写(writeback);
  3. 锁定即将迁移到的页;
  4. 将所有页表对旧页的访问都替换为迁移项(migration entries),这将会 减少旧页中的mapcount字段,如果旧页中的mapcount字段不为0,那么将不能进 行迁移。所有用户空间需要访问旧页的进程都会等待在page lock上;
  5. 获取基树锁(radix tree lock),这将会导致所有通过映射访问待迁移内存 的进程在基树自旋锁上等待;
  6. 检查旧页的refcount,如果refcount为1,说明此页可以进行迁移,因为我们 是唯一的使用者了;
  7. 检查基树中是否包含旧页,如果不包含,不能迁移,说明其他部分修改了基树;
  8. 根据旧页的设置来设置新页;
  9. 基树指向新页;
  10. 从基树中删除旧页,并将旧页的refcount减1;将新页的refcount加1;
  11. 释放基树锁,现在程序可以通过获取基树锁来查找映射,程序从基树锁上的 等待转移到page lock上的等待;
  12. 旧页中的数据被拷贝到新页中;
  13. 旧页中剩余的页标记被拷贝到新页中;
  14. 旧页中的标记被清除,表明这个页中不再包含有用的数据;
  15. 触发新页的writeback;
  16. 如果迁移项(migration entries)是页,就把他们替换为真正的pte;这样 就可以让那些还没有等待在page lock上的用户空间进程访问内存了;
  17. 释放旧页和新页的锁,等待在page lock上的进程将会重新执行page fault, 这样就可以到达新页;
  18. 新页被加入到LRU,因此可以被swapper等进行扫描;

ref

http://lxr.free-electrons.com/source/Documentation/vm/page_migration