1 linux linux-kernel huge-pages armv8 raspberry-pi4
我需要有关在运行树莓派操作系统 64 位的树莓派 4 上管理大页的帮助。
我在网上没有找到太多可靠的信息。
首先我重新编译了内核源启用Memory Management options --->Transparent Hugepage Support选项。当我运行命令时:
grep -i huge /proc/meminfo
输出是:
AnonHugePages: 319488 kB
ShmemHugePages: 0 kB
FileHugePages: 0 k
Run Code Online (Sandbox Code Playgroud)
并运行命令:
cat /sys/kernel/mm/transparent_hugepage/enabled
Run Code Online (Sandbox Code Playgroud)
输出是:
[always] madvise never
Run Code Online (Sandbox Code Playgroud)
所以我认为应该设置透明大页(AnonHugePages)。我需要使用 HugePages 使用 mmap 函数、c 代码来映射最大的连续内存块。
mem = mmap(NULL,buf_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
Run Code Online (Sandbox Code Playgroud)
查看https://www.man7.org/linux/man-pages/man2/mmap.2.html有两个标志来管理大页:MAP_HUGETLB 标志和 MAP_HUGE_2MB、MAP_HUGE_1GB 标志。
我的问题是:要使用 HugePages,我应该以这种方式映射吗?
mem = mmap(NULL,buf_size,PROT_READ|PROT_WRITE,MAP_SHARED,MAP_HUGETLB,fd,0);
Run Code Online (Sandbox Code Playgroud)
内核配置:
CONFIG_SYS_SUPPORTS_HUGETLBFS=y
CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y
CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
CONFIG_HAVE_ARCH_HUGE_VMAP=y
CONFIG_TRANSPARENT_HUGEPAGE=y
CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
# CONFIG_TRANSPARENT_HUGEPAGE_MADVISE is not set
CONFIG_TRANSPARENT_HUGE_PAGECACHE=y
# CONFIG_HUGETLBFS is not set
Run Code Online (Sandbox Code Playgroud)
大页面是通过减少 TLB 未命中次数来增强应用程序性能的一种方法。该机制将连续的标准物理页(典型大小为 4 KB)合并为一个大页(例如 2 MB)。Linux 以两种方式实现此功能:透明大页和显式大页。
透明大页 (THP) 由内核透明地管理。用户空间应用程序无法控制它们。内核会尽可能地分配大页面,但不能保证。此外,THP 可能会引入开销,因为名为khugepaged的底层“垃圾收集器”内核守护进程负责合并物理页以生成大页。这可能会消耗 CPU 时间,并对正在运行的应用程序的性能产生不良影响。在具有时间关键应用程序的系统中,通常建议停用 THP。
可以在引导命令行(参见本答案的末尾)或从sysfs中的 shell 中禁用 THP :
$ cat /sys/kernel/mm/transparent_hugepage/enabled
always [madvise] never
$ sudo sh -c "echo never > /sys/kernel/mm/transparent_hugepage/enabled"
$ cat /sys/kernel/mm/transparent_hugepage/enabled
always madvise [never]
Run Code Online (Sandbox Code Playgroud)
注意:关于 THP 的绩效评估/问题,存在一些有趣的论文:
如果应用程序级别需要大页面(即来自用户空间)。必须设置HUGETLBFS内核配置才能激活Hugetlbfs伪文件系统(内核配置器中的菜单类似于:“文件系统”-->“伪文件系统”-->“HugeTLB 文件系统支持”)。在内核源代码树中,该参数位于fs/Kconfig中:
config HUGETLBFS
bool "HugeTLB file system support"
depends on X86 || IA64 || SPARC64 || (S390 && 64BIT) || \
SYS_SUPPORTS_HUGETLBFS || BROKEN
help
hugetlbfs is a filesystem backing for HugeTLB pages, based on
ramfs. For architectures that support it, say Y here and read
<file:Documentation/admin-guide/mm/hugetlbpage.rst> for details.
If unsure, say N.
Run Code Online (Sandbox Code Playgroud)
例如,在 Ubuntu 系统上,我们可以检查:
$ cat /sys/kernel/mm/transparent_hugepage/enabled
always [madvise] never
$ sudo sh -c "echo never > /sys/kernel/mm/transparent_hugepage/enabled"
$ cat /sys/kernel/mm/transparent_hugepage/enabled
always madvise [never]
Run Code Online (Sandbox Code Playgroud)
注意:在 Raspberry Pi 上,可以配置/proc/config.gz的幽灵,并使用zcat执行相同的操作来检查参数。为此,配置菜单为:“常规设置”-->“内核 .config 支持”+“通过 /proc/config.gz 启用对 .config 的访问”
设置此参数后,hugetlbfs伪文件系统将添加到内核构建中(参见fs/Makefile):
obj-$(CONFIG_HUGETLBFS) += hugetlbfs/
Run Code Online (Sandbox Code Playgroud)
Hugetlbfs的源代码位于fs/hugetlbfs/inode.c。启动时,内核将安装内部hugetlbfs文件系统以支持其运行的体系结构的所有可用大页面大小:
config HUGETLBFS
bool "HugeTLB file system support"
depends on X86 || IA64 || SPARC64 || (S390 && 64BIT) || \
SYS_SUPPORTS_HUGETLBFS || BROKEN
help
hugetlbfs is a filesystem backing for HugeTLB pages, based on
ramfs. For architectures that support it, say Y here and read
<file:Documentation/admin-guide/mm/hugetlbpage.rst> for details.
If unsure, say N.
Run Code Online (Sandbox Code Playgroud)
Hugetlbfs文件系统是一种 RAM 文件系统,内核在其中创建文件来支持应用程序映射的内存区域。
可以通过将需要的大页数量写入/sys/kernel/mm/hugepages/hugepages- hugepagesize /nr_hugepages来保留所需的大页数量。
然后,mmap()能够将应用程序地址空间的某些部分映射到大页上。下面是一个示例,展示了如何执行此操作:
$ cat /boot/config-5.4.0-53-generic | grep HUGETLBFS
CONFIG_HUGETLBFS=y
Run Code Online (Sandbox Code Playgroud)
在上面的程序中, addr指向的内存是基于大页的。使用示例:
$ gcc alloc_hp.c -o alloc_hp
$ ./alloc_hp
mmap(): Cannot allocate memory
$ cat /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
0
$ sudo sh -c "echo 1 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages"
$ cat /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
1
$ ./alloc_hp
Mapping located at address: 0x7f7ef6c00000
Run Code Online (Sandbox Code Playgroud)
在另一个终端中,可以观察进程图来验证内存页的大小(它在pause()系统调用中被阻塞):
$ pidof alloc_hp
13009
$ cat /proc/13009/smaps
[...]
7f7ef6c00000-7f7ef6e00000 rw-s 00000000 00:0f 331939 /anon_hugepage (deleted)
Size: 2048 kB
KernelPageSize: 2048 kB <----- The page size is 2MB
MMUPageSize: 2048 kB
[...]
Run Code Online (Sandbox Code Playgroud)
在前面的图中,大页区域的文件名/anon_hugepage是由内核内部创建的。它被标记为已删除,因为内核删除了关联的内存文件,一旦不再有对该文件的引用,该文件就会消失(例如,当调用进程结束时,底层文件在 exit() 时关闭,引用计数器在文件降至 0,删除操作完成使其消失)。
在 Raspberry Pi 4B 上,默认大页面大小为 2MB,但该卡支持其他几种大页面大小:
$ ls -l /sys/kernel/mm/hugepages
total 0
drwxr-xr-x 2 root root 0 Nov 23 14:58 hugepages-1048576kB
drwxr-xr-x 2 root root 0 Nov 23 14:58 hugepages-2048kB
drwxr-xr-x 2 root root 0 Nov 23 14:58 hugepages-32768kB
drwxr-xr-x 2 root root 0 Nov 23 14:58 hugepages-64kB
Run Code Online (Sandbox Code Playgroud)
要使用它们,需要安装与所需大页面大小相对应的hugetlbfs类型文件系统。内核文档提供了有关可用安装选项的详细信息。例如,要在/mnt/huge上挂载一个具有 8 个大小为 64KB 的大页的Hugetlbfs文件系统,命令为:
mount -t hugetlbfs -o pagesize=64K,size=512K,min_size=512K none /mnt/huge
Run Code Online (Sandbox Code Playgroud)
那么就可以在用户程序中映射64KB的大页了。以下程序创建/tmp/hpfs目录,在该目录上挂载大小为 4 个 64KB 大页的Hugetlbfs文件系统。创建名为 /memfile_01 的文件并将其扩展为 2 个大页面的大小。由于mmap()系统调用,该文件被映射到内存中。它不会传递MAP_HUGETLB标志,因为提供的文件描述符适用于在hugetlbfs文件系统上创建的文件。然后,程序调用pause()来暂停执行,以便在另一个终端中进行一些观察:
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <fcntl.h>
#define ERR(fmt, ...) do { \
fprintf(stderr, \
"ERROR@%s#%d: "fmt, \
__FUNCTION__, __LINE__, ## __VA_ARGS__); \
} while(0)
#define HP_SIZE (64 * 1024)
#define HPFS_DIR "/tmp/hpfs"
#define HPFS_SIZE (4 * HP_SIZE)
int main(void)
{
void *addr;
char cmd[256];
int status;
int rc;
char mount_opts[256];
int fd;
rc = mkdir(HPFS_DIR, 0777);
if (0 != rc && EEXIST != errno) {
ERR("mkdir(): %m (%d)\n", errno);
return 1;
}
snprintf(mount_opts, sizeof(mount_opts), "pagesize=%d,size=%d,min_size=%d", HP_SIZE, 2*HP_SIZE, HP_SIZE);
rc = mount("none", HPFS_DIR, "hugetlbfs", 0, mount_opts);
if (0 != rc) {
ERR("mount(): %m (%d)\n", errno);
return 1;
}
fd = open(HPFS_DIR"/memfile_01", O_RDWR|O_CREAT, 0777);
if (fd < 0) {
ERR("open(%s): %m (%d)\n", "memfile_01", errno);
return 1;
}
rc = ftruncate(fd, 2 * HP_SIZE);
if (0 != rc) {
ERR("ftruncate(): %m (%d)\n", errno);
return 1;
}
addr = mmap(NULL, 2 * HP_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
if (MAP_FAILED == addr) {
ERR("mmap(): %m (%d)\n", errno);
return 1;
}
// The file can be closed
rc = close(fd);
if (0 != rc) {
ERR("close(%d): %m (%d)\n", fd, errno);
return 1;
}
pause();
return 0;
} // main
Run Code Online (Sandbox Code Playgroud)
前面的程序在调用mount()时必须以 root 身份运行:
$ gcc mount_tlbfs.c -o mount_tlbfs
$ cat /sys/kernel/mm/hugepages/hugepages-64kB/nr_hugepages
0
$ sudo sh -c "echo 8 > /sys/kernel/mm/hugepages/hugepages-64kB/nr_hugepages"
$ cat /sys/kernel/mm/hugepages/hugepages-64kB/nr_hugepages
8
$ sudo ./mount_tlbfs
Run Code Online (Sandbox Code Playgroud)
在另一个终端中,可以显示/proc/[pid]/smaps文件来检查大页分配。一旦程序写入大页,惰性分配机制就会触发大页的有效分配。
比照。本文为未来的详细信息
大页是由连续的物理内存页组成的。预留应该在系统启动的早期完成(尤其是在重负载的系统上),因为物理内存可能会碎片化,以至于有时无法在之后分配大页面。要尽早保留,可以在内核引导命令行上完成此操作:
hugepages=
[HW] Number of HugeTLB pages to allocate at boot.
If this follows hugepagesz (below), it specifies
the number of pages of hugepagesz to be allocated.
If this is the first HugeTLB parameter on the command
line, it specifies the number of pages to allocate for
the default huge page size. See also
Documentation/admin-guide/mm/hugetlbpage.rst.
Format: <integer>
hugepagesz=
[HW] The size of the HugeTLB pages. This is used in
conjunction with hugepages (above) to allocate huge
pages of a specific size at boot. The pair
hugepagesz=X hugepages=Y can be specified once for
each supported huge page size. Huge page sizes are
architecture dependent. See also
Documentation/admin-guide/mm/hugetlbpage.rst.
Format: size[KMG]
transparent_hugepage=
[KNL]
Format: [always|madvise|never]
Can be used to control the default behavior of the system
with respect to transparent hugepages.
See Documentation/admin-guide/mm/transhuge.rst
for more details.
Run Code Online (Sandbox Code Playgroud)
在 Raspberry Pi 上,引导命令行通常可以在/boot/cmdline.txt中更新,并且正在运行的内核使用的当前引导命令行可以在/proc/cmdline中看到。
注意:
| 归档时间: |
|
| 查看次数: |
4488 次 |
| 最近记录: |