对于 3.10 linux 内核的原始版本(没有 Redhat 补丁,因为我没有适用于 rhel 内核的 LXR)syscall move_pages将强制将大页面(2MB;THP 和 Hugetlbfs 样式)拆分为小页面(4KB)。 move_pages 使用的块太短(如果我计算正确的话大约 0.5MB),函数图如下:
move_pages
..->migrate_pages
-> unmap_and_move
->
static int unmap_and_move(new_page_t get_new_page, unsigned long private,
struct page *page, int force, enum migrate_mode mode)
{
struct page *newpage = get_new_page(page, private, &result);
....
if (unlikely(PageTransHuge(page)))
if (unlikely(split_huge_page(page)))
goto out;
PageTransHuge
对于两种大页(thp 和 libhugetlbs)返回 true:https://elixir.bootlin.com/linux/v3.10/source/include/linux/page-flags.h#L411
PageTransHuge() 对于透明巨大页面和巨大页面都返回 true,但对于普通页面则不返回 true。
And split_huge_page
will call split_huge_page_to_list
which:
将大页拆分为普通页。这不会改变首页的位置。
Split 还将发出 vm_event 计数器增量THP_SPLIT
。计数器出口于/proc/vmstat
(“文件显示各种虚拟内存统计信息”)。你可以检查这个柜台使用此 UUOC 命令 cat /proc/vmstat |grep thp_split
测试之前和之后。
3.10版本中有一些大页迁移的代码如下unmap_and_move_huge_page
不被调用的函数move_pages
. The 只使用它3.10 是在migrate_huge_page which 叫做仅从内存故障处理程序 soft_offline_huge_page
(__soft_offline_page
) (添加2010):
通过迁移或失效使页面软脱机,
不杀任何东西。这是针对以下情况:
页面尚未损坏(因此仍然可以访问),
但已经纠正了一些错误,最好采取
出去。
Answers:
move_pages() 可以移动大页吗?如果是,在传递页面地址数组时,页面边界应该是 4KB 还是 2MB?好像 5 年前就已经有一个支持移动大页的补丁了。
标准 3.10 内核具有 move_pages,它将接受 4KB 页面指针的数组“页面”,并将大页面分解(分割)为 512 个小页面,然后迁移小页面。它们被 thp 合并回来的机会非常低,因为 move_pages 会单独请求物理内存页面,并且它们几乎总是不连续的。
不要给出指向“2MB”的指针,它仍然会分割提到的每个大页面,并仅迁移该内存的前 4KB 小页面。
2013补丁没有添加到原来的3.10内核中。
- v2 https://lwn.net/Articles/544044/“扩展大页迁移”(3.9);
- v3 https://lwn.net/Articles/559575/ (3.11)
- v4 https://lore.kernel.org/patchwork/cover/395020/(单击“相关”即可访问各个补丁,例如move_pages补丁)
该补丁似乎于 2013 年 9 月被接受:
如果 move_pages() 无法移动大页,我该如何移动大页?
move_pages
会将数据从大页移动为小页。您可以: 在正确的 numa 节点以手动模式分配大页并复制数据(如果要保留虚拟地址,则复制两次);或者使用补丁更新内核到某个版本并使用补丁作者的方法和测试,堀口直也 (JP)。有他的测试副本:https://github.com/srikanth007m/test_hugepage_migration_extension
(https://github.com/Naoya-Horiguchi/test_core是必须的)
https://github.com/srikanth007m/test_hugepage_migration_extension/blob/master/test_move_pages.c
现在我不确定如何开始测试以及如何检查它是否正常工作。为了./test_move_pages -v -m private -h 2048
使用最新的内核运行它不会增加 THP_SPLIT 计数器。
他的测试看起来与我们的测试非常相似:mmap、memset 到错误页面、用指向小页面的指针填充页面数组,numa_move_pages
移动大页面后,我可以像查询常规页面一样查询大页面的 NUMA ID吗?
您可以通过提供正确的数组“页面”来查询任何内存的状态move_pages
查询模式下的系统调用(具有空节点)。数组应该列出您要检查的内存区域的每个小页面。
如果您知道任何可靠的方法来检查内存是否映射到大页面,则可以查询大页面的任何小页面。我认为如果您可以将物理地址从内核导出到用户空间(使用一些LKM模块例如):对于大页虚拟地址和物理地址将始终有 21 个公共地址LSB bits,并且对于小页面,仅百万分之一的测试中位会重合。或者直接写LKM导出PMD 目录.