Linux下使用HugePage减少TLB-Miss,以及使用HugePage创建共享内存

个人作品,禁止转载

概述

TLB miss是导致程序内存访问延迟的一大原因。特别是使用大量内存时TLB会变得异常拥挤。一个常见的TLB miss导致的内存延迟的现象是:访问一个连续数组,每4KB出现一次较大的访问延迟。

因此使用HugePage(巨页)能够改善内存访问延迟。

本文主要介绍在共享内存IPC场景下使用HugePage的方法。单进程访问内存的方式会更简单。

HugePage的内核支持

see also:https://docs.kernel.org/admin-guide/mm/hugetlbpage.html

内核支持两种HugePage使用方式:Transparent Huge Pages 和 Explicit huge pages

see also:https://stackoverflow.com/questions/64913818/hugepages-on-raspberry-pi-4/64914391#64914391

Transparent Huge Pages由操作系统管理,允许用户将已经mmap的地址转换为HugePage,也允许系统层面使用HugePage,可以将所有内存申请自动映射到HugePage上,无需修改代码。

Explicit huge pages允许用户控制HugePage的分配、使用和销毁。

在系统中预留HugePage

关于如何在启动阶段或者启动后创建HugePage,参考https://docs.kernel.org/admin-guide/mm/hugetlbpage.html

使用HugePage backed Shared Memory

x64架构支持两种巨页大小:2M和1G
假设用户已经使用

mount -t hugetlbfs none /mnt/hugetlbfs_1G -o pagesize=1G
mount -t hugetlbfs none /mnt/hugetlbfs_2M -o pagesize=2M

将hugetlbfs挂载到/mnt目录下,并授予了当前用户读写权限

创建巨页文件,并映射到共享内存

现在hugetlbfs中创建一个文件,并truncate到巨页的大小

int fd = open(("/mnt/hugetlbfs_2M/test" + to_string(num)).c_str(), O_CREAT | O_RDWR | O_TRUNC, 0766);
if (fd == -1) {
    perror("open");
    exit(-1);
}
ftruncate(fd, 2UL * 1024 * 1024);

这个文件会存放在巨页内存中,该内存大小为2M

下面将文件映射到进程的地址空间

void* addr = mmap(nullptr, FSize, PROT_READ | PROT_WRITE,
                      MAP_SHARED | MAP_HUGETLB, fd, 0);
if (addr == MAP_FAILED){
    perror("mmap");
    exit(-1);
}

然后就可以使用addr访问巨页了

创建1GB的巨页,也相同。

完整代码

#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
using namespace std;

static const size_t FSize = 2UL * 1024 * 1024;
int map_file()
{
    // create file under hugetlbfs
    int fd = open(("/mnt/hugetlbfs_2M/test" + to_string(1)).c_str(), O_CREAT | O_RDWR | O_TRUNC, 0766);
    if (fd == -1) {
        perror("open");
        exit(-1);
    }
    ftruncate(fd, FSize);
    void* addr = mmap(nullptr, FSize, PROT_READ | PROT_WRITE,
                      MAP_SHARED | MAP_HUGETLB, fd, 0);
    if (addr == MAP_FAILED){
        perror("mmap");
        exit(-1);
    }

    int* arr = (int*)addr;
    for (size_t i=0; i<FSize/sizeof(int); i++)
        arr[i] = i;
    munmap(addr, FSize);
    return 0;
}

int main(){
     map_file();
}

运行一次改代码之后,在命令行运行
cat /proc/meminfo | grep Huge
会输出

AnonHugePages:         0 kB
ShmemHugePages:        0 kB
FileHugePages:         0 kB
HugePages_Total:    1024
HugePages_Free:     1023
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:         4194304 kB

即一个2M的巨页已经被使用。

然后运行rm -f /mnt/hugetlbfs_2M/*
再度运行cat /proc/meminfo | grep Huge
会输出

AnonHugePages:         0 kB
ShmemHugePages:        0 kB
FileHugePages:         0 kB
HugePages_Total:    1024
HugePages_Free:     1024
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:         4194304 kB

2M HugePage已经被删除(巨页内存被释放)

巨页内存耗尽

如果一直在hugetlbfs中创建巨页,却不删除文件(即释放内存),会将巨页耗尽。
如下代码模拟了这种场景(系统中预留1024个2M巨页)

#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
using namespace std;

static const size_t FSize = 2UL * 1024 * 1024;
int map_file(int num)
{
    cout << "call for " << num << " times" << endl;
    // create file under hugetlbfs
    int fd = open(("/mnt/hugetlbfs_2M/test" + to_string(num)).c_str(), O_CREAT | O_RDWR | O_TRUNC, 0766);
    if (fd == -1) {
        perror("open");
        exit(-1);
    }
    ftruncate(fd, FSize);
    void* addr = mmap(nullptr, FSize, PROT_READ | PROT_WRITE,
                      MAP_SHARED | MAP_HUGETLB, fd, 0);
    if (addr == MAP_FAILED){
        perror("mmap");
        exit(-1);
    }

    int* arr = (int*)addr;
    for (size_t i=0; i<FSize/sizeof(int); i++)
        arr[i] = i % 26 + 'a';
    munmap(addr, FSize);
    return 0;
}

int main(){
    for (int i=0; ; i++)
        map_file(i);
}

程序输出为

call for 0 times
call for 1 times
......
call for 1021 times
call for 1022 times
call for 1023 times
call for 1024 times
mmap: Cannot allocate memory

Process finished with exit code 255
<think>好的,用户现在问的是华为昇腾中的“Hugepages-Usage(page)”的含义。首先,我需要确认用户的使用场景。可能他们在使用华为的昇腾处理器进行深度学习或者高性能计算时,遇到了关于内存管理的问题,或者是在监控系统性能时看到了这个指标,想要了解其具体含义和作用。 接下来,用户身份可能是一位开发人员、系统管理员,或者是从事AI模型训练的工程师。他们对系统底层的内存管理机制可能有一定的了解,但需要更具体的解释,特别是与昇腾处理器相关的部分。 用户的直接需求是明确“Hugepages-Usage(page)”这个术语的定义,但深层需求可能包括了解如何优化昇腾处理器的性能,或者解决与大页内存相关的配置问题。可能他们在实际应用中遇到了内存使用效率的问题,或者想要通过调整Hugepages来提升计算任务的效率。 我需要先解释Hugepages的基本概念,然后联系到昇腾处理器中的具体应用。Hugepages是Linux中的一种内存管理机制,使用更大的内存页来减少页表项的数量,提升TLB命中率,从而优化内存访问性能。这对于需要处理大量数据的AI计算尤其重要,因为频繁的内存访问会成为性能瓶颈。 然后,需要具体说明“Hugepages-Usage(page)”在昇腾中的含义。这可能指的是昇腾处理器或相关软件栈(如Ascend CANN)对大页内存的使用情况,通常以页面数量为单位。需要解释这个指标监控的是已分配的大页内存页数,帮助用户评估资源使用情况,预防内存不足的问题。 此外,用户可能想知道如何配置和监控Hugepages,所以需要提供一些相关的命令和配置方法,比如查看Hugepages状态的命令,配置大页内存的步骤,以及如何检查昇腾是否成功使用了大页内存。 还需要考虑用户可能的误区,比如大页内存虽然提升性能,但可能会增加内存碎片化,或者配置不当导致资源浪费。因此,在注意事项中需要提到合理分配大页内存,避免过量,以及结合应用需求进行调整。 最后,总结Hugepages在昇腾中的作用,强调其对性能优化的重要性,并引导用户根据实际需求进行配置和监控。确保回答结构清晰,逐步深入,覆盖基本概念、具体含义、配置方法和注意事项,满足用户的多层次需求。</think>### 华为昇腾 Hugepages-Usage(page) 详解 --- #### 1. **基本概念** **Hugepages**(大页内存)是 Linux 操作系统中的一种**内存管理机制**,通过使用比标准内存页(通常 4KB)更大的内存块(如 2MB 或 1GB),减少页表项数量,提升 **TLB(Translation Lookaside Buffer)缓存命中率**,从而优化**内存密集型应用性能**。 --- #### 2. **昇腾场景中的意义** 在华为昇腾(Ascend)AI 处理器场景中,**Hugepages-Usage(page)** 表示**昇腾计算任务实际占用的大页内存页数量**。 - **关键作用**: - 加速昇腾芯片与主机内存的数据传输(例如:模型权重、输入数据) - 减少内存访问延迟,提升 NPU(Neural Processing Unit)计算效率 - 避免频繁的页表切换,降低系统开销 --- #### 3. **技术细节** | 指标特征 | 说明 | |-----------------|----------------------------------------------------------------------| | **统计单位** | 以**页面数量**(page)为单位,例如:`Hugepages-Usage(page): 1024` | | **监控对象** | 昇腾驱动(如 `Ascend CANN`)或应用程序显式申请的大页内存 | | **关联配置** | 需提前在系统中配置大页内存池(通过 `/proc/sys/vm/nr_hugepages` 设置)| --- #### 4. **典型场景** - **模型训练**:大模型(如 ResNet-50、BERT)的权重数据加载到 Hugepages - **推理加速**:减少推理过程中内存与 NPU 之间的数据传输延迟 - **多任务并发**:多个昇腾任务共享大页内存池时,监控资源占用情况 --- #### 5. **操作指南** ##### (1) 查看 Hugepages 状态 ```bash # 查看系统大页内存总量与使用量(单位:页) cat /proc/meminfo | grep HugePages # 昇腾专用命令(需安装 CANN 工具包) npu-smi info -t memory -i 0 # 显示指定 NPU 的内存使用详情 ``` ##### (2) 配置 Hugepages ```bash # 临时分配 1024 个 2MB 大页(重启失效) echo 1024 > /proc/sys/vm/nr_hugepages # 永久生效(在 /etc/sysctl.conf 中添加) vm.nr_hugepages = 1024 sysctl -p # 立即生效 ``` ##### (3) 检查昇腾是否使用 Hugepages ```bash # 查看进程映射的大页内存(过滤昇腾相关进程) grep -B 10 Huge /proc/<昇腾进程PID>/smaps ``` --- #### 6. **注意事项** - **合理分配**:大页内存会锁定物理内存,过量分配可能导致其他应用内存不足 - **性能权衡**:大页内存减少 TLB Miss,但可能增加内存碎片化风险 - **昇腾适配**:需使用支持 Hugepages 的驱动版本(建议 ≥ CANN 5.0) --- #### 7. **总结** **Hugepages-Usage(page)** 是昇腾计算任务中**衡量大页内存资源占用**的核心指标,直接影响 AI 计算效率。通过合理配置和监控,可显著提升昇腾芯片在训练/推理任务中的性能表现。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值