Linux内核中对大页支持的简要概述

原链接

这个文件的目的是提供Linux内核中对大页支持的简要概述. 这种支持是建立在大多数现代体系结构提供的多页大小支持之上的. 例如, x86 CPU通常支持4K和2M(如果有架构支持则支持1G)的页面大小, ia64架构支持多种页面大小, 包括4K、8K、64K、256K、1M、4M、16M、256M, ppc64支持4K和16M. TLB是虚拟地址到物理地址的转换缓存. 通常, 这是处理器上非常有限的资源. 操作系统会尽量充分利用有限数量的TLB资源. 这种优化现在更加关键, 因为越来越大的物理内存(几GB)更容易获得.

用户可以通过使用 mmap 系统调用或标准的SYSV共享内存系统调用(shmget、shmat)在Linux内核中使用大页支持.

首先, Linux 内核需要使用 CONFIG_HUGETLBFS(位于“文件系统”下)和 CONFIG_HUGETLB_PAGE(在选择 CONFIG_HUGETLBFS 时自动选择)配置选项构建.

/proc/meminfo 文件提供了有关内核大页池中持久性大页总数的信息. 它还显示默认大页大小以及有关默认大小的大页池中的免费、保留和多余大页数量的信息. 大页大小用于生成映射大页区域的系统调用参数的适当对齐和大小.

The output of “cat /proc/meminfo” will include lines like:

.....
HugePages_Total: uuu
HugePages_Free:  vvv
HugePages_Rsvd:  www
HugePages_Surp:  xxx
Hugepagesize:    yyy kB
Hugetlb:         zzz kB
字段含义
HugePages_Free表示池中尚未分配的大页数.
HugePages_Rsvd是"保留"的缩写, 表示已经承诺从池中分配的大页数, 但尚未实际分配的数量. 保留的大页确保应用程序在出现错误时能够从大页池中分配一个大页
HugePages_Surp是"多余"的缩写, 表示池中超过 /proc/sys/vm/nr_hugepages 值的大页数. 多余大页的最大数量由 /proc/sys/vm/nr_overcommit_hugepages 控制
Hugepagesize是默认的大页大小(以KB为单位)
Hugetlb表示所有大小的大页消耗的总内存量(以KB为单位). 如果使用不同大小的大页, 此数字将超过 HugePages_Total * Hugepagesize. 要获取更详细的信息, 请参考/sys/kernel/mm/hugepages (如下所述)

/proc/filesystems 也应该显示内核中配置的类型为 “hugetlbfs” 的文件系统.

/proc/sys/vm/nr_hugepages 表示内核大页池中当前的 "持久性" 大页数量. “持久性” 大页在被任务释放时会被返回到大页池中. 具有 root 权限的用户可以通过增加或减少 ‘nr_hugepages’ 的值来动态分配更多或释放一些持久性大页.

作为大页使用的页面在内核内部被保留, 不能用于其他目的. 在内存压力下, 大页不能被交换出.

一旦一定数量的大页已经预先分配给内核的大页池, 具有适当权限的用户可以使用 mmap 系统调用或共享内存系统调用来使用大页. 请参阅下面的"使用大页"部分.

管理员可以通过在内核启动命令行上指定 "hugepages=N" 参数来分配持久性大页, 其中 ‘N’ = 请求的大页数量. 这是最可靠的分配大页的方法, 因为内存尚未变得分散.

一些平台支持多个大页大小. 要分配特定大小的大页, 必须在大页启动命令参数之前添加一个大页大小选择参数 “hugepagesz=”. 必须以字节为单位指定, 可以带有可选的比例后缀 [kKmMgG]. 默认的大页大小可以使用 “default_hugepagesz=” 启动参数来选择.

当支持多个大页大小时, /proc/sys/vm/nr_hugepages 表示当前预分配的默认大小大页的数量. 因此, 可以使用以下命令来动态分配/释放默认大小的持久性大页:

echo 20 > /proc/sys/vm/nr_hugepages

这个命令将尝试将大页面池中的默认大小的大页面数量调整为20, 根据需要分配或释放大页面.

在NUMA平台上, 内核将尝试将大页面池分布在由修改 nr_hugepages 的任务的 NUMA 内存策略指定的允许节点集合上. 当任务具有默认内存策略时, 允许节点的默认设置是所有具有内存的在线节点. 在分配持久大页面时, 如果允许的节点中没有足够的可用的连续内存来容纳大页面, 将会在分配持久大页面时静默跳过这些节点. 有关任务内存策略、cpuset 和每个节点属性与持久大页面的分配和释放交互的讨论, 请参见下面的内容.

大页面分配的成功或失败取决于系统中在分配尝试时存在的物理连续内存量. 如果内核无法从NUMA系统中的某些节点分配大页面, 它将尝试通过在具有足够可用的连续内存的其他节点上分配额外的页面来弥补差距(如果有的话).

系统管理员可能希望将此命令放在一个本地的rc初始化文件中. 这将使内核能够在引导过程的早期分配大页面, 这时获取物理连续页面的可能性仍然很高. 管理员可以通过检查sysctl或meminfo来验证实际分配的大页面数量. 要检查NUMA系统中大页面的每个节点分布, 请使用:

cat /sys/devices/system/node/node*/meminfo | fgrep Huge

/proc/sys/vm/nr_overcommit_hugepages指定了大页面池可以增长到多大, 如果应用程序请求的大页面数量超过/proc/sys/vm/nr_hugepages. 将任何非零值写入此文件表示, 当持久大页面池耗尽时, 允许大页面子系统尝试从内核的正常页面池中获取那么多"额外"的大页面. 当这些额外的大页面不再使用时, 它们将被释放回内核的正常页面池.

在通过nr_hugepages增加大页面池大小时, 任何现有的额外页面将首先提升为持久大页面. 然后, 如果需要且可能, 将分配额外的大页面, 以满足新的持久大页面池大小.

管理员可以通过将nr_hugepages sysctl设置为较小的值来缩小默认大页面大小的持久大页面池. 内核将尝试在修改nr_hugepages的任务的内存策略中的所有节点上平衡大页面的释放. 所选节点上的任何空闲大页面将被释放回内核的正常页面池.

注意:通过nr_hugepages缩小持久大页面池, 使其小于正在使用的大页面数量, 将使剩余大页面的平衡变成额外的大页面. 即使额外的页面数量超过了超额分配值, 这也会发生. 只要这个条件保持不变, 即直到nr_hugepages+nr_overcommit_hugepages足够增加, 或者额外的大页面不再使用并被释放, 就不允许分配更多的额外大页面.

有了运行时支持多个大页面池的功能, /proc/sys/vm中的大页面用户空间接口的大部分内容在sysfs中复制了一份. 上面讨论的/proc接口已经保留, 以确保向后兼容. sysfs中的根大页面控制目录为:

/sys/kernel/mm/hugepages

对于运行的内核支持的每种大页面大小, 将存在一个形式为:

hugepages-${size}kB

在这些目录中的每一个, 将存在相同的一组文件:

nr_hugepages
nr_hugepages_mempolicy
nr_overcommit_hugepages
free_hugepages
resv_hugepages
surplus_hugepages

这些文件的功能如上所述, 适用于默认大页面大小的情况.

任务内存策略与大页面分配/释放的交互

Interaction of Task Memory Policy with Huge Page Allocation/Freeing

无论是通过/proc接口还是通过使用nr_hugepages_mempolicy属性的/sysfs接口分配和释放大页面, 都受到修改nr_hugepages_mempolicy sysctl或属性的任务的NUMA内存策略的控制. 当使用nr_hugepages属性时, 内存策略会被忽略.

建议的方法, 使用上面的 nr_hugepages 示例来从内核大页面池中分配或释放大页面, 如下:

numactl --interleave <node-list> echo 20 \
			>/proc/sys/vm/nr_hugepages_mempolicy

or, more succinctly:

numactl -m <node-list> echo 20 >/proc/sys/vm/nr_hugepages_mempolicy

这将分配或释放绝对值为(20 - nr_hugepages) 的内存到指定的 <node-list> 中的节点, 具体取决于初始时持久大页面的数量是否小于或大于20. 不会在未包括在指定的 <node-list> 中的任何节点上分配或释放大页面.

通过nr_hugepages_mempolicy调整持久大页面计数时, 可以使用任何内存策略模式, 如绑定、首选、本地或交叉. 持久大页面分配的结果如下:

无论内存策略模式如何[请参阅Documentation/vm/numa_memory_policy.txt], 持久大页面将分布在内存策略中指定的节点或节点上, 就好像已经指定了“交叉”. 但是, 如果策略中的某个节点没有足够的连续内存来容纳一个大页面, 分配将不会“回退”到具有足够连续内存的最近邻节点. 这样做会导致大页面池的分布不均衡, 或者可能在任务的内存策略中不允许的节点上分配持久大页面.

可以使用绑定或交叉策略指定一个或多个节点. 如果使用首选策略指定了多个节点, 只会使用编号最低的节点. 本地策略将选择构建节点允许掩码时任务正在运行的节点. 要使本地策略具有确定性, 任务必须绑定到一个节点中的CPU或多个CPU. 否则, 任务在启动后随时可以迁移到其他节点, 因此得到的节点将是不确定的. 因此, 本地策略对此目的来说不是很有用. 可以使用任何其他内存策略模式来指定一个单一节点.

节点允许掩码将派生自任何非默认的任务内存策略, 无论是由任务自己还是其祖先(例如numactl)显式设置的策略. 这意味着, 如果从具有非默认策略的shell中调用任务, 将使用该策略. 可以使用numactl --interleave或–membind [-m]指定"all"的节点列表, 以在系统或cpuset中的所有节点上实现交错分布.

任何指定的任务内存策略(例如使用numactl)将受到任务运行的cpuset的资源限制的约束. 因此, 具有非默认策略的任务在cpuset中运行, 没有任何方法可以分配cpuset之外的大页面, 而不必先移动到包含所有所需节点的cpuset.

启动时的大页面分配尝试将请求的大页面数量分布在具有内存的所有在线节点上.

Per Node Hugepages Attributes

在sysfs中的根大页控制目录的一部分内容, 如上所述, 将在每个NUMA节点的系统设备下进行复制, 只要该节点有内存, 即:

/sys/devices/system/node/node[0-9]*/hugepages/

在sysfs中的根大页控制目录的一部分内容, 如上所述, 将在每个NUMA节点的系统设备下进行复制, 只要该节点有内存, 即:

nr_hugepages
free_hugepages
surplus_hugepages

free_hugepages 和 surplus_hugepages 属性文件是只读的. 它们分别返回父节点上的空闲和剩余 [overcommitted] 大页的数量.

nr_hugepages 属性返回指定节点上的大页总数. 当写入此属性时, 如果存在足够的资源, 将会调整父节点上的持久大页数量到指定值, 而不考虑任务的 mempolicy 或 cpuset 限制.

请注意, 过度承诺和保留页的数量保持全局数量, 因为直到故障发生时(故障任务的 mempolicy 应用), 我们无法知道大页分配将尝试从哪个节点开始

Using Huge Pages

如果用户应用程序要使用 mmap 系统调用请求大页, 那么系统管理员需要挂载 hugetlbfs 类型的文件系统:

mount -t hugetlbfs \
	-o uid=<value>,gid=<value>,mode=<value>,pagesize=<value>,size=<value>,\
	min_size=<value>,nr_inodes=<value> none /mnt/huge

这个命令会在目录 /mnt/huge 上挂载一个(伪)hugetlbfs 类型的文件系统. 在 /mnt/huge 上创建的任何文件都将使用大页. uid 和 gid 选项用于设置文件系统根目录的所有者和组. 默认情况下, 会采用当前进程的 uid 和 gid. mode 选项用于将文件系统根目录的权限设置为指定的值(按八进制表示). 默认情况下, 选取的值是 0755. 如果平台支持多个大页大小, 可以使用 pagesize 选项指定大页的大小和相关池. pagesize 的单位是字节. 如果未指定 pagesize, 则将使用平台的默认大页大小和相关池. size 选项用于设置文件系统(/mnt/huge)允许的内存(大页)的最大值. size 选项可以以字节形式指定, 也可以指定为指定的大页池(nr_hugepages)的百分比. size 会向下舍入到 HPAGE_SIZE 边界. min_size 选项用于设置文件系统允许的内存(大页)的最小值. min_size 可以以与 size 相同的方式指定, 即字节或大页池的百分比. 在挂载时, min_size 指定的大页数量会被保留供文件系统使用. 如果没有足够的空闲大页可用, 挂载将失败. 随着大页分配给文件系统并被释放, 保留计数会调整, 以确保分配和保留的大页的总和始终至少达到 min_size. nr_inodes 选项设置 /mnt/huge 可以使用的最大 inode 数. 如果未提供 size、min_size 或 nr_inodes 选项, 则不设置任何限制. 对于 pagesize、size、min_size 和 nr_inodes 选项, 您可以使用 [G|g]/[M|m]/[K|k] 来表示千兆/兆/千. 例如, size=2K 具有与 size=2048 相同的含义.

尽管支持对存储在大页文件系统上的文件执行读取系统调用, 但不支持写入系统调用.

可以使用常规的 chown、chgrp 和 chmod 命令(具有正确权限)来更改 hugetlbfs 上的文件属性.

还要注意的是, 如果应用程序只使用 shmat/shmget 系统调用或 mmap 与 MAP_HUGETLB 标志, 那么无需执行挂载命令. 有关如何使用 mmap 与 MAP_HUGETLB 的示例, 请参阅下面的 “map_hugetlb” 部分.

希望通过共享内存段使用大页内存的用户应成为辅助组的成员, 系统管理员需要将该 gid 配置到 /proc/sys/vm/hugetlb_shm_group 中. 同一个或不同的应用程序可以使用 mmaps 和 shm* 调用的任何组合, 尽管在没有 MAP_HUGETLB 的情况下使用 mmap 调用将需要文件系统的挂载.

仅在由大页支持的内存上运行的系统调用的长度仅与处理器的本机页大小对齐. 如果长度小于大页大小, 它们通常会失败, 错误代码设置为 EINVAL, 或者排除延伸到长度之外的大页. 例如, 如果内存由大页支持并且长度小于大页大小, munmap(2) 将失败.

Examples

  1. map_hugetlb: see tools/testing/selftests/vm/map_hugetlb.c

  2. hugepage-shm: see tools/testing/selftests/vm/hugepage-shm.c

  3. hugepage-mmap: see tools/testing/selftests/vm/hugepage-mmap.c

  4. The libhugetlbfs (https://github.com/libhugetlbfs/libhugetlbfs) library
    provides a wide range of userspace tools to help with huge page usability,
    environment setup, and control.

Kernel development regression testing

libhugetlbfs 仓库包含了最全面的大页测试集. 如果您修改了与大页相关的任何代码, 请使用 libhugetlbfs 测试套件来检查是否存在回归问题. 此外, 如果您添加了任何新的大页功能, 请在 libhugetlbfs 中添加相应的测试用例.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值