- 博客(197)
- 资源 (7)
- 收藏
- 关注
转载 自旋锁 spin_lock、 spin_lock_irq 以及 spin_lock_irqsave 的区别
能够停留下来认真读这篇文章的人大部分都已经了解了什么是自旋锁,至少知道自旋锁就是不停的询问资源有没有准备好的一把锁,这个从概念上很容易理解,当然他的内在也是很容易实现。
2023-08-23 11:10:53
1569
原创 Linux源码剖析struct page结构体flags成员
/跟page reclaim的二次机会法有关//page缓存内存和磁盘数据一致//代表是脏页PG_dirty,//page在lru链表中PG_lru,//page在active lru链表中PG_active,//IO错误PG_error,//page是对应的是slab内存PG_slab,PG_arch_1,//不能换出//正在回写//马上开始回收,回收前设置//匿名页和shmem page设置该条件//被mlock了#endifPG_young,PG_idle,
2023-08-13 23:26:21
754
原创 Linux源码剖析匿名共享内存shmem原理
进程间共享匿名内存有两种重要的方式,其一是mmap设置MAP_SHARED | PRIVATE创建的虚拟地址区域,这片区域fork执行之后,由父子进程共享。其二是主动调用shmget/shmat相关接口。此外android操作系统的ashmem匿名共享内存也是基于linux内核的shmem实现。本文我们将从源码角度剖析内核shmem的设计和实现原理。
2023-08-13 17:18:43
2836
1
原创 Linux mmap系统调用视角看缺页中断
实际开发过程中经常使用或者看到mmap函数,具体细节可以man mmap查看相关细节。这个系统调用是个多面手,应用空间申请内存(比如glibc库申请大内存使用的是mmap),还是读写大文件,链接动态库,多进程间共享内存都可以看到mmap的身影,要想真正的理解这个系统一方面是从这几种使用场景的需求上理解mmap,更重要的必须基于内核源码,深入剖析其每个参数具体对应的内核实现。内存拷贝次数以mmap映射文件场景来讲,mmap读写文件与read/write的相比少一次内存拷贝。
2023-08-07 22:16:35
1008
原创 linux页框回收之shrink_node函数源码剖析
Linux内存回收入口_nginux的博客-CSDN博客》前文我们概略的描述了几种内存回收入口,我们知道几种回收入口最终都会调用进入shrink_node函数,本文将以Linux 5.9源码来描述shrink_node函数的源码实现。
2023-07-30 11:31:37
919
原创 Linux内存回收入口
内存回收主要是有kswapd异步回收和direct reclaim同步回收两种入口,其中逻辑非常复杂,本文主要只概要描述不同回收场景下内核设计的主要思想,源码细节不同版本有不少区别,具体的分析后续会有专门的文章分析。
2023-07-29 14:27:00
688
原创 搞懂sparsemem稀疏内存模型
随着大内存和内存热插拔技术发展,内核物理内存越来越不连续,内核管理这种非连续物理内存的元数据metadata也需要随之发展,避免内存浪费,内核的sparse mem稀疏内存模型就是解决该问题。数据结构mmzone.h//根据sec number计算属于哪个root,即mem_section二位数组第一维的index//2048//相当于是[2048][256]的二维数组,每个数组元素是struct mem_section//为了节省空间,这个字段包含很多信息,具体见下面源码的解释/*
2023-07-28 23:00:00
1230
原创 page _refcount和_mapcount字段
linux page有两个非常重要的引用计数字段_refcount和_mapcount,都是atomic_t类型,其中,_refcount表示内核中应用该page的次数。当_refcount = 0时,表示该page为空闲或者将要被释放。当_refcount > 0,表示该page页面已经被分配且内核正在使用,暂时不会被释放。
2023-07-24 22:59:08
1656
原创 ext4 mballoc之buddy算法
ext4_mb_init_cache,而是ext4_mb_load_buddy就会调用ext4_mb_init_cache,这里init cache就是指保存磁盘data block bitmap的pagecache和buddy bitmap。ext4_mb_init_group和ext4_mb_load_buddy都会调用ext4_mb_init_cache,我们就以ext4_mb_init_group调用为启动分析。
2023-07-23 15:55:53
1212
原创 ext4 delay allocation之ext4_writepages页回写源码剖析
ext4 write写入pagecache之后,再合适的时机会回写到磁盘,ext4文件系统中是通过ext4_writepages写入磁盘,本来将在源码角度分析该过程。建议先参照ext4 - delay allocation数据结构_nginux的博客-CSDN博客看下涉及的重要数据结构。
2023-07-23 01:03:21
1077
原创 ext4 - delay allocation数据结构
延迟分配delay allocation是ext4非常重要的特性,启用该特性write系统将用户空间buffer写入内存page cache中即返回,此时也不会真正进行磁盘block分配,而是延迟到磁盘回写时(比如dirty ratio达到一定值,定时刷新,主动sync等) 才开始映射磁盘block(map block)进行块分配,好处就是可以将连续的块进行合并merge,结合ext4的mballoc多块分配机制,可以一次性分配多个物理block,降低cpu使用率和碎片化问题。
2023-07-22 15:22:12
1334
原创 Linux pagecache writeback的一个性能优化patch分析
用来主要降低设备IO拥塞时,由于jdb transaction commit引起的性能问题,如果page cache不需要执行block allocation和extent conversion逻辑,就先将这部分dirty page submit交给块设备层,然后复用一个transcation即可。buffer_unwritten(bh)逻辑,命中map->m_len = 0逻辑返回true。mpage_add_bh_to_extent会返回true,会进入的mpage_submit_page逻辑。
2023-07-17 16:10:59
418
原创 Ext4文件系统介绍 - 实战篇
红框的f30a对应上图的extent_header,根据ext4理论篇中的定义我们知道extent_header数据结构如下:正好f30A对应extent_header的magic number。我们知道inode是存储在inode table中,每个inode size 是256B,所以我们怎么找到inode table的block号?dumpe2fs命令!本文主要通过dd,hexdump和dumpe2fs工具分析ext4的磁盘二进制数据,加深对ext4文件系统的印象,要想理解本建议先阅读下。
2023-07-14 21:34:31
1022
原创 Android代码解读之渲染机制揭秘
本文从代码层面,把应用进程启动和渲染的流程走读了一遍,理解了Android的渲染原理对于理解其他UI框架或者引擎有比较好的借鉴意义,比如研究google的flutter框架时会更轻松:flutter的渲染流程(图来自网络上图从网络上搜到的flutter 框架的流程图,这个流程是不是有点像套娃战术,同样是vsync信号、UI线程,GPU线程(也就是android的renderthread)两线程加速性能。
2023-07-11 20:53:20
780
原创 Ext4文件系统介绍 - 理论篇
但是,ext4_inode_info没有定义指向ext4_inode的字段,只是拷贝了ext4_inode的i_block,i_flags等字段;ext4_sb_info和ext4_super_block中的很多字段相似,但也有区别,ext4_sb_info中的很多字段是根据ext4_super_block的字段计算而得,虽然可以通过 ext4_super_block计算而得到,但是定义在ext4_sb_info定义可以省去重复计算的时间。磁盘数据的每个inode通过ext4_inode数据结构表示。
2023-07-09 21:46:39
3849
转载 Linux iowait到底是什么含义
IOwait 一个迷之参数,top/iostat/mpstat/sar 都会统计的关键数据,字面理解是系统等待IO的时间,经常用于反映系统IO压力。IOwait时候CPU在干什么?什么时间才算IOwait,到底在wait什么?
2023-07-08 07:56:50
1089
原创 Linux bio数据结构
代码中newblock=map->m_lblk - ee_block + ee_start即是起始逻辑地址映射的磁盘块地址,allocated = ee_len - (map->m_lblk - ee_block)是成功映射的block数,注意未必等于map.m_len,有可能小于map.m_len,因为磁盘block未必有map.m_len个连续的块。ext4_mpage_readpages函数就会读取磁盘数据就会构建一个个的bio,如上面描述我们知道bio指向的是一块连续的磁盘数据,
2023-07-08 01:43:15
1142
原创 Linux 读文件 - readahead预读算法
根据ondemand_readahead中initial_readahead label处逻辑看,ra->size是由get_init_ra_size函数计算,该函数第一个参数是应用read的数据页(每个数据页4K)的数量,该场景每次读取4K bytes,相当于调用get_init_ra_size(1,32)返回4。这里async readahead就是指generic_file_buffered_read函数中的:page_cache_async_readahead函数调用。: 开始预读的数据页索引,
2023-07-02 22:46:16
1475
原创 Linux read的核心函数generic_file_buffered_read
【代码】Linux read的核心函数generic_file_buffered_read。
2023-07-02 16:19:27
1096
1
原创 buffer_head数据结构
buffer_head用来将一个单独的block映射到一个page,一般80x86体系结构上,根据block size大小,一个page可以包含1-8个block,比如如果block size = 1K,那么一个缓存page缓存4个block,且buffer_head是文件系统和block layer的io基本单位。假设page size = 4K, block size = 1K。bio取代了buffer_head作为io基本单位。
2023-07-01 16:55:28
1515
原创 Linux源码编译开启cgroup blk限制io性能
经过上面的mout之后就可以看到/sys/fs/cgroup/blkio中出现了各种控制节点。
2023-07-01 13:47:14
866
原创 Linux vfs各种operation操作介绍
由于目录也是一种文件,而目录操作和普通文件操作不同,所以文件系统需要定义两种file_operations,创建普通文件和目录文件时候都要创建inode对象,inode对象中包含两个重要的成员:i_op和i_fop,分别代表inode_operations和file_operations,要根据不同文件类型,给其inode赋予不同的结构体: 通过strace观察ls命令分两步:1)打开目录 2)读取遍历目录2.1.1 打开目录:openat对应的操作调用栈可以看到调用路径:vsys_openat ->
2023-06-26 21:50:19
706
原创 从源码视角彻底搞懂Linux线程实现原理
上面代码看完是否产生一个疑问,man手册中说pthread_detach的线程要自己释放资源,而上面源码中并未看到释放资源的代码,线程执行完比之后是怎么实现自己释放资源的?内核执行完clone系统调用,创建完线程之后会跳转到__start_thread执行,最终会调用到用户pthread_create传入的线程执行函数体中。与pthread_join使用的场景相反,如果线程A请线程B帮忙做事,线程A和线程B可以并行执行,不需要等待线程B的结果反馈,此时由于可能B线程完毕了,
2022-09-18 22:32:45
3090
2
原创 基于bionic c分析线程的一生
1.概述和问题进程和线程操作系统基础和重要的机制,从源码角度理解进程和线程的区别对于理解操作系统的基本原理非常有帮助,同时进程和线程的创建又是通过系统调用实现,两者结合起来理解可以融会贯通。
2022-09-18 21:00:22
1696
原创 Linux进程内核栈
进程创建的时候Linux内核会创建内核栈(arm手册也要求内核态有单独的栈),如应用进程在用户态通过系统调用陷入内核态的时候,上下文信息(如cpu寄存器)需要有个地方保存,如此,从内核态切换回用户态时候,能继续从系统调用之后的代码开始执行,这个保存的地方就是进程的内核栈,本文主要描述arm32下内核栈的生成过程和结构。
2022-09-18 10:08:57
1709
原创 彻底搞懂内存屏障(下)
线程cosume中使用 memory_order_acquire内存屏障,保证了consumer线程后面的所有读写(包括非原子)操作不能重排序到acquire之前,并且consumer的load操作一旦完成,线程producer release之前的读写操作对producer线程可见。我们知道,acquire/release只保证load完成之后,release之前的内存操作在load之后是可见,但是并不保证一个线程中的store(release)操作,立马对其他线程的load(acquire)可见。
2022-09-04 18:10:40
4741
原创 彻底搞懂内存屏障(上)
由于store buffer的大小是有限,上面例子中如果cpu1无法快速处理read invalidate消息,那么cpu0中的store buffer马上就会满了,所以arm增加了invalidate queue存放收到invalidate消息,收到invalidate消息放入invalidate queue中,然后给对方(cpu0)发送一个respone响应,但是此时并不真正处理invalidate消息,正因如此,invalidate queue又引入新的复杂性。.........
2022-08-28 22:24:24
3346
2
原创 cache line提升程序性能
数据结构中频繁访问的成员可以单独占用一个cache line或者相关的成员在不同的cache line中错开,以提高访问效率。比如linux内核struct zone数据结构中zone->lock和zone->lru_lock两个频繁访问的锁,可以让他们在不同的cache line中,以提高获取锁的效率。如果Data结构体不对齐到cache line,那么dArray[0]和dArray[1]会在同一个cacheline上面,两个线程同时修改结构体成员变量,由于缓存一致性机制,会导致缓存失效。......
2022-08-27 21:49:58
1837
原创 编程中likely和计算机基本原理关系
(x),1)!(x),0)_builtin_expect 这个指令是 gcc 引入的。该函数作用是允许程序员将最有可能执行的分支告诉编译器,来辅助系统进行分支预测。当正确地使用了__builtin_expect后,编译器在编译过程中会根据程序员的指令,将可能性更大的代码紧跟着前面的代码,从而减少指令跳转带来的性能上的下降。2.示例!(x), 1)!n = n + 2;}return 0;}~...
2022-08-27 09:33:04
341
原创 arm/arm64函数栈帧(stackframe)结构和传参规则
本文汇编代码的平台及编译器:arm/gcc。分析函数调用栈的规则对于理解程序运行基本原理很有帮助,汇编代码分析crash问题也大有裨益。本文示例代码通过C语言函数调用一个汇编函数,再从汇编函数跳转回C函数,分析该示例的汇编代码就可以stack frame的创建和arm函数调用的传参规则。arm32使用哪些寄存器传参,如果参数超过4个怎么传参?arm32/gcc中函数调用stack frame的创建,以及函数返回stack frame的销毁过程是怎样的?
2022-08-20 22:12:03
5847
1
原创 ELF格式分析动态链接原理
objdump -r elf(readelf -r也可以)可以读取rel.dyn变量重定位段,获取需要重定位的变量的相关信息,其中offset字段就是该变量的重定位地址对应的.got(GOT)的表项,比如global_module的offset = 1fdc(正如上面汇编计算的结果),对应的是.got(GOT)表中global_module的表项地址。跳转到.plt section首地址处执行代码,该处代码会会跳转到GOT表项的第三项,存储的是链接器的符号解析函数(装载时才能确定该地址,初始化时为0)...
2022-08-07 23:59:34
1128
1
原创 汇编视角分析C++虚函数实现原理
虚函数是c++语言非常重要的机制,日常的c++编程工作中经常使用虚函数,通过汇编视角来探究虚函数的实现原理,有助于深刻理解虚函数的内部机制。c++语法规范并没有规定虚函数的具体实现方案,不同的编译器实现方式可以不同,本文基于arm32平台,g++编译器来分析虚函数表的实现机制,基本主流编译器的原理基本是相似的,所以理解g++实现方案再去分析其他编译器的实现也是类似的。......
2022-08-07 17:43:22
883
原创 arm push/pop/b/bl汇编指令
push支持同时将多个寄存器入栈,格式{xx,xx},如push{r0,r1,r2}BL函数条跳转前执行LR=PC-4;如同push一样,pop也支持同时pop出栈多个寄存器。
2022-07-31 15:48:04
11536
4
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅