使用 move_pages() 移动大页?

2023-12-04

这个问题是针对:

  1. 内核3.10.0-1062.4.3.el7.x86_64
  2. 通过引导参数分配的非透明大页,可能会或可能不会映射到文件(例如安装的大页)
  3. x86_64

根据这个内核source, move_pages()将会通知do_pages_move()移动页面,但我不知道它是如何间接调用的migrate_huge_page().

所以我的问题是:

  1. can move_pages()移动大页?如果是,在传递页面地址数组时,页面边界应该是 4KB 还是 2MB?好像有一个patch5 年前支持移动大页。
  2. if move_pages()无法移动大页,如何移动大页?
  3. 移动大页面后,我可以像查询常规页面一样查询大页面的 NUMA ID吗answer?

根据下面的代码,我似乎通过以下方式移动大页面move_pages()页面大小 = 2MB 但这是正确的方法吗?:

#include <cstdint>
#include <iostream>
#include <numaif.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <limits>

int main(int argc, char** argv) {
        const int32_t dst_node = strtoul(argv[1], nullptr, 10);
        const constexpr uint64_t size = 4lu * 1024 * 1024;
        const constexpr uint64_t pageSize = 2lu * 1024 * 1024;
        const constexpr uint32_t nPages = size / pageSize;
        int32_t status[nPages];
        std::fill_n(status, nPages, std::numeric_limits<int32_t>::min());;
        void* pages[nPages];
        int32_t dst_nodes[nPages];
        void* ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_HUGETLB, -1, 0);

        if (ptr == MAP_FAILED) {
                throw "failed to map hugepages";
        }
        memset(ptr, 0x41, nPages*pageSize);
        for (uint32_t i = 0; i < nPages; i++) {
                pages[i] = &((char*)ptr)[i*pageSize];
                dst_nodes[i] = dst_node;
        }

        std::cout << "Before moving" << std::endl;

        if (0 != move_pages(0, nPages, pages, nullptr, status, 0)) {
            std::cout << "failed to inquiry pages because " << strerror(errno) << std::endl;
        }
        else {
                for (uint32_t i = 0; i < nPages; i++) {
                        std::cout << "page # " << i << " locates at numa node " << status[i] << std::endl;
                }
        }

        // real move
        if (0 != move_pages(0, nPages, pages, dst_nodes, status, MPOL_MF_MOVE_ALL)) {
                std::cout << "failed to move pages because " << strerror(errno) << std::endl;
                exit(-1);
        }

        const constexpr uint64_t smallPageSize = 4lu * 1024;
        const constexpr uint32_t nSmallPages = size / smallPageSize;
        void* smallPages[nSmallPages];
        int32_t smallStatus[nSmallPages] = {std::numeric_limits<int32_t>::min()};
        for (uint32_t i = 0; i < nSmallPages; i++) {
                smallPages[i] = &((char*)ptr)[i*smallPageSize];
        }


        std::cout << "after moving" << std::endl;
        if (0 != move_pages(0, nSmallPages, smallPages, nullptr, smallStatus, 0)) {
            std::cout << "failed to inquiry pages because " << strerror(errno) << std::endl;
        }
        else {
                for (uint32_t i = 0; i < nSmallPages; i++) {
                        std::cout << "page # " << i << " locates at numa node " << smallStatus[i] << std::endl;
                }
        }

}

我应该根据 4KB 页面大小查询 NUMA ID(如上面的代码)吗?还是2MB?


对于 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 目录.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 move_pages() 移动大页? 的相关文章

  • 为什么基类必须有一个带有 0 个参数的构造函数?

    这不会编译 namespace Constructor0Args class Base public Base int x class Derived Base class Program static void Main string a
  • 使用实体框架从集合中删除项目

    我正在使用DDD 我有一个 Product 类 它是一个聚合根 public class Product IAggregateRoot public virtual ICollection
  • std::map 和二叉搜索树

    我读过 std map 是使用二叉搜索树数据结构实现的 BST 是一种顺序数据结构 类似于数组中的元素 它将元素存储在 BST 节点中并按其顺序维护元素 例如如果元素小于节点 则将其存储在节点的左侧 如果元素大于节点 则将其存储在节点的右侧
  • 调试内存不足异常

    在修复我制作的小型 ASP NET C Web 应用程序的错误时 我遇到了 OutOfMemoryException 没有关于在哪里查看的提示 因为这是一个编译时错误 如何诊断此异常 我假设这正是内存分析发挥作用的地方 有小费吗 Thank
  • 为什么 BOOST_FOREACH 不完全等同于手工编码的?

    From 增强文档 http www boost org doc libs 1 48 0 doc html foreach html foreach introduction what is literal boost foreach li
  • 如何在 VS 中键入时显示方法的完整文档?

    标题非常具有描述性 是否有任何扩展可以让我看到我正在输入的方法的完整文档 我想查看文档 因为我可以在对象浏览器中看到它 其中包含参数的描述和所有内容 而不仅仅是一些 摘要 当然可以选择查看所有覆盖 它可能是智能感知的一部分 或者我不知道它并
  • VS30063:您无权访问 https://dev.azure.com

    我正在尝试在 asp net core 2 1 mvc 应用程序中使用以下代码连接 Azure DevOps Uri orgUrl new Uri https dev azure com xxxxx String personalAcces
  • 是否有与 C++11 emplace/emplace_back 函数类似的 C# 函数?

    从 C 11 开始 可以写类似的东西 include
  • 为什么 std::allocator 在 C++17 中丢失成员类型/函数?

    一边看着std 分配器 http en cppreference com w cpp memory allocator 我看到成员 value type pointer const pointer reference const refer
  • Xamarin Android:获取内存中的所有进程

    有没有办法读取所有进程 而不仅仅是正在运行的进程 如果我对 Android 的理解正确的话 一次只有一个进程在运行 其他所有进程都被冻结 后台进程被忽略 您可以使用以下代码片段获取当前正在运行的所有 Android 应用程序进程 Activ
  • 事件日志写入错误

    很简单 我想向事件日志写入一些内容 protected override void OnStop TODO Add code here to perform any tear down necessary to stop your serv
  • 用于从字符串安全转换的辅助函数

    回到 VB6 我编写了一些函数 让我在编码时无需关心字符串的 null 和 数字的 null 和 0 等之间的区别 编码时 没有什么比添加特殊情况更能降低我的工作效率了用于处理可能导致一些不相关错误的数据的代码 9999 10000 如果我
  • “MyClass”的类型初始值设定项引发异常

    以下是我的Windows服务代码 当我调试代码时 我收到错误 异常 CSMessageUtility CSDetails 的类型初始值设定项引发异常 using System using System Collections Generic
  • 如何在 shell 脚本中并行运行多个实例以提高时间效率[重复]

    这个问题在这里已经有答案了 我正在使用 shell 脚本 它读取 16000 行的输入文件 运行该脚本需要8个多小时 我需要减少它 所以我将其划分为 8 个实例并读取数据 其中我使用 for 循环迭代 8 个文件 并在其中使用 while
  • gdb查找行号的内存地址

    假设我已将 gdb 附加到一个进程 并且在其内存布局中有一个文件和行号 我想要其内存地址 如何获取文件x中第n行的内存地址 这是在 Linux x86 上 gdb info line test c 56 Line 56 of test c
  • 为什么我使用google'smtp'无法发送电子邮件?

    我有以下程序使用 smtp gmail com 587 发送电子邮件 namespace TestMailServer class Program static void Main string args MailMessage mail
  • Fluent NHibernate 日期时间 UTC

    我想创建一个流畅的 nhibernate 映射来通过以下方式映射 DateTime 字段 保存时 保存 UTC 值 读取时 调整为本地时区值 实现此映射的最佳方法是什么 就我个人而言 我会将日期存储在 UTC 格式的对象中 然后在读 写时在
  • 为什么 Ajax.BeginForm 在 Chrome 中不起作用?

    我正在使用 c NET MVC2 并尝试创建一个 ajax 表单来调用删除数据库记录 RemoveRelation 的方法 删除记录的过程正在按预期进行 删除记录后 表单应调用一个 JavaScript 函数 从视觉效果中删除该记录 Rem
  • Azure函数版本2.0-应用程序blobTrigger不工作

    我有一个工作功能应用程序 它有一个 blob 输入和一个事件中心输出 在测试版中工作 随着最新的更改 我的功能不再起作用 我尝试根据发行说明更新 host json 文件 但它没有引用 blob 触发器 version 2 0 extens
  • 如何创建向后兼容 Windows 7 的缩放和尺寸更改每显示器 DPI 感知应用程序?

    我是 WPF 和 DPI 感知 API 的新手 正在编写一个在 Windows 7 8 1 和 10 中运行的应用程序 我使用具有不同每个显示器 DPI 设置的多个显示器 并且有兴趣将我的应用程序制作为跨桌面配置尽可能兼容 我已经知道可以将

随机推荐