Linux 内核page migration设计文档

news2024/12/25 12:31:19

概述

page migration设计之初是在numa system的各个node之间迁移physical pages,意味着进程页面的虚拟地址不会变化,物理地址发生改变,migration的目的将page迁移到临近的cpu上降低内存访问延迟。

页面迁移粗略步骤

A. In kernel use of migrate_pages()
-----------------------------------

1. Remove pages from the LRU.

   Lists of pages to be migrated are generated by scanning over
   pages and moving them into lists. This is done by
   calling isolate_lru_page().
   Calling isolate_lru_page increases the references to the page
   so that it cannot vanish while the page migration occurs.
   It also prevents the swapper or other scans to encounter
   the page.

2. We need to have a function of type new_page_t that can be
   passed to migrate_pages(). This function should figure out
   how to allocate the correct new page given the old page.

3. The migrate_pages() function is called which attempts
   to do the migration. It will call the function to allocate
   the new page for each page that is considered for
   moving.

1. 将页面从LRU列表移除。

使用isolate_lru_page将一批pages从LRU中隔离出来,同时会增加page->_refcount引用计数,避免迁移过程中被回收或者swap-out换出。

2. 使用一个函数找到一个空闲的页面当作迁移目的地。

3. migrate_pages函数实现迁移逻辑。

 

Non-LRU page migration

具体参考内核:bda807d4445414e8e77da704f116bb0880fe0c76 这个提交

尽管migration最开始是numa系统降低内存访问延迟,随着内核发展,申请high-order时候触发的memory compaction也是migration重要使用者。当前migration设计的存在一个挺严重的问题:只能迁移LRU列表中的Page。但是万事都有例外,比如某些内核,某些内核申请的pages还是可以迁移的,比如zsmalloc, virtio-balloon pages。

为了解决上面的问题,driver需要一种方式告诉kernel说,是可以迁移Non-LRU page的。高速内存的方式就是定义三个函数:


1. bool (*isolate_page) (struct page *page, isolate_mode_t mode);

What VM expects on isolate_page function of driver is to return *true*
if driver isolates page successfully. On returing true, VM marks the page
as PG_isolated so concurrent isolation in several CPUs skip the page
for isolation. If a driver cannot isolate the page, it should return *false*.

Once page is successfully isolated, VM uses page.lru fields so driver
shouldn't expect to preserve values in that fields.

2. int (*migratepage) (struct address_space *mapping,
        struct page *newpage, struct page *oldpage, enum migrate_mode);

After isolation, VM calls migratepage of driver with isolated page.
The function of migratepage is to move content of the old page to new page
and set up fields of struct page newpage. Keep in mind that you should
indicate to the VM the oldpage is no longer movable via __ClearPageMovable()
under page_lock if you migrated the oldpage successfully and returns
MIGRATEPAGE_SUCCESS. If driver cannot migrate the page at the moment, driver
can return -EAGAIN. On -EAGAIN, VM will retry page migration in a short time
because VM interprets -EAGAIN as "temporal migration failure". On returning
any error except -EAGAIN, VM will give up the page migration without retrying
in this time.

Driver shouldn't touch page.lru field VM using in the functions.

3. void (*putback_page)(struct page *);

If migration fails on isolated page, VM should return the isolated page
to the driver so VM calls driver's putback_page with migration failed page.
In this function, driver should put the isolated page back to the own data
structure.

non-lru movable page flags

对于这种non-lru的pages有个重要的问题是:内核怎么知道non-lru pages是否movable?因为linux struct page的flags成员并没有一个PG_movable的标志,所以这种方式行不通,需要另辟蹊径,让driver主动告诉kernel,使用如下函数:

 linux复用了page->mapping的最低两位,在内核里面page->mapping不仅可以用于标识non-lru page的movable特性,anon page也有在使用:

 为什么anon page要在低两位增加PAGE_MAPPING_ANON呢?如上面代码anon page的mapping字段实际指向的是一个anon_vma结构,又因为mapping字段的类型是address_space,所以上面强转伪装成了address_space,这么一伪装就把kernel欺骗了,如果不适用额外的手段,kernel无法知道page->mapping到底是anon_vma,还是address_space了!!!,所以对于Anon page也复用mapping的低两位,用于区分这两种情况,内核注释如下:

 内核这么处理就可以通过page->mapping的判定是否是Anone page,正如上面的PageAnon函数实现。

内核如何判定non-lru page movable?

上面绕了一圈,总结起来就是driver需要通过page->mapping的低两位上设置PAGE_MAPPING_MOVABLE告诉kernel non-lru page是movable的,kernel同时增加了__PageMovable判定这种non-lru page是否可以movable:

 注意:

1. LRU pages never can have PAGE_MAPPING_MOVABLE in page->mapping。

2. __PageMovable函数不能确保返回值的准确性,要100%准确判定non-lru page是否movable需要使用PageMovable函数:

 但是由于__PageMovable更速度轻量,且LRU中的page不可能设置PAGE_MAPPING_MOVABLE ,所以内核往往这样使用这两个函数:

1. __PageMovable判定page是否在LRU当中:

2. 先调用轻量级的__PageMovable判定movable,再通过PageMovable进一步确认,因为__PageMovable返回false肯定是不movable的,如果返回true,那需要进异步PageMovable判定,由于大概率__PageMovable就判定准确了,少部分降低到PageMovable二次确认,所以性能还是有好处的:

migrate_pages设计逻辑

内核文档介绍该函数实现逻辑如下:

上面步骤还是比较繁琐的,在本小节中我们先抓住重点梳理逻辑,先不陷入源码细节。迁移核心要做几个事情:

  1. 解除page A的映射,并映射到新page B。由于共享内存等原因,一个page可能被映射给多个进程的VMA里面,所以迁移的时候page可能涉及多个映射的解除。
  2. address_space的radix tree 从指向A到指向B.
  3. 新page B对应的flags和内容要和老page A一样。

 迁移的过程中除了进程1-3依然可能会继续访问Page A,内核内存管理系统其他的部分也可能访问PageA,应该避免内核的内存管理的其他部分干扰迁移。比如正在迁移PageA,内存子系统还在LRU里面扫描A,试图将PageA从inactive Lru移动到active LRU中,那么这就属于骚操作了,所以迁移过程会先通过isolate_lru_page将PageA从LRU中隔离出来,隔离出来之后就可以安心迁移PageA了,因为isolate会组织PageA被释放,也避免LRU的扫描动作,isolate_lru_page参考本文前面的分析。

PageA页面隔离之后,进程访问1-3访问PageA必须是无缝的,不能因为迁移页面就无法运行,当然迁移过程中进程被delay是可以接受的。迁移分3个阶段:

早期:进程的页表项依然指向PageA,此时进程可照常访问A。

中期:PageA已unmap,但是还没map到B,这个阶段属于空窗期,进程无法访问A,此时访问实际会触发缺页中断,然后缺页处理程序就是要等待map B,换个空窗期进程访问会延迟等到。

末期:pageB完成map,唤醒中期中被延迟等待的进程,并能访问到B。

上面中期等待是通过__migration_entry_wait完成:

中期阶段的时候,进程访问Page A会触发page fault,其此时会进程is_migration_entry逻辑(设置成migration entry是在unmap A的时候做的),然后migration_entry_wait等待迁移完成。 

 

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

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

相关文章

SpringBoot简单上手

spring boot 是spring快速开发脚手架,通过约定大于配置,优化了混乱的依赖管理,和复杂的配置,让我们用java-jar方式,运行启动java web项目 入门案例 创建工程 先创建一个空的工程 创建一个名为demo_project的项目,并且…

人员操作行为识别监测

人员操作行为识别监测实时监测人员的操作行为,人员操作行为识别监测通过yolov7深度学习算法网络模型,对前端采集人员操作行为的图像使用算法进行分析,识别出不符合规范的操作行为,并发出告警信号以提醒相关人员。在训练之前&#…

C++笔记之rolling counter(滚动计数器)

C笔记之rolling counter(滚动计数器) 一个 rolling counter(滚动计数器)是一个计数器,可以在给定的范围内不断增加,当达到最大值时会从最小值重新开始。 code review! 文章目录 C笔记之rolling counter&…

【Git】测试持续集成——Git+Gitee+PyCharm

文章目录 概述一、使用Gitee1. 注册账号2. 绑定邮箱3. 新建仓库4. 查看项目地址 二、安装配置Git1. 下载安装包2. 校验是否安装成功。3. 配置Git4. Git命令5. Git实操 三、PyCharmGit1. 配置Git2. Clone项目3. 提交文件到服务器4. 从服务器拉取文件 概述 持续集成(…

【Mac】编译Spring 源码和Idea导入

今天我们开始Spring源码的阅读之旅。阅读Spring的源码的第一步当然是编译Spring源码。首先我们要去GitHub上将spring源码给clone下来。 笔者编译环境如下: Spring版本:5.28 https://github.com/spring-projects/spring-framework/tree/v5.2.8.RELEASE …

Linux(基础篇二)

Linux基础篇 Linux基础篇二5. 系统管理5.1 Linux中的进程和服务5.3 systemctl5.4 运行级别CentOS 6CentOS 7 5.5 关机重启命令 Linux基础篇二 5. 系统管理 5.1 Linux中的进程和服务 计算机中,一个正在执行的程序或命令,被叫做“进程”(process) 启动之…

软件测试知识点总结(一)

文章目录 前言一. 什么是软件测试二. 软件测试和软件调试的区别三. 软件测试和研发的区别四. 优秀的测试人员所应该具备的素质总结 前言 在现实生活中的很多场景下,我们都会进行测试。 比如买件衣服,我们需要看衣服是不是穿着好看,衣服材质如…

Django学习笔记-AcApp端授权AcWing一键登录

笔记内容转载自 AcWing 的 Django 框架课讲义,课程链接:AcWing Django 框架课。 AcApp 端使用 AcWing 一键授权登录的流程与之前网页端的流程一样,只有申请授权码这一步有一点细微的差别: 我们在打开 AcApp 应用之后会自动向 AcW…

Servlet的使用(JavaEE初阶系列17)

目录 前言: 1.Servlet API的使用 1.1HttpServlet 1.2HttpServletRequest 1.3HttpServletResponse 2.表白墙的更新 2.1表白墙存在的问题 2.2前后端交互接口 2.3环境准备 2.4代码的编写 2.5数据的持久化 2.5.1引入JDBC依赖 2.5.2创建数据库 2.5.3编写数…

云原生之使用Docker部署SSCMS内容管理系统

云原生之使用Docker部署SSCMS内容管理系统 一、SSCMS介绍二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载SSCMS镜像五、部署SSCMS内容管理系统5.1 创建SSCMS容器5.2 检查SSC…

LabVIEW开发检测肌肉疾病的新技术

LabVIEW开发检测肌肉疾病的新技术 肌电图(EMG)是一种生物信号,可检测骨骼肌在收缩过程中产生的电流,以量化神经肌肉活动。了解肌电图信号需要了解骨骼肌以及允许它们产生生物电信号的机制。它还考虑了影响信号的众多系统和事件。…

Django基础5——ORM中间程序

文章目录 一、基本了解二、ORM基本操作2.1 连接数据库2.1.1 使用sqlite数据库2.1.2 使用MySQL数据库 2.2 对数据库操作2.2.1 增(前端数据——>数据库)2.2.2 查(数据库——>前端展示)2.2.3 改(修改数据&#xff0…

【人脸考勤项目】

本项目主要是基于Opencv完成的人脸识别的考勤系统 人脸检测器的5种实现方法 方法一:haar方法进行实现(以下是基于notebook进行编码) # 步骤 # 1、读取包含人脸的图片 # 2.使用haar模型识别人脸 # 3.将识别结果用矩形框画出来# 导入相关包 …

自动驾驶感知传感器标定安装说明

1. 概述 本标定程序为整合现开发的高速车所有标定模块,可实现相机内参标定和激光、相机、前向毫米波 至车辆后轴中心标定,标定参数串联传递并提供可视化工具验证各个模块标定精度。整体标定流程如下,标定顺序为下图前标0-->1-->2-->3,相同编号标定顺序没有强制要求…

疲劳检测-闭眼检测(详细代码教程)

简介 瞌睡经常发生在汽车行驶的过程中,该行为害人害己,如果有一套能识别瞌睡的系统,那么无疑该系统意义重大! 实现步骤 思路:疲劳驾驶的司机大部分都有打瞌睡的情形,所以我们根据驾驶员眼睛闭合的频率和…

微服务鉴权中心之网关配置SpringSecurity+oauth2

微服务鉴权中心流程如下: 1. 网关配置oauth2之TokenStore存储方式,此处用RedisTokenStore Configurationpublic class TokenConfig {Autowiredprivate RedisConnectionFactory redisConnectionFactory;Beanpublic TokenStore tokenStore() {return new …

生信分析Python实战练习 2 | 视频20

开源生信 Python教程 生信专用简明 Python 文字和视频教程 源码在:https://github.com/Tong-Chen/Bioinfo_course_python 目录 背景介绍 编程开篇为什么学习Python如何安装Python如何运行Python命令和脚本使用什么编辑器写Python脚本Python程序事例Python基本语法 数…

如何做好微信号标签管理?

微信除了生活外,也越来越多企业用微信来联系维护客户和发展自己的私域流量池,微信好友越加越多。 为了提高微信的管理效率,针对不同的微信好友群体进行群发,但每次都要手动打标签很费时间,那么有没有什么工具可以批量打…

Java项目01——项目配置

1. 前置知识: 1.把项目提交到本地仓库 2. gitee新建仓库,idea推送 3. 新建数据库,直接用navicate导入sql语句即可 4. 前后端联调,先编译,然后运行 5. 前端发送的请求,是如何请求到后端服务的&#xff1f…

【提升接口响应能力的最佳实践】常规操作篇

文章目录 1. 并行处理简要说明CompletableFuture是银弹吗?测试案例测试结论半异步,半同步总结 2. 最小化事务范围简要说明编程式事务模板 3. 缓存简要说明 4. 合理使用线程池简要说明使用场景线程池的创建参数的配置建议 线程池的监控线程池的资源隔离 5…