c++ mmap写入速度_内存管理(24)mmap和缺页中断

相关文件:

mm/mlock.c

mm/util.c

mm/mmap.c

include/linux/slab.h

mmap系统调用陷入内核中会调用vm_mmap_pgoff=>do_mmap_pgoff函数来真正完成mmap操作

1.1.do_mmap_pgoff函数(关键部分代码)

2be17b95c2f7c02f9e018a99d2ab9086.png

do_mmap_pgoff

  • 16行:对需要映射的内存长度页对齐
  • 20行:get_unmapped_area返回需要映射的地址空间
  • 25行:建立映射关系,如果定义了VM_LOCKED还要立即申请物理内存,该函数的实现细节请看1.2小节

1.2.mmap_region函数(关键部分代码)

a16b02f9c00cec4bfeec0e44af449378.png

mmap_region

  • 40行:查找符合条件的vma
  • 46行:合并相邻的vma
  • 49行:如果没找到合适的vma则调用kmem_cache_zalloc申请一个vma结构,这个函数前面也说过
  • 51行:把初始化好的vma插入mm下的内存管理树结构
  • 55行:配置vma的访问权限

2.缺页中断(armv7架构)

相关文件:

mm/memory.c

arch/arm/mm/fault.c

缺页中断与具体的处理器架构密切相关。以ARM为例,页面转换失效和页面访问权限失效对应的核心处理函数为do_page_fault。

83f930021cdb9e307c68899cb3871148.png

缺页中断基本流程

2.1.do_page_fault函数(关键部分)

e7b3ad19714a34fdda6941f79e11f5ff.png

do_page_fault函数-1

  • 69行:处于中断上下文或者禁止抢占时跳转到no_context标签
  • 71行:用户空间添加FAULT_FLAG_USER标志
  • 73行:具备FSR_WRITE权限则添加FAULT_FLAG_WRITE标志
  • 76行:真正处理缺页中断的函数,详情看小节2.2
70356a80dde6095a34749a8b65a0cd8d.png

do_page_fault函数-2

  • 85行:不属于以上异常就说明缺页中断正常处理完成
  • 88行:缺页中断处理有异常发生,如果是内核空间跳转到no_context标签执行__do_kernel_fault函数
  • 90行:VM_FAULT_OOM则调用pagefault_out_of_memory发送OOM信号
  • 95行:用户空间则向进程发送SIGSEGV信号,进程中断
  • 99行:__do_kernel_fault函数发送Oops错误

2.2.__do_page_fault函数(关键部分)

f6353a730080c66102f5b9b2ce91c999.png

__do_page_fault函数

  • 112行:查找vma
  • 115行:vma访问权限
  • 120行:缺页中断处理,详见2.3

2.3.__handle_mm_fault函数(关键部分)

2bfeb2a71b80043d6b95b97f9344d70f.png

__handle_mm_fault函数

  • 141~148行:获取到addr所对应的PGD、PUD、PMD、PTE
  • 150行:handle_pte_fault处理缺页中断,详见2.4

2.4.handle_pte_fault函数(关键部分)

78ab248d531e4976e9b86448f591fc30.png

handle_pte_fault函数-1

176行:如果页面不在内存中(还未映射真正的页),调用pte_none177行:页面为空。对于文件映射通常会调用do_fault(详见2.6);否则表示匿名映射则会调用do_anonymous_page(详见2.5)186行:页面不为空,表示正处于交换内存中,调用do_swap_page函数,详见2.7189行:写异常190行:如果pte为只读权限,调用do_swap_page函数193行:如果具备写属性,L_PTE_DIRTY置位
c5c9f37f5138821a0020c6b2eab712c4.png

handle_pte_fault函数-2

  • 189行:设置L_PTE_YONG位
  • 190行:如果pte页面项有变化就要写入物理页面项,并更新TLB cache

2.5.do_anonymous_page函数

4af21e8acdb0a8085e92f2fc49d65067.png

do_anonymous_page函数-1

  • 225行:判断当前VMA是否需要增加一个guard page作为安全垫
  • 229~236行:对于只读的VMA,系统使用0号页面生成新的PTE entry,0号页面是在paging_init中初始化的,前面提过。使用pte_offset_map_lock能得到页表项。如果表项不为空则跳转到setpte处更新到硬件表中。
3110c89781f359fa5764b4c3b1a5fa2d.png

do_anonymous_page函数-2

241行:分配一个可写的匿名页面,最终调用伙伴系统的alloc_pages,优先选择高端内存254~256行:通过mk_xxx生成一个新的pte entry262行:inc_mm_counter_fast增加系统中匿名页面的引用计数263行增加到RMAP反向映射系统中265行:把匿名页添加到LRU链表中,kswap中会用到267行:设置pte entry到硬件页表中
7a9feb51585149ffb6d44ad2ba83bcb6.png

do_anonymous_page函数-3

  • 270行:刷新TLB和cache

2.6.do_fault函数

767397bd4d47786d3c46530f5fbcf387.png

do_fault函数

  • 300行:只读缺页异常,详见2.8小节
  • 303行:私有映射且发生写时拷贝缺页异常,详见2.9小节
  • 305行:公有映射写缺页异常,详见2.10小节

2.7.do_swap_page函数

与2.8和2.9类似

2.8.do_read_fault函数

static int do_read_fault(struct mm_struct *mm, struct vm_area_struct *vma,unsigned long address, pmd_t *pmd,pgoff_t pgoff, unsigned int flags, pte_t orig_pte){struct page *fault_page;if (vma->vm_ops->map_pages && fault_around_bytes >> PAGE_SHIFT > 1) {//拿到缺页异常地址addr所对应的ptepte = pte_offset_map_lock(mm, pmd, address, &ptl);/*以缺页异常地址为中心,从start_addr开始检查相应的pte是否为空,若为*空则从这个pte开始到max_pgoff为止使用map_pages()来映射PTE。这么做为*了提前建立缺页地址(进程地址空间)与(现存)page cache的映射关系,*减少缺页中断的次数从而提高效率。*/do_fault_around(vma, address, pte, pgoff, flags);//页面内容在刚刚被系统修改了,跳转到unlock_out标签if (!pte_same(*pte, orig_pte))goto unlock_out;pte_unmap_unlock(pte, ptl);}//为缺页异常地址分配page cache ret = __do_fault(vma, address, pgoff, flags, NULL, &fault_page);if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))return ret;//拿到映射好的缺页地址的PTEpte = pte_offset_map_lock(mm, pmd, address, &ptl);if (unlikely(!pte_same(*pte, orig_pte))) {pte_unmap_unlock(pte, ptl);unlock_page(fault_page);page_cache_release(fault_page);return ret;}//为PTE创建条目,并加入反向映射机制do_set_pte(vma, address, fault_page, pte, false, false);unlock_page(fault_page);unlock_out://放弃映射pte_unmap_unlock(pte, ptl);return ret;}

2.9.do_cow_fault函数

//省略部分错误判断static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma,unsigned long address, pmd_t *pmd,pgoff_t pgoff, unsigned int flags, pte_t orig_pte){pte_t *pte;int ret;if (unlikely(anon_vma_prepare(vma)))return VM_FAULT_OOM;//以GFP_HIGHUSER_MOVABLE分配掩码分配一个物理页面new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address);if (mem_cgroup_try_charge(new_page, mm, GFP_KERNEL, &memcg)) {page_cache_release(new_page);return VM_FAULT_OOM;}//读取文件内容到fault_pageret = __do_fault(vma, address, pgoff, flags, new_page, &fault_page);if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))goto uncharge_out;if (fault_page)//拷贝内容到物理页面copy_user_highpage(new_page, fault_page, address, vma);__SetPageUptodate(new_page);//取得对应的PTEpte = pte_offset_map_lock(mm, pmd, address, &ptl);//为对应PTE创建条目再添加到反向映射机制do_set_pte(vma, address, new_page, pte, true, true);mem_cgroup_commit_charge(new_page, memcg, false);//物理页面加入LRU队列进行管理,内存回收会用到lru_cache_add_active_or_unevictable(new_page, vma);pte_unmap_unlock(pte, ptl);if (fault_page) {unlock_page(fault_page);page_cache_release(fault_page);} else {i_mmap_unlock_read(vma->vm_file->f_mapping);}return ret;uncharge_out:mem_cgroup_cancel_charge(new_page, memcg);page_cache_release(new_page);return ret;}

2.10.do_shared_fault函数

与2.8和2.9类似

2.11.do_fault_around函数

static void do_fault_around(struct vm_area_struct *vma, unsigned long address,pte_t *pte, pgoff_t pgoff, unsigned int flags){unsigned long start_addr, nr_pages, mask;pgoff_t max_pgoff;struct vm_fault vmf;int off;/*fault_around_bytes是一个全局变量,等于16个page的大小,所以此处nr_pages=16*/nr_pages = ACCESS_ONCE(fault_around_bytes) >> PAGE_SHIFT;//以16页对齐为步长计算掩码mask = ~(nr_pages * PAGE_SIZE - 1) & PAGE_MASK;//以16页对齐,取缺页地址和vm_start较大的那个为扫描PTE的起始地址start_addr = max(address & mask, vma->vm_start);/*PTRS_PER_PTE 表示每个PTE项所对应的条目数,此处为512也就是1个PTE对应512页*这一步相当于取缺页地址和start_addr的偏离(页数单位)的绝对值*/off = ((address - start_addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);//查找PTE的起始位置pte -= off;pgoff -= off;/* *  max_pgoff is either end of page table or end of vma *  or fault_around_pages() from pgoff, depending what is nearest. */max_pgoff = pgoff - ((start_addr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +PTRS_PER_PTE - 1;max_pgoff = min3(max_pgoff, vma_pages(vma) + vma->vm_pgoff - 1,pgoff + nr_pages - 1);/* Check if it makes any sense to call ->map_pages */while (!pte_none(*pte)) {if (++pgoff > max_pgoff)return;start_addr += PAGE_SIZE;if (start_addr >= vma->vm_end)return;pte++;}//找到为空的PTE,则从此处开始到max_pgoff映射PTEvmf.virtual_address = (void __user *) start_addr;vmf.pte = pte;vmf.pgoff = pgoff;vmf.max_pgoff = max_pgoff;vmf.flags = flags;vma->vm_ops->map_pages(vma, &vmf);}

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

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

相关文章

邬贺铨院士:边缘计算“新十问”

来源:C114通信网作者:水易两年前的边缘计算技术峰会上,中国工程院院士邬贺铨就边缘计算提出十问,直戳技术演进与产业发展的核心问题,引起业内巨大反响。在过去两年中,边缘计算产业得到了长足发展&#xff0…

java 字符串第一个字符_深入Java源码剖析之字符串常量

字符串在Java生产开发中的使用频率是非常高的,可见,字符串对于我们而言非常关键。那么从C语言过来的同学会发现,在C中是没有String类型的,那么C语言要想实现字符串就必须使用char数组,通过一个个的字符来组拼成字符串。…

耗时11年,120页论文,中科大数学家成功证明微分几何核心猜想

大数据文摘出品近日,中国科技大学几何与物理研究中心创始主任陈秀雄教授与王兵教授团队发布论文“Space of Ricci flows (II)—Part B: Weak compactness of the flows”,在全球范围内率先证明了“哈密尔顿-田”和“偏零阶估计”这两个困扰数学界20多年的…

java 写入txt_Java线程转储的8个选项

线程转储是诊断CPU尖峰,死锁,内存问题,无响应的应用程序,较差的响应时间以及其他系统问题的重要工件。有很多很棒的在线线程转储分析工具,可以分析和发现问题。但是对于那些工具,您需要提供适当的线程转储作…

重磅!2020年度人类社会发展十大科学问题发布

来源:科技导报 在11月9日下午的第二届世界科技与发展论坛的闭幕式上,中国工程院院士、清华大学教授、《Research》编委周济和《柳叶刀》主编,爱思唯尔柳叶刀系列期刊总编辑、理查德霍顿共同发布了“2020年度人类社会发展十大科学问题”。本次…

前端导出excel文件带样式_vue前端使用xlsx导出数据到excel中--最简单的方式

最新项目中需要将页面数据导出到excel中,首先想到的就是度娘,得到的结果都是千篇一律,答案都是你复制我我复制你的,虽然能解决问题,但是这个过程也太复杂。既然无法改变,那就只好插手你的生活了。废话少说&…

7种情绪,人类心智的通用模块

来源:混沌巡洋舰1859年,达尔文以一个挑衅性的断言结束了他的《物种起源》,那就是‘人类的起源和他的历史将会被(进化)点亮’。在他的后期著作《人类的由来》(1和《人类与动物的情感表达》中,达尔文阐明了人…

gitbook mysql_使用Gitbook做笔记

一、安装# 通过npm全局安装npm install gitbook-cli -g# 查看版本gitbook --version二、创建一本书2.1 本地创建# 创建一个文件夹mkdir mysql-note# 初始化cd mysql-notegitbook init# 会创建两个文件# README.md 书皮# SUMMARY.md 目录# 从本地打开这本书gitbook serve# 将md文…

03、数据类型(02)

字典(dict) 字典是一种映射型的数据类型,每个元素成对出现,即key- value,每对元素key 和 value“:”冒号分开,元素之间用逗号隔开,整个字典包括子在{}中。 字典中的“key”必须是不可变类型&am…

器官复刻、脑机接口、电子皮肤…这些前沿科学或改写人类未来

来源:MEMS“2020年,新冠疫情爆发,面对困境,我们采取的行动将很可能改写这个时代。” 11月7日,2020腾讯科学WE大会线上举行。腾讯首席探索官网大为在开场演讲中表示,前沿科学突破能帮助我们做好准备拥抱未来…

GPT-3:人工智能的新突破

来源:王宏琳科学网博客在过去几个月里,占据海外科技新闻头条主导地位的、人工智能领域最令人兴奋的新事物之一是GPT-3——OpenAI的新的文本生成程序,一种由神经网络驱动的语言模型,一个根据人类用户的提示自动生成文本的人工智能引…

把 mysql 整个加载进内存磁盘中_MySQL 缓冲池 是什么?

Mysql 中数据是要落盘的,这点大家都知道。读写磁盘速度是很慢的,尤其和内存比起来更是没的说。但是,我们平时在执行 SQL 时,无论写操作还是读操作都能很快得到结果,并没有预想中的那么慢。可能你会说我有索引啊&#x…

Cell重磅:记忆研究的突破进展!在诺奖成果基础上,用“全光学”组合来“操纵记忆”...

来源:brainnews这项发表在《细胞》杂志上的研究,解释了研究人员如何利用双光子钙成像和双光子光遗传学的“全光学”组合,同时读写小鼠“位置细胞”(神经元的一种)中的活动,而这种细胞可以在虚拟现实环境中进…

mysql like 多个条件_千万级MySQL数据库这样建索引可以让你的数据库飞起来.........

创建索引常用规则1、表的主键、外键必须有索引;2、数据量超过300的表应该有索引;3、经常与其他表进行连接的表,在连接字段上应该建立索引;4、经常出现在Where子句中的字段,特别是大表的字段,应该建立索引&a…

mysql主从配置访问_Mysql主从配置,实现读写分离

大型网站为了软解大量的并发访问,除了在网站实现分布式负载均衡,远远不够。到了数据业务层、数据访问层,如果还是传统的数据结构,或者只是单单靠一台服务器扛,如此多的数据库连接操作,数据库必然会崩溃&…

靠脑机接口“隔空探物”,大脑植入芯片可实现“心灵感应”

来源:脑极体1979年,在四川大足县的12岁农村少年唐雨突然具有了“耳朵识字”的神通。原本是当地的一件稀罕的谈资,结果后来引起了当地媒体的报道,后来又居然经过中国的权威科技期刊《自然杂志》的“确证”和香港《明报》&#xff0…

android app 适应不同大小屏幕_移动APP测试:Android屏幕适配问题二

设计选择性的布局和图片,替代资源的类型,取决于应用程序的需求。通常,应该使用尺寸和方向限定符提供选择性的布局资源,使用密度限定符提供选择性的图片资源。以下部分分别概括了该如何使用尺寸和密度限定符提供选择性的布局和图片…

使用node中的express解决vue-cli加载不到dev-server.js的问题

在使用vue开发过程中,难免需要去本地数据地址进行请求,而原版配置在dev-server.js中,新版vue-webpack-template已经删除dev-server.js,改用webpack.dev.conf.js代替,所以 配置本地访问在webpack.dev.conf.js里配置即可…

脑机接口:从基础科学到神经康复

本文转自公众号:脑机接口社区大家好 ,我是米格尔尼科莱利斯,美国杜克大学神经生物学、神经学和生物医学工程教授。今天我将为大家介绍脑机接口和这一技术从基础科学到应用于神经康复的研究历程。首先,我要感谢2020腾讯科学WE大会的…

从Airbnb的发展历程和网易云的大起大落看IT行业创新(第5周课后作业)

我想先根据个人看法回答“创新是什么?”这个空泛的问题。创新是面对当下的资源条件限制创造出能够满足动态需求或解决动态发展中的问题的新策略。这种实用化定义在大部分邻域都勉强能让定义者自圆其说,对于IT行业算是比较贴切,但是当我们把创…