一文图解|内存页面迁移技术

news2024/11/28 22:41:58

1. 概述

页面迁移(page migrate)最早是为 NUMA 系统提供一种将进程页面迁移到指定内存节点的能力用来提升访问性能。后来在内核中广泛被使用,如内存规整、CMA、内存hotplug等。

页面迁移对上层应用业务来说是不可感知的,因为其迁移的是物理页面,而应用只访问的是虚拟内存。内核迁移完成后,更新修改对应页表指向迁移后的页面即可。当然了这里说的不可感知是指业务不太关注,也不需要做对应修改。实际上有些场景发生页面迁移是业务性能是有影响的,下面会详细描述。

2. 典型场景

我们列举2个内核中发生页面迁移的典型场景。

2.1 NUMA Balancing引起的页面迁移

在典型 NUMA 中,存在多个 node, 本地 CPU 访问本地 node 节点对应的 memory 性能会快一些。

Linux 的 NUMA 自动均衡机制会尝试将内存迁移到正在访问它的 CPU 节点所在的 node。如下图所示, CPU24 ~ CPU47 访问不是本地 node 对应的 memory,性能会比较慢,系统会将其迁移到本地 node 对应的 memory 以提升访问性能。

迁移后如下图:

2.2 内存碎片整理

系统使用一段时候后,由于内存碎片的原因,较难满足连续内存需求,如果需要分配连续大块内存,需要进行内存规整以形成大块连续内存,页面迁移是内存碎片整理的基础。

3. 实现分析

3.1 迁移模式

内核中通过接口 migrate_pages 实现页而迁移, 分为3个模式。

3.2 实现流程

内核文档有描述这个API是怎么工作的。不过这个描述着实是不太友好, 不容易在脑海形成画面。

我们通过结合代码实现,把这个转化为流程图:

总结一下,页面迁移过程本质就是分配一个 new_page, 解除原有 page 映射,把旧 page 复制到新 page 并建立新 page 的映射。

  资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈

4. 页面迁移过程用户态访问处理

到这里可能会有疑问:如果在页面迁移过程中,应用发生发访问这个迁移中的页面,会发生什么?

  • 情景1: 旧页面的页表还未解映射, 此时发生缺页可以正常访问原来页面。

  • 情景2: 旧页面解除了映射,但新页面还未建立映射。这时访问会发生等待,需要等新页面建立映射并copy完成页面后才能访问。

  • 情景3: 完成了页面迁移动作,可以正常访问新页面了。

下面我们重点分析一下,当旧页面解除了映射,且新页面未建立映射这个过程中发生了用户态访问,内核的处理流程是怎样的。

首先我们看一下旧页面解除了映射的过程:

static bool try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
       unsigned long address, void *arg)
{
...  
  if (PageHWPoison(page) && !(flags & TTU_IGNORE_HWPOISON)) {

...
  } else if (pte_unused(pteval) && !userfaultfd_armed(vma)) {
...
  } else if (IS_ENABLED(CONFIG_MIGRATION) &&
    (flags & (TTU_MIGRATION|TTU_SPLIT_FREEZE))) { 
    // 页面迁移会设置TTU_MIGRATION标记,走到这个分支来
   swp_entry_t entry;
   pte_t swp_pte;

   if (arch_unmap_one(mm, vma, address, pteval) < 0) {
    set_pte_at(mm, address, pvmw.pte, pteval);
    ret = false;
    page_vma_mapped_walk_done(&pvmw);
    break;
   }

   /*
    * Store the pfn of the page in a special migration
    * pte. do_swap_page() will wait until the migration
    * pte is removed and then restart fault handling.
    */
    // 迁移中的页面, 生成了一个swap entry, 并写到PTE页表项中
    // 当再次发生缺页时会走进do_swap_page等待直到迁移完成.
   entry = make_migration_entry(subpage, pte_write(pteval));
   swp_pte = swp_entry_to_pte(entry);
   if (pte_soft_dirty(pteval))
    swp_pte = pte_swp_mksoft_dirty(swp_pte);
   if (pte_uffd_wp(pteval))
    swp_pte = pte_swp_mkuffd_wp(swp_pte);
    // 当设置了迁移标记的Swap entry到pte后, 这个旧页面就不能像原来那样的顺利被访问了
   set_pte_at(mm, address, pvmw.pte, swp_pte);
   /*
    * No need to invalidate here it will synchronize on
    * against the special swap migration pte.
    */
  } else if (PageAnon(page)) {
   swp_entry_t entry = { .val = page_private(subpage) };
   pte_t swp_pte;
   /*
    * Store the swap location in the pte.
    * See handle_pte_fault() ...
    */
   if (unlikely(PageSwapBacked(page) != PageSwapCache(page))) {
    WARN_ON_ONCE(1);
    ret = false;
    /* We have to invalidate as we cleared the pte */
    mmu_notifier_invalidate_range(mm, address, address + PAGE_SIZE);
    page_vma_mapped_walk_done(&pvmw);
    break;
   }
...
}

解除映射后,再次发生映射就走到 do_swap_page 中了。

vm_fault_t do_swap_page(struct vm_fault *vmf)
{
...
  // 获取到这是一个在迁移过程的的PTE的标识
 entry = pte_to_swp_entry(vmf->orig_pte);
 if (unlikely(non_swap_entry(entry))) {  // 不是传统的Swap entry
  if (is_migration_entry(entry)) {      // 是迁移标记进来的
     /* 等待migration的完成。本质是在等待旧page释放其page lock
      * 最终调用到 wait_on_page_bit_common
      */
   migration_entry_wait(vma->vm_mm, vmf->pmd, vmf->address);
  } 
...
}

总结一下:

页面迁移前,首先会获取旧页面和新页面的页面锁 PG_lock,在解除映射的时候传入了由于页面迁移导致的解映射标记 TTU_MIGRATION,设置了此标记会生成一个带页面迁移标识的 swap_entry 设置到 pte 中。在设置好的那一刻走,应用进程无法很顺利地访问这个页面了,需要通过 do_swap_entry 路径。

假如此时应用进程访问了这个页面,会走进到 do_swap_entry,取出带迁移标识的 swap_entry,识别到这个标识,会等待页面锁释放。页面锁只有在页面迁移完成后才会被释放,也就是会发生等待直到页面迁移完成。

5. 用户态如何避免发生页面迁移

上面我们已经知道,如果有页面迁移过程中发生用户态访问,很可能是需要发生等待其迁移完成, 这个过程需要一定耗时。而有时的场景我们是需要避免此种时延抖动,那有什么办法呢?

方法就是让这个页面短时间内变得不可移动。

int migrate_page_move_mapping(struct address_space *mapping,
  struct page *newpage, struct page *page, int extra_count)
{
...
  if (page_count(page) != expected_count) 
   return -EAGAIN;
...
 return MIGRATEPAGE_SUCCESS;
}

可以看到当发生页面复制过程中,如果 page 的引用计数不符合预期(期望为0)时,这时系统认为有人在使用,不适用做迁移。那么,我们只需要增加 page 的引用计数就可以。

可以在不想被迁移的时间段开始前通过 pin_user_pages 这样的接口,结束时 unpin 就可以了。接口最终会调到 try_grab_page 增加引用计数。

bool __must_check try_grab_page(struct page *page, unsigned int flags)
{
...
   refs = GUP_PIN_COUNTING_BIAS; // #define GUP_PIN_COUNTING_BIAS (1U << 10)
   page_ref_add(page, refs);
  }

  return true;
}

原文作者:五花肉

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1028306.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【无标题】同创永益王澍│新环境下数字韧性建设探讨

2023年9月7日&#xff0c;由同创永益主办的2023数字韧性保险峰会在上海成功举办。ITSS DCMG组长肖建一等数十位保险行业专家、企业代表出席本次会议&#xff0c;同创永益与多方共同探讨保险行业数字化发展与数字韧性体系建设&#xff0c;共话行业数智化未来。 会上&#xff0c…

贵阳RapidSSL的ssl证书适合个人网站吗

现在很多开发者不论是为了记录还是宣传&#xff0c;很多人都会创建一个属于自己的网站&#xff0c;而有了自己的网站&#xff0c;为了保护网站信息安全以及防止网站数据被篡改与劫持&#xff0c;就需要为网站安装SSL证书。那么RapidSSL的SSL证书个人开发者可以使用吗&#xff1…

Windows Server 2008安装.NET Framework 3.5

安装.NET Framework 3.5一、打开服务器管理器 在开始菜单中搜索“服务器管理器” 二、添加.NET Framework 3.5.1功能 &#xff08;一&#xff09;功能-》添加功能 &#xff08;二&#xff09;选择功能“.NET Framework 3.51” 1.点击“NET Framework 3.5.1”勾选框 2.点击“添…

python教程:内置函数和语法糖触发魔法方法

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 如果有什么疑惑/资料需要的可以点击文章末尾名片领取源码 下面总结python内置函数对应的魔法方法 魔法方法 数学计算 abs(args):返回绝对值&#xff0c;调用__abs__; round(args):返回四舍五入的值&#xff0c;调用__roun…

GPIO基础知识的概括

GPIO 是通用输入/输出端口的简称&#xff0c;本文以STM32为例进行说明&#xff0c;其他的单片机功能上都是大同小异&#xff0c;学会STM32的GPIO&#xff0c;我们可以触类旁通。 GPIO 的引脚与外部硬件设备连接&#xff0c;可实现与外部通讯、控制外部硬件或者采集外部硬件数据…

CMS之织梦导航二级下拉菜单

操作步骤 1、首先&#xff1a; 将下面这段代码贴到templets\default\footer.htm文件里&#xff08;只要在此文件里就行&#xff0c;位置无所谓啦&#xff01;自己看着办&#xff01;&#xff09; <!-- //二级子类下拉菜单&#xff0c;考虑SEO原因放置于底部 --><scr…

最大限度节省采购成本的七种方法

当前经济环境下&#xff0c;降低成本比以往任何时候都更受到企业的重视。降低成本通常是指在采购过程中节省的成本&#xff0c;但其实远不止于此。它还包括通过重新谈判合同条款和条件、改进管理和运营流程&#xff0c;以及数据和技术的智能使用而节省的成本。 节省采购成本的…

提升技术招聘有效性| 杜绝候选人刷题应试

企业在技术人员招聘中&#xff0c;时常出现候选人“笔试考高分&#xff0c;工作写Bug&#xff0c;绩效来垫底”的尴尬窘境&#xff0c;让企业倍感煎熬。不仅浪费时间精力、也增大招人的成本投入。 如何招到真正合适的技术人选&#xff0c;成为摆在企业心头的难题。 合适的技术…

Vue中的生命周期钩子

生命周期钩子 :::warning 注意 所有生命周期钩子的 this 上下文将自动绑定至实例中&#xff0c;因此你可以利用 this 访问 props、data、computed 和 methods 等选项内的数据/函数。这意味着你不应该使用箭头函数来定义一个生命周期方法&#xff0c;因为箭头函数中没有 this&a…

基于Kintex UltraScale系列FPGA KU060/KU115高性能PCIe数据预处理载板(5GByte/s带宽)

PCIE702是一款基于PCIE总线架构的高性能数据预处理FMC载板&#xff0c;板卡具有1个FMC&#xff08;HPC&#xff09;接口&#xff0c;1路PCIe x8主机接口、1个RJ45千兆以太网口、2个QSFP 40G光纤接口。板卡采用Xilinx的高性能Kintex UltraScale系列FPGA作为实时处理器&#xff0…

vuex实现简易购物车加购效果

目录 一、加购效果动图二、前提条件三、开始操作四、解决vuex刷新数据丢失问题五、最终效果 一、加购效果动图 二、前提条件 创建了vue项目&#xff0c;安装了vuex 三、开始操作 目录结构如下&#xff1a; main.js文件中引入store: import Vue from vue import App from ./…

星戈瑞Cyanine7-COOH在生物学和医学中的应用 CY7-COOH

Cyanine7-COOH作为一种近红外荧光染料&#xff0c;在生物学和医学领域应用。以下是一些Cyanine7-COOH在这些领域中可能的应用&#xff1a; 生物荧光成像&#xff1a; Cyanine7-COOH可以用于细胞和组织的荧光成像&#xff0c;特别是在近红外范围内。这个波长范围的荧光信号穿透…

分布式链路追踪系统zipkin【杭州多测师_王sir】

一、部署zipkin环境的方式 》1.docker 2、java -jar 3、运行源码 二、分别可以在Linux系统和Windows系统里面运行zipkin 三、在地址栏输入&#xff1a;http://127.0.0.1:9411 四、zipkin的流程图 由上图可以看出&#xff0c;应用的代码(User Code)发起 Http Get 请求(请…

Unity丨移动相机朝向目标并确定目标在摄像机可视范围内丨摄像机注释模型丨摄像机移动丨不同尺寸模型优化丨

文章目录 问题描述功能展示技术细节小结 问题描述 本文提供的功能是摄像机朝向目标移动&#xff0c;并确定整个目标出现在摄像机视角内&#xff0c;针对不同尺寸的模型优化。 功能展示 提示&#xff1a;这里可以添加技术名词解释 技术细节 直接上代码 using UnityEngine;…

阿里云产品试用系列-函数计算 FC

函数计算&#xff08;Function Compute&#xff09;是一个事件驱动的全托管 Serverless 计算服务&#xff0c;您无需管理服务器等基础设施&#xff0c;只需编写代码并上传&#xff0c;函数计算会为您准备好计算资源&#xff0c;并以弹性、可靠的方式运行您的代码。 如上所示&am…

Selenium 4.11 正式发布--再也不用手动更新chrome driver 了

Selenium 4.11.0 正式发布了&#xff0c;先来看一下主要特性。 Chrome DevTools支持的版本现在是&#xff1a;v113、v114和v115&#xff08;Firefox仍然对所有版本使用v85&#xff09; 通过Selenium Manager支持Chrome For Testing&#xff08;CfT&#xff09; Selenium Manag…

网络基础 (深信服)

一 走进网络世界 1.1.1 企业网络环境介绍 计算机网络类型&#xff1a; LAN ------本地局域网 Local Area Network&#xff1a; •通常指几千米以内的&#xff0c;可通过某种介质互联的计算机、打印机、modem或其他设备的集合 WAN ------ 广 域 网 Wide Area Network&am…

ClickHouse分布式集群部署

目录 ​编辑 一、环境说明 二、安装部署 2.1 RPM方式安装 2.1.1 安装yum-utils 2.1.2 配置yum repo源 2.1.3 yum install 下载安装clickhouse 2.2 信息配置 2.2.1 配置外网可访问地址 2.2.2 修改存储路径 2.2.2.1 新建存储目录 2.2.2.2 授权 2.2.2.3 修改配置 2.…

Tomcat的启动问题

今天去打开Tomcat的时候没反应 如下 按之前是到Tomcat目录下的bin目录下的startup.bat文件&#xff0c;双击&#xff0c;就可以启动Tomcat服务器。启动后可以 打开浏览器&#xff0c;在浏览器地址栏中输入以下地址测试&#xff1a; 1、http://localhost:8080 2、http://127.…

手撕 LFU 缓存

大家好&#xff0c;我是 方圆。LFU 的缩写是 Least Frequently Used&#xff0c;简单理解则是将使用最少的元素移除&#xff0c;如果存在多个使用次数最小的元素&#xff0c;那么则需要移除最近不被使用的元素。LFU 缓存在 LeetCode 上是一道困难的题目&#xff0c;实现起来并不…